четвртак, 25 априла, 2024
Како да...?

LibGDX „Java game development framework” (2. дио)

Аутор: Гаврило Продановић

У прошлом броју смо сазнали да је LibGDX Java cross-platform framework за развијање игара, који помаже да своју идеју лако преточимо у нешто „опипљиво”. Сазнали смо како апстрактује датотечни систем између различитих платформи и на који начин нам помаже да организујемо наш кôд. Сазнали смо за render() функцију која се позива у круг, па ћемо тако наставити излагање са графичким могућностима које LibGDX пружа.

Као камен темељац LibGDX користи OpenGL ES. У последњој стабилној верзији, подржани су OpenGL ES 2.0 и 3.0. У нешто старијој верзији овог framework-а постојала је и подршка за OpenGL ES 1.1. Да би све OpenGL ES функције ниског нивоа биле доступне у овом framework-у, постоје два wrapping интерфејса GL20 и GL30, а њихово позивање се врши преко статичких чланова класе Gdx који их имплементирају. Овде нећемо трошити времена говорећи како се користи OpenGL (за то треба читава једна књига, прим.аут.), али за оне који воле да заобиђу OpenGL у најширем кругу, споменућемо најчешћи блок кода који ће за основну боју позадине поставити црну.

Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
Gdx.gl.glClearColor(0f, 0f, 0f,1);

Од класа „вишег” нивоа, игра се врти око SpriteBatch-а, између чијих begin() и end() позива се врши потребно исцртавање графике. Често ћемо уз SpriteBatch поставити ивице пројекције уз помоћ OrthographicCamera објекта. Texture, као што и име каже, служи за чување текстуре. Помоћу различитих конструктора, текстуру можете учитати из фајла, или из претходног Pixmap објекта, такође можете креирати празну текстуру одређене ширине и висине. Pixmap је класа која представља слику у меморији и посједује неколико метода за манипулисање том сликом као што су цртање пиксела, линије, троугла, квадрата и круга. TextureRegion је класа која ће бити од помоћи ако је потребно са неке текстуре издвојити површину која треба бити исцртана. У њој је дефинисана статичка функција split која је од помоћи ако је одређену текстуру потребно подјелити на неколико једнаких региона. Класа /Sprite је тзв. хелпер класа (енг. helper – она која помаже) која у својим конструкторима узима Texture или TextureRegion и чува информације гдје текстура треба да буде исцртана. Посједује методе за манипулацију као што су rotate, scale, translate, setColor и још многе које могу бити од помоћи. Animation класа чува листу TextureRegion објеката којима манипулише тако да би се направила анимација. У конструктору се задаје дужина анимације, листа TextureRegion-а и константа из енумерације Animation.PlayMode-а која дефинише да ли анимација иде нормално, у петљу или обрнутим редосљедом. Послије иницијализације ове класе довољно је да у својој render() функцији позовемо getKeyFrame(float stateTime) да добијемо текстуру за тај циклус рендеровања. NinePatch ће бити користан онима који исцртавају текстуру у различитим димензијама, а да морају одредити дјелове који ће остати непромјењени и дјелове који ће се раширивати. У суштини, NinePatch подјели текстуру у 3×3 матрицу чијим се ћошковима не мјења геометрија. Примјер NinePatch-а је дугме контрола.

Прије него што се изврши неко цртање текстуре, потребно ју је учитати у меморију (енг. texture binding), када је потребно извршити цртање друге текстуре, онда се она исто мора учитати. Учитавање текстура је доста „скуп” процес и одузима много времена, зато се у пракси више мањих текстура спаја у једну велику и онда се дјелови те велике текстуре исцртавају и тако се добија на перформансама. LibGDX за овај проблем има алатку названу TexturePacker која ће претраживањем задате путање упаковати текстуре унутар атласа. За сваки директоријум се може написати фајл pack.json у којем се налази конфигурација о паковању фајлова унутар тог директоријума и његових поддиректоријума. Такође, креирање атласа, барем по нашем мишљењу, помаже да се фајлови боље организују јер се унапријед одреди чему је намјењена која текстура и зато што је сва графика упакована у један .atlas фајл. Да бисмо приближили како изгледа коришћење атласа, послужићемо се овим кодом:

TextureAtlas atlas;
atlas = new TextureAtlas(Gdx.files.internal("packedimages/pack.atlas"));
Sprite sprite = atlas.createSprite("otherimagename");
NinePatch patch = atlas.createPatch("patchimagename");

У игрицама се визуелни доживљај преноси графиком, али натписи и слова ипак су неизоставан дио игрице. LibGDX за ту намјену нуди класу BitmapFont. Класа је доста примитивна, она посједује листу TextureRegion-а који су повезани са одговарајућим словима. Унутар assets директоријума, фонт је представљен у облику два фајла – једног који је текстура и другог који описује карактере који се налазе унутар текстуре. Један од проблема у BitmapFont-у (из имена можемо наслутити тај проблем) јесте то што се не може мјењати величина без губитка квалитета, па због тога исти фонт мора имати више текстура за различите величине. LibGDX унутар свог кода и даље нема подршку за TrueType фонтове, али постоји gdx-freetype библиотека која нам омогућује да из FreeType фонтова креирамо BitmapFont-ове различитих величина у лету.

За крај, споменућемо још да овај framework има подршку за particle ефекте и да посједује свој едитор за креирање ових ефеката као и хелпер класе за учитавање и управљање ефектима. Поред 2D графике постоји подршка за 3D графику у коју нећемо залазити због нешто веће комплексности, али смо из других извора и туђих искустава утврдили да је 3D графика исто веома добро подржана од стране овог framework-а. У сљедећим бројевима нећемо улазити више у дубинско разматрање графичких могућности LibGDX-а.