FallingBricks - dokumentace
Princip a pravidla hry:
Základním rysem jsou náhodně generované kostky, které postupně jednotlivě v určitém časovém intervalu
padají svisle dolů až na dno hrací plochy. Kostky mají v klasické verzi 7 různých tvarů připomínající
písmena. Hráč má k dispozici možnost pomocí klávesových šipek posouvat a otáčet kostku tak aby se šikovně
vešla mezi zaplněná políčka na hracím poli. Důležitým pravidlem je skutečnost, že pokud se na hrací ploše objeví plný
řádek, bude tento řádek vymazán. Cílem je skládat kostky tak aby se podařilo odstranit co nejvíce řádků na
jednou. Hra končí když hráč špatným uspořádáním kostek dosáhne stropu hrací plochy.
Fungování programu
Program se skládá celkem z šesti souborů, z nichž každý obsahuje nadefinovanou třídu obstarávající
příslušnou část hry.
-
Brick.java - třída Brick reprezentuje obecně kostku, se kterou hráč manipuluje, a její pozici na hrací
ploše. Při vytvoření nové instance třídy se, pokud není upřesněn tvar (jako číselný argument konstruktoru),
načte náhodný tvar z vnitří statické třídy Shapes. Třída Brick má definovany čtyři důležité metody, které
pro kostku zajišťují čtyři interaktivní operace v prostředí hrací plochy - posun doleva a doprava, rotaci
kostky a posun o řádek dolu. Každá z těchto metod přistupuje do dvourozměrného pole (představující hrací
plochu) třídy Matrix, a podle aktuální pozice a tvaru kostky kontroluje zda nedošlo ke kolizi s vyplněnými
dílky hrací plochy. Třída Brick, jelikož implementuje rozhrání ActionListener, je schopna spustit vlastní
časovač akce a v pravidelném intervalu (definovaném v třídě Game), posouvat kostku o jeden řádek dolu (tj.
zprovozňuje padání kostky). Objekty třídy Brick lze nalézt v "manažerské" třídě Game, která je předává
třídě Matrix pokud je potřeba aktuální kostku zaznamenat mezi zaplněné dílky na hrací ploše (tj. když dojde ke
kolizi s již zaplněnými dílky). Třída Brick také obsahuje metodu pro vykreslení kostky - pokud je metodě
argumentem předán odkaz na grafické rozhrání, vykreslí do něj na příslušných souřadnicích tvar kostky.
Ještě dodám, že pro vyjádření stavu prázdného a zaplněného dílku kostky jsem využil naprosto dostačující
a paměťově nejméně náročnější typ boolean (např. viz třída Shapes).
-
Matrix.java - třída Matrix představuje hrací pole. Vnitřně je hrací pole založeno na dvourozměrném poli
typu boolean o velikosti dané statickou vlastnosti dimension. Obsahuje metodu pro zapsání tvaru kostky
podle její pozice do hracího pole (v případě kolize se zaplěnými dílky), metodu pro vymazání celých
zaplněných řádků z hracího pole, dálš zjištovací metody "zda byl dosažen strop" a "zda je, argumentem předaný,
řádek celý plný nebo celý prázdný". Obsahuje také metodu pro vykreslení celé hrací plochy (vykreslení
zaplněných dílků), princip fungování stejný jako ve třídě Brick.
-
Score.java - třída Score spravuje bodování hry a vykreslení aktuálního skóre. Body dosažené v aktuální
hře jsou uloženy jednoduše jako počítadlo ve vlastnosti totalScore (int). Body jsou přičítány do této třídy
v jiné třídě Matrix, která podle informací o množství vymazaných řádků rozhoduje kolik bodů hráč získá.
Zbytek třídy tvoří vykreslovací metody pro situaci kdy hráč ještě hraje, a pro situaci kdy hráč hru skončil
(game over).
-
Game.java - je hlavní organizátor celé hry. Spojuje mezi sebou třídu Matrix (hrací pole), třídu Brick
(padající kostka) a třídu Score (bodování). Třída Game totiž vytváří instance všech těchto základních tříd
a ukládá je do statických vlastností, které pak tyto základní třídy (Matrix, Brick, Score) využívají když
potřebují přistoupit k metodám a vlastnostem jiné základní třídy - proto mají tyto třídy u sebe také
uloženou instanci třídy Game. Třída Game obsahuje důležité metody:
správa stavu hry:
- start hry (čistá hrací plocha, vynulování skóre,nová náhodná kostka, spuštění časovače pro
vykreslování hry)
- zastavení hry (zastavení časovače pro vykreslování a zastavení časovače padající kostky)
- obnovení hry (spuštění časovačů pro vykreslování a padající kostky)
- ukončení hry (vypnutí časovačů a nastavení vlastnosti gameOver na true)
hlavní smyčka hry:
- metoda actionPerformed je pravidelně volána časovačem pro vykreslování a zajišťuje logiku kontrolující
zda byla hra ukončena, zda je potřeba zapsat zablokovanou kostku a vyčistit hrací pole od plných řádků,
zda byl dosažen strop hracího pole, také generuje nové náhodné kostky a volá metodu repaint zajišťující
vykreslování:
- metoda pro vykreslování vyčistí plochu v okně a předá objekt grafického prostředí základním třídám
Matrix, Brick a Score.
obsluha klávesnice:
- díky implementaci rozhrání KeyListener je možné během hry kontrolovat hráčem stisknuté klávesy a podle
toho zajistit správné chování pohybu kostky (zavolají se příslušné metody třídy Brick). Například pokud
byla stisknuta klávesa "šipka nahoru" bude na objektu fallingBrick zavolána metoda rotate zajišťující
otočení kostky
-
FallingBricks.java - třída FallingBricks obsahuje soubor Main a je tedy spouštěcí třídou celého programu. Má poměrně
jednoduchý a jednorázový úkol inicializovat swingové okno JFrame, umístit jej do středu obrazovky a hlavně
vytvořit objekt Game a spustit tak celou hru.
-
Debug.java - třída Debug je pouze jednoduchá pomocná, velice užitečná při ladění programu. V začátcích
se občas některé úseky, zejména s grafikou chovaly nepřidvídaně a díky této třídy bylo možné sledovat
posloupnost volání metod během hry. Vypisování na konzoli lze vypnout nastavením konstanty inProduction.
Závěr a vlastní postřehy
Při vytváření této semestrálky jsem si chvílema, hlavně kolem grafiky, nevěděl moc rady, ale naštěstí trocha
hledání na internetu a experimentování vždycky pomohla a podařilo se tak vytvořit co jsem potřeboval. Co do
návrhu algoritmů jsem rád že se mi podařilo vytvořit některé části kódu tak aby zbytečně nezpracovávaly
některé úseky víckrát. Například v třídě Matrix metoda removeFullRows nejdříve v první "hluboké smyčce"
vymaže celé plné řádky a zároveň tak zjistí stav každého řádku (zda je částečně zaplněný), a pak v další
smyčce když už je znám stav jednotlivých řádků stačí "mělká smyčka" (nemusí kontrolovat navíc každé políčko
řádku) na to aby zajistila základní gravitaci propadnutím prázdných řádků.
Gravitace je v mé implementaci hry skutečně pouze základní. To znamená že se na hrací ploše hledají prázdné
řádky a pokud tam jsou, zajístí se aby se vyšší řádky propadly. Hra neobstarává reálnou gravitaci, která by
zajistila propadnutí dílků do mezer, které se objevily po vymazání plných řádků. Tudíž může nastat
situace, kdy se na hrací ploše objeví dílek, který přestože není ničím podpírán, visí nad volným prostorem.
Zdroje
Užitečný zdroj základních informací a tipů pro vývoji her Gamedev.net
Kniha Java 5 (Ivor Horton) - trochu horší na čtení ale celkem dobře vysvětleno fungování komponent awt a swingu.