V tomto opakovacom tutoriáli vyrobíme jednoduchú hru, v ktorej budeme klávesami ovládať hladný krúžok na ceste za zeleným jedlom a v ohrození nepriateľom.
Hráč je fialový krúžok, pohybuje sa horizontálne alebo vertikálne a pri vyjdení z okraja obrazovky sa vráti na opačnom konci. Nepriateľ je červený krúžok, na začiatku má náhodný smer a odráža sa od okrajov obrazovky. Jedlo je vygenerované na náhodnej pozícii a je to pulzujúci zelený štvorček.
1. Základný skeč
Keď chceme, aby skeč reagoval na klávesy či myš, alebo ak má byť animovaný, tak budeme využívať podprogramy setup() a draw(). Zároveň si už pripravíme aj pozadie a nejaké základné premenné:
Jeden z šikovných spôsobov, ako napísať program, je najprv si ho napísať ľudskou rečou pomocou komentárov. Tým získame prehľad o tom, čo všetko treba urobiť, a následne už len dopĺňame ku každému komentáru jeho kód. Aha takto:
float hx, hy; // pozicia hraca
float shx, shy; // smer hraca
float nx, ny; // pozicia nepriatela
float snx, sny; // smer nepriatela
float jx, jy; // pozicia jedla
void setup()
{
size(600,600);
// Nastavenie pozicie a smeru hraca
// Nastavenie pozicie a smeru nepriatela
// Nastavenie pozicie jedla
}
void draw()
{
background(0);
// Pohyb hracom
// Pohyb nepriatelom
// Vykreslenie hraca, jedla, nepriatela
// Zisti, ci som sa zrazil s jedlom
// Zisti, ci som sa zrazil s nepriatelom
}
3. Počiatočné nastavenia
Pozície hráča, jedla aj nepriateľa nastavíme náhodne na obrazovke. Smer hráča budeme určovať klávesami, ale pre začiatok mu dajme smer doprava (shx = 1, shy = 0). Smer nepriateľa dajme ako náhodné súradnice s rozsahu -3, 3.
Pohyb docielime tak, že v draw() budeme zvyšovať pozície hráča aj nepriateľa o ich príslušné smery. Takto:
// Pohyb hracom
hx = hx + shx;
hy = hy + shy;
// Pohyb nepriatelom
nx = nx + snx;
ny = ny + sny;
Pohyb hráča je zacyklený na obrazovke. Ak je jeho pozícia príliš vpravo, nastavíme o na ľavý okraj obrazovky. A podobne pre všetky ostatné smery:
// Pohyb hracom
hx = hx + shx;
hy = hy + shy;
if (hx > width)
{
hx = 0;
}
if (hx < 0)
{
hx = width;
}
if (hy > height)
{
hy = 0;
}
if (hy < 0)
{
hy = height;
}
Alebo môžeme tento kód zapísať aj skrátene. Ak je v podmienke if len jeden jediný príkaz a žiadne else, dá sa každá podmienka zapísať aj bez zátvoriek {,} a do jedného riadku:
// Pohyb hracom
hx = hx + shx;
hy = hy + shy;
if (hx > width) hx = 0;
if (hx < 0) hx = width;
if (hy > height) hy = 0;
if (hy < 0) hy = height;
Nepriateľ sa má pri svojom pohybe odrážať od stien. To znamená, že ak jeho x-ová súradnica je mimo obrazovky, tak jeho x-ové smerovanie sa obráti na opačné. A takisto v prípade y:
// Pohyb nepriatelom
nx = nx + snx;
ny = ny + sny;
if (nx > width) snx = -snx;
if (nx < 0) snx = -snx;
if (ny > height) sny = -sny;
if (ny < 0) sny = -sny;
6. Rýchlosť pohybu
Ak sa objekty hýbu príliš pomaly, môžeme pridať parameter rýchlosti pre hráča aj pre nepriateľa
A pri pohybe jednotlivých objektov týmto parametrom vynásobíme smer:
// Pohyb hracom
hx = hx + rh * shx;
hy = hy + rh * shy;
// Pohyb nepriatelom
nx = nx + rn * snx;
ny = ny + rn * sny;
7. Ovládanie klávesnicou
Ak meniť smer pohybu hráča klávesnicou, budeme pridáme do skeču podprogram, ktorý reaguje na stlačenie klávesy:
void keyPressed()
{
}
Pohyb budeme ovládať šípkami. Ak bola stlačená šípka nahor, zmení sa smer na shx = 0 a shy = -1. Ak bola stlačená šípka nadol, bude shx = 0, shy = 1. A tak podobne pre ostatné dva smery. Položíme podmienku na základe hodnoty systémovej premennej keyCode, ktorá obsahuje kód stlačenej klávesy:
Ak chcete fintu na skrátenie kódu, rozbaľte si nasledujúcu sekciu. Ale nie je to povinné:
Skrátenie if-ov podmocou switch
Ak máme takto veľa if-ov, ktoré sa všetky pýtajú, čomu sa rovná jedna premenná (v našom prípade keyCode), tak môžeme namiesto 4 if-ov napísať jeden switch a 4 prípady case:
Toto je jediná vec, ktorá je nová v tomto opakovaní. Aby sme vedeli zistiť, či sa dve veci dotýkajú, budeme potrebovať jednoduchú matematiku. Dve veci sa dotýkajú, ak vzdialenosť ich stredov je menšia ako súčet ich polomerov.
Aby sme mali program urobený všeobecne, tak vyrobme premenné na veľkosť hráča, nepriateľa aj jedla. Doteraz sme mali v kóde čísla natvrdo (v príkazoch square a circle), ale vytiahneme si ich do premenných:
Teraz už môžeme napísať podmienku na zistenie, či sme sa zrazili s jedlom. Pomôžeme si príkazom dist, ktorý počíta vzdialenosť medzi dvojicou súradníc. Ak je vzdialenosť menšia ako súčet polomerov, tak došlo ku kolízii a my vygenerujeme nové jedlo na nových súradniciach:
// Zisti, ci som sa zrazil s jedlom
if (dist(hx, hy, jx, jy) < vh/2 + vj/2)
{
// Zapocitame skore
// ...
// Presunieme jedlo na nove suradnice
jx = random(width);
jy = random(height);
}
Ostáva pridať započítavanie skóre a jeho výpis na obrazovku. Vyrobíme si premennú pre skóre:
A do podmienky, keď nastala kolízia, doplníme zvýšenie skóre o 1:
// Zisti, ci som sa zrazil s jedlom
if (dist(hx, hy, jx, jy) < vh/2 + vj/2)
{
// Zapocitame skore
skore = skore + 1;
// Presunieme jedlo na nove suradnice
jx = random(width);
jy = random(height);
}
9. Kolízia s nepriateľom
Podmienku, či som sa zrazil s nepriateľom, doplníme podobne ako v prípade jedla:
// Zisti, ci som sa zrazil s nepriatelom
if (dist(hx, hy, nx, ny) < vh/2 + vn/2)
{
// Koniec hry
// ...
}
A na koniec hry vypíšeme na obrazovku veľký červený GAME OVER a zastavíme hru.
Ako zastavíme hru? Urobiť to korektne by bolo trochu na dlhšie, ale my si pomôžeme jednoduchým hackom: Nastavíme frameRate aplikácie na 0, tým sa vypnú všetky animácie. Bohužiaľ sa vypne aj interakcia, preto je to nekorektné. Ale na teraz nám to stačí:
// Zisti, ci som sa zrazil s nepriatelom
if (dist(hx, hy, nx, ny) < vh/2 + vn/2)
{
// Koniec hry
frameRate(0);
textSize(100);
fill(255, 0, 0);
textAlign(CENTER, CENTER);
text("GAME OVER", width/2, height/2);
}
10. Pulzujúce jedlo
Ako bonus si dorobíme animáciu jedla, ktorého veľkosť bude pulzovať. Na tento recept budeme potrebovať:
nejakú premennú, ktorá rastie v čase
funkciu, ktorá z tej premennej bude vyrábať pulzujúce hodnoty
funkciu, ktorá z tých pulzujúcich hodnôt vyrobí veľkosť jedla.
Premenná, ktorá rastie v čase je napríklad systémová premenná frameCount, ktorú Processing automaticky zvyšuje o 1 po každom vykonaní draw().
Pomocou matematickej funkcie sínus vyrobíme z rastúcich hodnôt frameCount hodnoty, ktoré oscilujú medzi -1 až +1.
A pomocou funkcie map() zmeníme hodnoty z intervalu -1 až +1 na interval napríklad 0.8 * veľkosť jedla až 1.5 * veľkosť jedla.
Keď toto vyrátame, uložíme si to do novej premennej, a tú potom použijeme pri vykreslení štvorčeka v príkaze square.
Zelený štvorček začne pulzovať. Ak sa vám nepáči, že pulzuje veľmi rýchlo, tak spomalíme rýchlosť tak, že frameCount vynásobíme nejakým malým číslom, napríklad 0.1: