Cykly a podmienky
Vytvorme generátor levelu, ktorý na celú šírku obrazovky vytvorí terén pozostávajúci zo štvorcových dielikov v rôznej výške. Dieliky majú veľkosť d
. Výška terénu je v každom stĺpci náhodná. Spodné dieliky sú hnedé ako hlina, najvyššie dieliky sú zelená ako tráva. Ak má náhodou stĺpec výšku 0, tak sa vykreslí modrý dielik pre vodu.
A náhodne sa nad každým stĺpcom môže vykresliť aj žltá minca.

Zopakujeme si pri tom tieto koncepty:
Cyklus
for
Dvojitý cyklus
for
Podmienka
if
Náhodnosť
Postup
Rozdelíme si úlohu na pod-úlohy tak, že najprv napíšeme kód na vykreslenie jedného jediného stĺpca, vyriešime tam ofarbovanie tehličiek podľa výšky. A potom pomocou cyklu nakreslíme stĺpce vedľa seba.
1. Základný sketch
Nebudeme potrebovať žiadnu animáciu ani interakciu, takže nateraz si vystačíme s jednoduchým skečom bez setup
a draw
. Nastavíme si veľkosť okna, farbu pozadia a vyrobíme si premennú, ktorá d
, ktorá bude definovať veľkosť jedného dieliku.
size(800, 200);
background(#58D4FF);
int d = 20;
2. Čistý stĺpec
Vytvorme si premennú vyska
, ktorá bude definovať, koľko dielkov je v stĺpci. Zatiaľ si ju nastavme napríklad na hodnotu 4:
int vyska = 4;
A pomocou for
cyklu vykreslíme nad seba dieliky v počte vyska
:
size(800, 200);
background(#58D4FF);
int d = 20;
int vyska = 4;
for (int i = 0; i < vyska; i++)
{
square(0, i*d, d);
}
Takýto program vykreslí dieliky odhora:

Musíme sa preto pohrať s y-súradnicou v príkaze square
. Ľavý horný roh prvého dielika chceme mať vo výške height-d
, druhý dielik bude vo výške height-2*d
, tretí dielik vo výške height-3*d
a tak ďalej, takže výraz i*d musíme prepísať takto:
square(0, height - (i+1)*d, d);
Vyskúšajte rôzne hodnoty premennej vyska, uistite sa, že sa vždy vykreslí správny počet dielikov:

vyska=6
3. Ofarbenie stĺpca
Štandardne chceme všetky dieliky hnedé:
for (int i = 0; i < vyska; i++)
{
fill(#6C4700); // Hneda farba
square(0, height - (i+1)*d, d);
}
Ale ak chceme, aby posledný dielik v poradí bol zelený, musíme si pomôcť podmienkou. Ak ide o posledný dielik v poradí, nastav farbu na zelenú, inak nastav farbu na hnedú.
Ako vieme, že ide o posledný dielik? Podľa hodnoty i
. A aká je posledná hodnota i
ak cyklus ide od i=0
po i < vyska
? Je to vyska-1
. Podmienku teda napíšeme takto:
for (int i = 0; i < vyska; i++)
{
if (i == vyska - 1)
{
fill(#12B727); // Zelena farba
}
else
{
fill(#6C4700); // Hneda farba
}
square(0, height - (i+1)*d, d);
}

Ešte doplníme prípad, ak výška je rovná 0. Vtedy vykreslíme len modrý dielik. Znovu si pomôžeme podmienkou if
. Ak je výška väčšia ako 0, tak sa vykoná tento náš už existujúci cyklus. A inak sa vykreslí modrý dielik:
if (vyska > 0)
{
// Vykreslenie stlpca
for (int i = 0; i < vyska; i++)
{
if (i == vyska - 1)
{
fill(#12B727); // Zelena farba
}
else
{
fill(#6C4700); // Hneda farba
}
square(0, height - (i+1)*d, d);
}
}
else
{
fill(#0B7F9B); // Modra farba
square(0, height - d, d);
}
Nastavte premennú vyska
na 0
a vyskúšajte, či program funguje:

Tým by sme mali jeden stĺpec vyriešený a môžeme začať stĺce vedľa seba opakovať.
4. Stĺpce vedľa seba
V programe už máme jeden cyklus for
, ktorý kreslí dieliky nad seba a vytvára stĺpec. Vytvoríme druhý cyklus for, ktorý bude opakovať stĺpce vedľa seba.
Koľko ale budeme potrebovať stĺpcov? To si vypočítame podľa veľkosti dieliku a veľkosti obrazovky a uložme si to do premennej stlpcov
a zavrieme zvyšok programu o veľkého for
cyklu:
size(800, 200);
background(#58D4FF);
int d = 20;
int vyska = 0;
int stlpcov = width / d;
for (int s = 0; s < stlpcov; s++)
{
if (vyska > 0)
{
// Vykreslenie stlpca
for (int i = 0; i < vyska; i++)
{
if (i == vyska - 1)
{
fill(#12B727); // Zelena farba
}
else
{
fill(#6C4700); // Hneda farba
}
square(0, height - (i+1)*d, d);
}
}
else
{
fill(#0B7F9B); // Modra farba
square(0, height - d, d);
}
}
Zatiaľ program viditeľne nič nerobí:

Ale to je preto, že síce nakreslíme veľa stĺpcov, akurát im nijak nemeníme x-súradnicu v príkaze square
, takže všetky sú natlačené vľavo na súradnici 0. Musíme teda nuly nahradiť výrazom, ktorý sa odvíja od stĺpca, v ktorom sme:
for (int s = 0; s < stlpcov; s++)
{
if (vyska > 0)
{
// Vykreslenie stlpca
for (int i = 0; i < vyska; i++)
{
if (i == vyska - 1)
{
fill(#12B727); // Zelena farba
}
else
{
fill(#6C4700); // Hneda farba
}
square(s*d, height - (i+1)*d, d);
}
}
else
{
fill(#0B7F9B); // Modra farba
square(s*d, height - d, d);
}
}

5. Náhodná výška stĺpca
Teraz sú všetky stĺpce rovnako vysoké, lebo nijak nemeníme ich výšku. V každo opakovaní veľkého cyklu, ktorý ide cez stĺpce teda musíme určiť náhodnú výšku každému stĺpcu.
Z akého rozsahu bude? Vyrátajme si, koľko najviac riadkov môže terén mať podľa výšky okna a veľkosti dielika:
size(800, 200);
background(#58D4FF);
int d = 20;
int vyska = 0;
int stlpcov = width / d;
int riadkov = height / d;
A nastavme výšku pred každým jedným stĺpcom na náhodnú hodnotu:
for (int s = 0; s < stlpcov; s++)
{
vyska = int(random(0, riadkov));
if (vyska > 0)
{
// Vykreslenie stlpca
for (int i = 0; i < vyska; i++)
{
if (i == vyska - 1)
{
fill(#12B727); // Zelena farba
}
else
{
fill(#6C4700); // Hneda farba
}
square(s*d, height - (i+1)*d, d);
}
}
else
{
fill(#0B7F9B); // Modra farba
square(s*d, height - d, d);
}
}

6. Pekná náhodná výška
Toto je dosť divoký terén, preto upravíme generovanie výšky. Namiesto toho, aby každá výška bola kompletne náhodná, tak zmeníme kód tak, aby sa výška ďalšieho stĺpca líšila od súčasnej výšky maximálne o 1.
Nastavme na začiatku výšku na nejakú peknú hodnotu, napríklad na tretinu maximálneho počtu riadkov:
size(800, 200);
background(#58D4FF);
int d = 20;
int stlpcov = width / d;
int riadkov = height / d;
int vyska = riadkov/3;
A teraz namiesto nastavenia úplne náhodnej výšky vnútri cyklu, si nastavíme, aby sa výška zmenila náhodné číslo z rozsahu -1, 0, 1:
for (int s = 0; s < stlpcov; s++)
{
vyska = vyska - round(random(-1, 1));
if (vyska > 0)
{
// Vykreslenie stlpca
for (int i = 0; i < vyska; i++)
{
if (i == vyska - 1)
{
fill(#12B727); // Zelena farba
}
else
{
fill(#6C4700); // Hneda farba
}
square(s*d, height - (i+1)*d, d);
}
}
else
{
fill(#0B7F9B); // Modra farba
square(s*d, height - d, d);
}
}
Prečo sme použili nejaké neznáme round
namiesto známeho int
? Lebo round
zaokrúhľuje v tomto prípade lepšie ako int
. Koho to zaujíma, môže si rozbaliť vysvetlenie tejto zákernosti, ale koho nie, môže to preskočiť.
Po tejto úprave náhodnosti z úplne divokej na náhodnosť plus mínus jedna už vyzerá terén pekne:

Ak nám vadia dlhé vodné plochy, tak tie vznikajú preto, že vyska
klesne hlboko do záporných čísel a chvíľu jej trvá, kým vylezie naspäť nad nulu. Môžeme tomu pomôcť napríklad tak, že ak klesne vyska
pod 0, vrátime ju na 0. Zabráni to výške, aby klesla príliš hlboko.
vyska = vyska + round(random(-1, 1));
if (vyska < 0)
{
vyska = 0;
}
Upravený generátor funguje výborne:

7. Mince
Správny level musí obsahovať aj niečo, čo sa dá zbierať. My vygenerujeme nad terénom zlaté mince. Mince sa budú generovať iba nad terénom nie nad vodou. Preto kód na vykreslenie mince vložíme do veľkého cyklu, po vykreslení stĺpca:
if (vyska > 0)
{
// Vykreslenie stlpca
for (int i = 0; i < vyska; i++)
{
if (i == vyska - 1)
{
fill(#12B727); // Zelena farba
}
else
{
fill(#6C4700); // Hneda farba
}
square(s*d, height - (i+1)*d, d);
}
// Minca
fill(#FFF52C);
noStroke();
circle(s*d + d/2, height - vyska*d - d/2, d/2);
stroke(0);
}
A máme mince všade nad terénom:

My ich ale nechceme mať všade. Chceme aby sa minca objavila napríklad iba v jednom prípade z desiatich. Pomôžeme si tak náhodnou podmienkou:
// Minca
if (random(10) < 1)
{
fill(#FFF52C);
noStroke();
circle(s*d + d/2, height - vyska*d - d/2, d/2);
stroke(0);
}

Na koniec ešte otestujeme, či náš generátor funguje dobre pre rôzne hodnoty veľkosti dielika:

d=40

Last updated