Početak rada na HOPA igrama, za studio Mad Head Games, predstavlja veliki korak i polje koje smo doživeli pre svega kao izazov. Većina projekata sa kojima smo se do tog trenutka susreli, rađena je u specifičnoj tehnologiji, što nije ostavljalo mogućnost da se određena tehnologija bolje izuči, da se članovi tima sa njom dublje upoznaju i konkretna znanja primene na narednim projektima.

S druge strane, ovakav način rada je predstavljao veliko iskustvo, jer nas je doveo u kontakt sa velikim brojem različitih alata i softvera, ali i očvrsnuo samopouzdanje tima da nova i drugačija tehnologija ne predstavlja prepreku, već izazov.

Za kreiranje HOPA igara, odlučili smo se za razvoj sopstvene tehnologije koja će biti sačinjena iz nekoliko segmenata:

Rad na prethodnim projektima nam je ostavio veliki broj skripti i plugin-ova za alate koje smo koristili (Photoshop, 3ds Max, Total Commander), i njih smo uspešno iskoristili za početak rada na HOPA igrama.

Što se tiče C++ engine-a, za osnovu smo uzeli postojeći engine koji je podržavao PC, Mac i iOS, tako da nam je ostalo da izaberemo skriptni jezik i povežemo ga sa low-level engine-om. Ovaj deo je najviše zavisio od izbora konkretnog skriptnog jezika.

Izbor skriptnog jezika

Iako je u trenutku izbora skriptnog jezika koji ćemo koristiti, u Mad Head Games-u radio samo jedan programer, i ostali članovi tima su već uspešno koristili skriptne jezike u postojećim alatima (pre svega 3ds Max-u) da ih prilagode svojim potrebama.

Upravo je ovo bio razlog da skriptni jezik koji izaberemo bude što jednostavniji za korišćenje, kako bi na programiranju igre moglo da učestvuje što više članova tima.

Faktori koji su primarno uticali na izbor (a kasnije i dizajn) skriptnog jezika su bili:

Analizirali smo nekoliko postojećih skriptnih jezika: Lua, Squirrel, Python i JavaScript. Sa svim jezicima smo imali prethodnog iskustva, a jezike Lua i Squirrel smo uspešno i integrisali. Jezici Python i JavaScript su bili nešto kompleksniji za integrisanje, pa smo ih vrlo brzo eliminisali iz dalje analize. Jezici Lua i Squirrel su se primarno razlikovali u sintaksi.

Jezik Squirrel je imao implementirane neke od naprednijih koncepata (klase, generatori), dok je prednost jezika Lua bila u njegovoj jednostavnosti i aktivnoj zajednici.

Međutim, osnovna funkcionalnost koju smo želeli da pokrijemo implementacijom skripte je definisanje logike prolaza kroz HOPA igru, što bi bio poduhvat podjednake kompleksnosti u obe od ova dva skriptna jezika.

Tako smo došli na ideju da kreiramo specifičan skriptni jezik koji će sadžati minimalan skup operacija neophodnih da se kreira logika jedne HOPA igre. Ovo je ujedno i prva faza u razvoju specifičnog skriptnog jezika koji Mad Head Games do danas koristi za razvoj svojih igara.

Faza 1 – Definisanje akcija

Osnovna funkcionalnost koja je pokrivena u ovoj fazi razvoja skripte jeste definisanje igračevih akcija. Jedna igračeva akcija predstavlja celinu koju čine igračev klik (ili druga vrsta input-a), i odgovarajuća reakcija.

Kako smo se u trenutku razvoja skripte bazirali na HOPA igre, ovo je drstično smanjilo opseg kontrola koje je trebalo pokriti. Jedina korisnička interakcija je bila klik na nekoj poziciji na ekranu.

S druge strane, reakciju na igračevu interakciju možemo podeliti na nekoliko kategorija:

Ovako pojednostavljena skripta, sa svim neophodnim komandama, implementirana je u svega nekoliko dana, nakon kojih smo bili u mogućnosti da radimo na logici prolaza kroz igru.

U kasnijim fazama unapređivanja skripte, dodate su matematičke operacije, podrška za funkcije, podrška za uslove i petlje, prefiks za sve objekte kojim im se određuje tip (inspisirano Perl-om), ali je osnovni model definisanja gampelay-ja ostao isti.  Upravo ta jednostavnost nas je ograničavala da svoj rad pojednostavimo i ubrzamo.

Primer jednostavnog koda kojim se kontroliše zatvaranje trenutno otvorenog prozora sa animacijom:

fun show_close_animation {
animate ~close_anim 20f 10f
}
action close click $button_x {
do {
call show_close_animation
set #Is_opened 0
after 5f {
close
}
}
}

Prednost: jednostavna sintaksa, brza implementacija, mogućnost da se od početka radi na logici igre

Nedostatak: skroman opseg mogućnosti, često dupliranje koda

Faza 2 – Apstrakcija akcija

Najveći problem koji je postojao sa postojećim skriptnim jezikom je često dupliranje koda. Ubacivanje podrške za nizove je olakšalo rad, ali suštinski je i dalje ostao osnovni problem da svaka akcija označava klik samo na jedan objekat na sceni. Ovo je predstavljalo naročito veliki problem u puzlama i HO scenama gde većina akcija ima vrlo sličan efekat.

Tako smo došli do nekoliko koncepata koji su označili novu brzinu i fleksibilnost u radu.

Implementacijom ovih ideja, stvorene su “automatizacije” – generički blokovi koda koji se automatski instanciraju na osnovu imena grupe objekata u sceni.

Na taj način je omogućeno da se kod koji se često ponavlja izdvoji, i da se umesto “copy-paste”-ovanja koda on jednostavno koristi na ostalim mestima u igri. Takođe je ostavljena mogućnost da se za svaku konkretnu akciju, koja je implementirana preko neke automatizacije, napiše specifičan kod, čime je uspostavljena veza sa implementacijom logike prolaska igrača kroz igru.

Skriptni jezik je najduže bio u ovoj fazi, jer nije postojala dovoljno velika potreba da se jezik dodatno unapređuje, pa smo svoje vreme ulagali u ostale segmente tehnologije. Kod većine igara na kojima radimo, kod u skripti je i dalje na ovom nivou, što je pokazatelj da je u pitanju optimalan balans između mogućnosti pisanja generičkog koda i konkretne impelementacije nekog dela igre.

Primer komande kojom se za sve objekte čije ime počinje sa iz_ definiše koja skripta treba da se instancira za svaki od objekata:

include_for_each #+::$iz_ALL[] task_iz

Primer generičke skripte koja implementira akciju klika na object i prikazuje tekst (task_iz), gde je <NAME> generičko ime koje se zamenjuje konkretnim imenom za svaku instancu nekog objekta:

action <NAME> info $<NAME> {

init {

enable

set #$.Is_info_zone 1

set #$.Task #@

}

do {

enable

set_str %info_text “<SCENE_NAME>:” #$.name

msg %info_text

call @<NAME>.on_click #$

}

}

Prednost: drastično manje dupliranog koda, korišćenje “automatizacija” za ubrzavanje razvoja igre, zahteva kvalitetno imenovanje objekata (što dovodi do potrebe za većom komunikacijom unutar tima)

Nedostatak: zahteva više planiranja u imenovanju objekata (pogrešno imenovana tekstura se propagira na pogrešno imenovan objekat u sceni, i korišćenje u skripti)

Faza 3 – Dinamičke akcije

Inicijalna ideja ovog skriptnog jezika je da ne postoje eksplicitni dinamički objekti i akcije, već da se svi objekti i akcije koji su igraču neophodni unapred definišu, i kasnije koriste po potrebi.

Dakle, u pitanju je bilo klasično korišćenje “objects pool” design pattern-a. Ovo je predstavljalo kvalitetno rešenje u kom smo mogli da predvidimo korišćenje memorije, dok se optimizacija izvršavanja najviše bazirala na pojednostavljivanju animacija i particle system-a.

Međutim, kako su rasli zahtevi igara na kojima radimo, primetili smo da dosta vremena trošimo na osmišljavanje najboljeg načina da se organizuju objects pool-ovi, u situacijama kada bi bilo daleko lakše da se iskoriste dinamički objekti. Tako smo dolazili u situacije u kojima je u objects pool-ovima postojalo po nekoliko hiljada objekata, iako se tokom izvršavanja igre koristilo maksimalno nekoliko stotina.

Implementaciju podrške za dinamičkim objektima i akcijama smo dosta dugo odlagali, jer smo u startu hteli da izbegnemo probleme vezane za alokaciju i dealokaciju memorije. Ipak, sve češće smo se nalazili u situaciji u kojoj je vreme potrebno za implementaciju relativno jednostavnih logika bilo daleko duže od očekivanog, a scene postale nepotrebno kompleksne.

Zbog toga smo u skriptu dodali mogućnost da se objekti na sceni kreiraju dinamički, ali i da se dinamički kreiraju akcije nad objektima. Pri tome su ove dve operacije bile potpuno nezavisne, pa je bilo moguće da se dinamička akcija kreira i nad statičkim i nad dinamičkim objektima. Za prvu iteraciju implementacije, odlučili smo se da osim komande new, ubacimo i komandu delete, dakle da se dealokacija memorije radi ručno.

Primer kreiranja dinamičkog objekta, postavljanja njegovih parametara, i kreiranja dinamičke akcije vezane za taj objekat:

; Generic action used to handle plane clicks

action plane_action click {

do on press {

call #@.on_click #$

}

}

; Create plane and associated action on specific coordinates

fun create_plane %x %y %texture %on_click_function {

; Create plane…

new %plane $?

set_image %plane %texture

set_size %plane 50 50

move %plane %x %y

set_z %element -30

; Create action for created plane

new %action @plane_action %plane

set %action.on_click %on_click_function

set %plane.action %action

}

Prednost: manje statičkih objekata u scenama, korišćenje objects pool-a nije forsirano već je stvar odluke, korišćenje memorije proporcionalno zahtevima igre u tom trenutku

Nedostatak: potencijalni problemi sa dealokacijom memorije, potencijalno povećanje zauzeća memorije

Faza 4 – Dinamički modeli

Kreiranje dinamičkih objekata i akcija je donelo nove velike mogućnosti u radu. S druge strane, ovako kreirani objekti i akcije su bile nestruktuirani, pa je njihovo korišćenje bilo ad-hoc, i predstavljalo je potencijalni problem na duže staze.

Analizirajući kako bismo dalje mogli da poboljšamo postojeći sistem i da uvedemo mogućnost stuktuiranja dinamičkih objekata i akcija, prirodno nam se nametnula potreba da implementiramo odrađene principe objektno-orjentisanog programiranja, pre svega klase.

Kako je ceo skriptni jezik bio inicijalno planiran da bude jednostavan, i samim tim lak za korišćenje i članovima tima koji nisu programeri, ovaj korak je predstavljao potencijalan zaokret po ovom pitanju.

Nakon nekoliko brainstorming session-a programera koji rade na tehnologiji, došli smo do minimalnog skupa novih komandi koje su nam bile neophodne da uspešno implementiramo struktuiranje delova igre u klase. Pri tome smo se odlučili za najjednostavniji model – jednostruko nasleđivanje, pri čemu su sve metode virtualne, bez ograničenja po pitanju property-ja objekata.

U ovom trenutku smo ponovo evaluirali alternativne jezike, pošto Python, Squirrel i JavaScript sadže implementaciju klasa, i analizirali šta bi prelazak na svaki od njih doneo, a šta bismo izgubili.

Iako je postojao veliki broj pozitivnih faktora za prelazak na novi jezik, zadržali smo se na svom jeziku primarno zbog kolektivnog znanja koje je u tom trenutku bilo usvojeno. Naime, članovi studija su u postojećoj tehnologiji lako dolazili do novih rešenja, dok bi prelazak na drugi jezik označavao određeni zastoj u radu.

Implementacija klasa u sam skriptni jezik je uzela svega nekoliko dana, a najveći posao je tek predstojao, a to je prerađivanje postojećih sistema kojima je bilo neophodno bolje struktuiranje.

Iako OOP principi predstavljaju moćno oružje u modelovanju dinamičkih sistema, pažljivo pristupamo korišćenju klasa unutar igara, i koristimo ih samo za one segmente koda na kojima će raditi isključivo programeri. Ostatak koda se piše tako da bude jednostavan za čitanje i korišćenje svim članovima tima.

Prednosti: mogućnost dodavanja novih apstraktnih koncepata koji nisu deo osnovnog dizajna skripte, struktuiranje dinamički kreiranih objekata i akcija

Nedostaci: potrebno poznavanje OOP principa, potencijalni over-engineering, ulaganje vremena u planiranje koji delovi koda zaista treba prebacivati na OOP

What Went Right

Najbitniji rezultat koji smo uspešno postigli je da u vrlo kratkom roku imamo mogućnost da implemeniramo gameplay preko skripte, što je značilo veliku brzinu developmenta igre od samog početka. Iako je opseg mogućnosti skripte bio skroman, bili smo u mogućnosti da eksperimentišemo sa varijantama gameplay-a, što nam je i bio osnovni cilj.

Takođe, izbor da koristimo svoj skriptni jezik nam je ostavljao mogućnost da istražujemo sa drugačijom sintaksom pojedinih konstrukcija kako bismo došli do najoptimalnijeg rezultata. Ovo je značilo da će skripta koju koristimo pratiti razvoj igara, i da nećemo biti ograničeni na postojeću sintaksu.

Razvijanjem sopstvene skripte, dobili smo i mogućnost da implementiramo specifične bazične koncepte u skripti – objekti na sceni, grupe objekata na sceni, zvuci, objekti u inventaru, funkcije, akcije – sve su ovo first-class entiteti skripte. Ovakav pristup je omogućio da sama sintaksa skripte bude vrlo bliska engleskom jeziku, što skriptu čini lakom za čitanje.

Na kraju, rad na implementaciji konkretne skripte je omogućio programerima, koji su radili na tom delu tehnologije, da primene znanja iz ove oblasti na konkretnom primeru i na taj način teoriju koju su usvojili tokom obrazovanja primene na rešavanje konkretnog problema.

What Went Wrong

Iako je osnovna zamisao bila da skriptni jezik koji koristimo ostane maksimalno pojednostavljen, zahtevi igara na kojima smo radili su se povećavali, pa je bilo neophodno da ubacujemo kompleksnije konstrukcije. Ovo je dovelo do toga da reimplementiramo jezičke konstrukcije koje su već implementirane u nekim od postojećih jezika, što se moglo izbeći korišćenjem nekog od postojećih skriptnih jezika.

Ulaganje u razvoj skripte značio je manje ulaganje u ostale segmente tehnologije i organizaciju rada. Zbog toga je razvoj skriptnog jezika koji koristimo, njegova optimizacija,  bolja integracija u tehnologiju, prerađivanje sintakse oduzimalo vreme koje je moglo biti uloženo u dodavanje više funkcionalnosti na drugim poljima, ili u razvoj gameplay-ja igara.

Sa povećanjem broja aktivnih projekata, povećala se i potreba da se održi backward compatibility skripte. Princip da istu tehnologiju koristimo na svim aktivnim projektima, predstavlja povremeno ozbiljnu prepreku da se skripta razvija dalje, i nalaze bolja rešenja za probleme.

Šta sad znamo?

Razvoj specifičnog skriptnog jezika predstavlja veliki izazov, pre svega po pitanju njegovog dizajna. Implementiranje samo onih konstrukcija koje su u nekom trenutku neophodne za dalji razvoj igre omogućuju balansiranje u radu između razvoja tehnologije i rada na samoj igri.

Ceo poduhvat razvoja skriptnog jezika zahteva konstantan rad na ovom polju, pre svega preispitivanje, analizu i kritiku postojećih rešenja. Međutim, iako u svakom trenutku postoji veliki broj ideja, predloga, pa i osmišljenih rešenja za identifikovane probleme, potrebno je svaku promenu staviti u kontekst rada celog tima, postojećih projekata i sveukupnog pristupa razvoju igrama.

Tek iz takve perspektive se dobija kvalitetan odgovor na pitanje da li je određena promena neophodna, ili dugoročno neće davati bolje rezultate.

Studio Mad Head Games će nastaviti svoje ulaganje u specifičan skriptni jezik, kako bismo došli do rešenja koje će nam omogućiti da ubrzamo i olakšamo razvoj igara, ali i da proširimo opseg igara na kojima radimo.