Sam svoj programer
Programiranje v predmetno usmerjenem jeziku, kot je java, nam omogoča, da aplikacijo, ki jo želimo razviti, opišemo v obliki strukture (hierarhije) razredov. Razredi v takšni strukturi predstavljajo osnovne sestavne dele naše aplikacije in s svojimi spremenljivkami in metodami določajo delovanje celotne aplikacije. Tako lahko še tako zahtevno aplikacijo razčlenimo na enostavne sestavne dele in s tem razbijemo kompleksno implementacijo na več enostavnejših delov. S tem ne le poenostavimo sam razvoj aplikacije, temveč tudi zmanjšamo možnosti vnosa napak v programsko kodo, saj se pri implementaciji posameznega dela aplikacije lažje osredotočamo na samo funkcionalnost kode. Z razredno strukturo prav tako poenostavimo razumevanje kode, povečamo možnost vnovične rabe posameznih delov kode, pa tudi povečamo pregled nad celotno implementacijo in lažje določimo, katere funkcionalnosti moramo v našo aplikacijo še vpeljati.
Razredna struktura igre
Igro smo razdelili na več smiselnih delov, ki so predstavljeni s posameznimi razredi. Vstopni razred v našo aplikacijo je, kot pri večini drugih androidnih aplikacij, tipa Aktivnost. To v našem primeru predstavlja razred And_GameActivity, ki poskrbi za inicializacijo naše igre. Razred Game predstavlja samo igro, hrani informacije, v katerem stanju je trenutno igra, in vse druge komponente igre. GameView je razred, ki smo ga v podobni obliki spoznali že v prejšnjem delu serije in skrbi za prikaz vsebine igre in interakcijo z njo. Abstraktni razred GameObject predstavlja šablono za vse objekte, ki se v igri izrisujejo in so predstavljeni z razredi GUI, SpaceShip, SpaceInvader, Bullet in GameLevel. Prav tako razred GameObject implementira vmesnik Renderable, s čimer poskrbimo za to, da so vsi primerki tega razreda izrisljivi (vsebujejo metodo render). V nadaljevanju so predstavljene podrobnosti posameznih razredov, njihove lastnosti in funkcionalnosti. Slika 1 prikazuje razredno strukturo naše igre. Označena so dedovanja in implementacije med razredi, s čimer si laže predstavljamo organizacijo same igre.
SLIKA 1: Razredni diagram, ki predstavlja celotno razredno hierarhijo naše igre.
And_GameActivity
Aktivnost predstavlja vstopni razred za androidno aplikacijo za vse aplikacije z uporabniškim vmesnikom. Tako tudi v našem primeru vstopni razred razširja razred Activity. V razredu nastavimo razporejevalnik uporabniškega vmesnika, za kar bomo v našem primeru uporabili zgolj instanco razreda GameView, definiranega podobno kot v prejšnjem delu serije člankov in podrobneje opisanega v nadaljevanju. V glavnem razredu prav tako nastavimo, da naša aplikacija prepreči ugašanje in zaklepanje zaslona po določenem času. To storimo tako, da aplikacija zahteva preprečitev ugašanja in zaklepa zaslona, kar prikazuje spodnja koda:
getWindow().addFlags(LayoutParams.FLAG_KEEP_SCREEN_ON);
V aktivnosti ustvarimo še nov primerek razreda Game, ki prevzame nadaljnji nadzor nad igro. Igri ob stvaritvi podamo tudi GameView, na katerega se bo celotna igra izrisovala.
Game
Razred predstavlja osrčje igre in skrbi, da se celotna igra izvaja, kot je treba. V njem hranimo stanje, v katerem je trenutno naša igra (glavni menu, igranje, konec igre ...), kakšno je stanje točk v naši igri, koliko življenj še ima igralec in podobne lastnosti. Poleg teh informacij pa razred hrani še vse predmete, ki se med igro izrisujejo (vesoljsko ladjico, napadalce, izstrelke, vmesnik ...), časovnike, ki skrbijo za izris objektov ob pravem času, poslušalce za detekcijo dotika in metode, potrebne za izvajanje igre. Javne metode so:
Timer invaderTimer = new Timer("Invaders");
invaderTimer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
gameLoop();
}, 0, 500);
public void render(Canvas c) {
switch (currentGameState) {
case MAIN_MENU_STATE:
...
break;
case GAMEPLAY_STATE:
...
break;
case GAME_OVER_STATE:
...
break;
}
gameView.postInvalidate();
}
zasebne metode pa so:
SLIKA 2: Prikaz detekcije trka med napadalcem in izstrelkom s pomočjo metode AABB
Slovarček
abstraktni razred - razred, za katerega velja, da ne moremo ustvariti njegovih primerkov. Koncept se uporablja pri definiranju razredne hierarhije.
inicializacija - postopek za pripravo programa ali računalniškega sistema za delovanje.
vmesnik - angl. interface, programerski koncept, ki od razredov, ki ga implementirajo, zahteva, da vsebujejo redefinicijo metod, definiranih v vmesniku.
GameObject
Razred GameObject razširja razred View, namenjen prikazu androidne aplikacije. Podrobneje smo nalogo takšnega razreda predstavili že v prejšnjem delu serije člankov. V trenutni implementaciji smo razred poenostavili in uporabljamo predvsem njegovo sposobnost izrisa na zaslon. Tako se znotraj metode onDraw ????
Renderable
Renderable predstavlja vmesnik za objekte, ki so izrisljivi. Razredi, ki implementirajo ta vmesnik, morajo tako nujno redefinirati njegove metode in s tem izpolniti določene funkcionalnosti. V našem primeru to pomeni, da bodo vsi razredi, ki implementirajo ta vmesnik, vsebovali metodo render, ki kot parameter prejme objekt Canvas (platno) in skrbi za izris objekta na zaslon. Razred, ki neposredno razširja vmesnik, je GameObject. Razredi, ki vmesnik razširjajo posredno, pa so GUI, SpaceShip, SpaceInvader, Bullet in GameLevel. Definicija vmesnika je nadvse preprosta in je prikazana spodaj:
public interface Renderable {
public abstract void render(Canvas c);
}
GameObject
Abstraktni razred, ki predstavlja osnovo za dedovanje vseh izrisljivih elementov igre in vsebuje spremenljivke, ki jih uporabljajo vsi razširjeni razredi. Te spremenljivke so:
GUI
Razred je namenjen izrisu celotnega grafičnega vmesnika igre. Grafični vmesnik se razlikuje za posamezna stanja, v katerih je igra v določenem času, kot so glavni menu, igranje, konec igre ... Pri glavnem menuju je treba izrisati ime igre in gumbe vmesnika (začetek igre, izhod) in vse druge grafične elemente (naslov, napadalce ...), kar je prikazano na sliki 3.
SLIKA 3: Slika glavnega menuja igre, ki se prikaže ob zagonu
Poleg glavnega menuja razred GUI poskrbi tudi za izris vmesnika med samo igro. V času igranja nam igra prek vmesnika sporoča, koliko točk smo zbrali in koliko življenj imamo še na voljo. Na tem mestu naj kot zgled omenimo, kako smo izvedli izpis številk. Posamezna cifra je predstavljena s samostojno sliko, kar skupno nanese 10 slik (za cifre 0, 1, ... , 9). Izpis samega števila točk pa je izveden kot prikaz ustreznih slik na ustreznih mestih na zaslonu. Izsek kode, ki skrbi za izris števil, je prikazan spodaj:
for (int i=0; i<score.length(); i++) {
int x = 10 + scoreImage.getWidth()/2 + i * no0.getWidth()/2;
int y = 20;
int no = Integer.parseInt(score.substring(i, i+1));
switch (no) {
case 0:
c.drawBitmap(no0, null,
new RectF(x, y, no0.getWidth()/2+x, no0.getHeight()/2+y), mPaint);
break;
...
case 9:
c.drawBitmap(no9, null,
new RectF(x, y, no0.getWidth()/2+x, no0.getHeight()/2+y), mPaint);
break;
};
Podobno bi lahko izvedli tudi izris besedila, a se za to možnost zaradi majhne količine slednjega nismo odločili. Besedilo smo oblikovali in shranili kot slike napisov, ki se prikazujejo v igri. Za aplikacije oz. igre z več besedila bi bilo to vsekakor smiselno. Poleg števila zbranih točk in življenj med igro izrisujemo tudi puščice, ki nakazujejo predele zaslona, kjer dotik pomeni pomik ladjice v smer, ki jo nakazuje puščica.
Drugačen vmesnik pa se prikaže tudi, ko igro končamo. Takrat na zaslon izpišemo "GAME OVER" in s tem uporabnika obvestimo, da je igre konec, in ga vprašamo, ali želi igro spet začeti ali se vrniti na glavni menu igre.
Vmesnik tako vsebuje metode,s katerimi lahko osvežujemo prikazano vsebino. Metode razreda GUI so:
SpaceShip
Razred predstavlja vesoljsko ladjico, ki jo upravlja igralec. Ladjica je predstavljena z eno samo bitno sliko. Razred vsebuje spremenljivke za hranjenje trenutnega položaja ladjice in metode, s katerimi lahko izvemo, kje je ladjica, in jo tudi ustrezno premikamo. Največkrat uporabljene metode v igri so:
Izris ladjice je zelo enostaven, saj moramo med igranjem v določenem času le na ustrezno mesto izrisati bitno sliko, ki predstavlja ladjico.
SpaceInvader
Razred SpaceInvader predstavlja primerke napadalcev. V igri so trije tipi napadalcev, ki se med seboj razlikujejo po videzu in številu točk, ki jih prinesejo ob uspešni sestrelitvi. Vesoljski napadalci so tudi animirani, kar pomeni, da se njihov videz s časom spreminja. To smo izvedli tako, da smo za vsakega napadalca narisali dve sliki, ki ju pri premiku napadalca zamenjujemo. Zgledi parov slik so prikazani na sliki 4. Tako ustvarimo navidezno spreminjanje napadalca (premikanje njegovih posameznih delov). Razred SpaceInvader je zasnovan tako, da ga lahko uporabimo za prikaz poljubnega izmed treh tipov napadalcev. Stvaritev napadalca, določitev njegovega tipa, velikosti in položaja prikazuje spodnji zgled:
SpaceInvader invader = new SpaceInvader(gameView.getResources());
invader.setInvaderType(2);
invader.setScale(scale);
invader.setPosition(...);
SLIKA 4: Prikazane slike vseh treh parov slik napadalcev, svetlo moder - vreden 10 točk, zelen - vreden 20 točk, in roza - vreden 30 točk.
Metode, ki jih vsebuje razred SpaceInvader, so:
Bullet
Izstrelki, ki jih kot igralec izstreljujemo proti napadalcem, so definirani z razredom Bullet. Razred v osnovi predstavlja izstrelek, ki ga izstreli vesoljska ladjica, lahko pa bi z njim realizirali izstrelke, ki bi jih napadalci izstreljevali proti vesoljski ladjici. Spremenljivke razreda hranijo sliko izstrelka, položaj izstrelka na zaslonu, smer izstrelka, hitrost izstrelka in tip izstrelka, metode razreda pa so:
Izstrelek je animiran, kar je realizirano s časovnikom, podobno kot pri napadalcih. Za razliko od napadalcev se položaj izstrelka izračuna vsakih 40 ms, s čimer postane njegovo premikanje po zaslonu veliko bolj zvezno.
GameLevel
Celotno okolje, v katerem se odvija igra (ozadje, okrasi ...), je definirano z razredom GameLevel. Na ta način lahko enostavno prilagajamo videz posameznega nivoja igre in tako naredimo igro bolj zanimivo. V razredu tako glede na trenutni nivo igre izrisujemo različne grafične elemente, s katerimi je definirano igralno okolje.
Kako naprej?
V članku je opisana struktura celotne igre in povzeta funkcionalnost posameznih delov. Kljub temu da gre za preprosto igro, skozi članek spoznamo, da je za lažji razvoj in izvedbo zelo pomembna dobra razredna struktura aplikacije. Naša aplikacija - igra je sestavljena iz 10 razredov. Nekateri razredi predstavljajo zgolj drobne koščke celote (posamezni elementi izrisa GUI, SpaceInvader, SpaceShip ...), nekateri pa povezujejo celotno množico razredov (Game) in s tem definirajo delovanje celotne igre. Omenili smo tudi možnosti za nadgradnjo igre z dodatnimi nivoji in možnostjo implementacije agresivnejših igralcev s sposobnostjo streljanja. Prav tako trenutna realizacija igre ne upošteva življenj igralca, temveč se konča, ko napadalec uniči vse napadalce, ali pa ko napadalci dosežejo našo vesoljsko ladjico. Projekt tega članka je tako kot prejšnji dostopen na android.monitor.si. Vsi nastavki za nadgradnje programa so namenoma nedokončani. Program bomo skupaj nadgradili v naslednjem članku, bralec pa lahko do takrat doda poljubno funkcionalnost po lastni želji ali na svoj način implementira nakazane razširitve.