Táto jednoduchá ukážka má simulovať prekážky približujúce sa z jedného bodu v diaľke smerom dopredu k objektu ovládanému hráčom (uhýbačovi). Podrobnosti implementácie sa dajú prečítať zo zdrojových kódov tried.
import knižnica.*;
public class Prekážka extends GRobot
{
// Tento príznak je nastavený od štartu prekážky dovtedy, kým neklesne
// pod určitú úroveň na ploche, kedy vyžiada vznik novej prekážky
// a príznak vynuluje. (Pozri reakciu aktivita.)
private boolean žiadajNovúPrekážku = true;
public Prekážka()
{
zdvihniPero();
pomer(0.8); // (Nastavenie pomeru tvaru obĺžnika.)
gyroskop(90.0); // (O gyroskope sa píše v metóde koliduje nižšie.)
// Zrýchlenie je nastavené tak, aby pred dosiahnutím spodného
// okraja obrazovky nedosiahlo maximálnu povolenú rýchlosť (20 bodov
// za tik). Napriek tomu sa zdá, že prekážka spomaľuje, pretože mení
// svoju veľkosť podľa vertikálnej súradnice, aby vznikol dojem
// perspektívy.
zrýchlenie(0.25);
maximálnaRýchlosť(20);
reset();
}
public void reset()
{
// (Reset rýchlosti, polohy a cez aktivitu aj veľkosti.)
rýchlosť(0, false);
skočNa(0, Svet.najväčšieY());
aktivita();
// (Nastavenie nového cieľa zároveň prekážku aktivuje.)
cieľ(Svet.náhodnéReálneČíslo(Svet.najmenšieX(), Svet.najväčšieX()),
Svet.najmenšieY() * 4);
žiadajNovúPrekážku = true;
// (Presunieme prekážku na spodok kreslenia, aby pôsobila, že je za
// ostatnými, ktoré sa mezitým posunuli na obrazovke nižšie.)
naSpodok();
}
@Override public void kresliTvar()
{
hrúbkaČiary(veľkosť() / 8);
farba(biela);
vyplňObdĺžnik();
farba(čierna);
kresliObdĺžnik();
}
@Override public boolean koliduje(GRobot iný)
{
// Blok try-finally spolu s riadkom kódu pred ním slúžia na
// zálohovanie a obnovenie uhla prekážky, pretože jej uhol sa musí
// v čase detekcie kolízie rovnať 90°.
//
// Inak by detekcia bola odchýlená, pretože by porovnávala tvar
// obdĺžnikovej oblasti orientovanej v skutočnom smere prekážky.
//
// Skutočný smer prekážky sa od kresleného smeru líši, pretože
// prekážka má aktivovaný gyroskop. Gyroskop vždy pootočí tvar
// kreslenia na zadaný uhol (v tomto prípade 90°).
double uhol = uhol();
try
{
uhol(90.0);
return bodVObdĺžniku(iný);
}
finally
{
uhol(uhol);
}
}
@Override public void aktivita()
{
if (žiadajNovúPrekážku && polohaY() < Svet.najväčšieY() / 2)
{
žiadajNovúPrekážku = false;
// Vytvorenie novej prekážky na tomto mieste by spôsobilo zmeny
// vo vnútornom zozname robotov. Tento zoznam by nikdy nemal byť
// upravovaný v rámci „pracovných reakcií,“ preto je vytvorenie
// odložené na spracovanie v čase nečinnosti.
Svet.vykonaťNeskôr(() -> Uhýbač.nováPrekážka());
}
// (Automatická úprava veľkosti podľa vertikálnej súradnice.)
veľkosť(
(-polohaY() + Svet.najväčšieY()) * 100 /
(Svet.najväčšieY() - Svet.najmenšieY()));
}
}
~
import knižnica.*;
public class Uhýbač extends GRobot
{
private final static Zoznam<Prekážka> prekážky = new Zoznam<>();
private Uhýbač()
{
veľkosť(15);
hrúbkaČiary(10);
nováPrekážka();
}
public static void nováPrekážka()
{
// Buď nájde neaktívnu prekážku v zozname prekážok, …
for (Prekážka prekážka : prekážky)
if (prekážka.neaktívny())
{
prekážka.reset();
return;
}
// … alebo vytvorí novú.
prekážky.pridaj(new Prekážka());
}
@Override public void kresliTvar()
{
krúžok();
}
@Override public void pohybMyši()
{
skočNa(ÚdajeUdalostí.polohaMyšiX(), Svet.najmenšieY());
}
@Override public void tik()
{
for (Prekážka prekážka : prekážky)
{
if (prekážka.koliduje(this))
{
// (Kolízia s prekážkou zafarbí uhýbača načerveno.)
farba(červená);
return;
}
}
farba(čierna);
}
public static void main(String[] args)
{
Svet.použiKonfiguráciu("Uhýbač.cfg");
Svet.skry();
Svet.nekresli();
new Uhýbač();
Svet.zbaľ();
Svet.kresli();
Svet.zobraz();
}
}
Návrhy na zlepšenia
Upravte projekt tak, aby bol hráč nútený prechádzať z ľavej strany obrazovky na pravú a späť. (Napríklad striedavým pridávaním dlhých „vlajočiek“ k prekážkam zľava a sprava.)
Graficky zvýraznite kolízie uhýbača s prekážkami. (Napríklad farebným zablysnutím plochy.)
/*# (Zmeny sú označené takto.) #*/
import knižnica.*;
public class Prekážka extends GRobot
{
// Tento príznak je nastavený od štartu prekážky dovtedy, kým neklesne
// pod určitú úroveň na ploche, kedy vyžiada vznik novej prekážky
// a príznak vynuluje. (Pozri reakciu aktivita.)
private boolean žiadajNovúPrekážku/* = true*/;
/*# (Odobraná inicializácia atribútu. V podstate ju netreba, lebo ju
*# vykoná konštruktor – cez reset.) #*/
private boolean zľava; /*# (Pridaný príznak toho, z ktorej strany je „zástavka.“) #*/
public Prekážka(boolean zľava) /*# (Pridaný parameter.) #*/
{
zdvihniPero();
pomer(0.8); // (Nastavenie pomeru tvaru obĺžnika.)
gyroskop(90.0); // (O gyroskope sa píše v metóde koliduje nižšie.)
// Zrýchlenie je nastavené tak, aby pred dosiahnutím spodného
// okraja obrazovky nedosiahlo maximálnu povolenú rýchlosť (20 bodov
// za tik). Napriek tomu sa zdá, že prekážka spomaľuje, pretože mení
// svoju veľkosť podľa vertikálnej súradnice, aby vznikol dojem
// perspektívy.
zrýchlenie(0.25);
maximálnaRýchlosť(20);
reset(zľava); /*# (Pridaný argument.) #*/
}
public void reset(boolean zľava) /*# (Pridaný parameter.) #*/
{
this.zľava = zľava; /*# (Pridané .) #*/
// (Reset rýchlosti, polohy a cez aktivitu aj veľkosti.)
rýchlosť(0, false);
skočNa(0, Svet.najväčšieY());
aktivita();
// (Nastavenie nového cieľa zároveň prekážku aktivuje.)
cieľ(Svet.náhodnéReálneČíslo(Svet.najmenšieX(), Svet.najväčšieX()),
Svet.najmenšieY() * 4);
žiadajNovúPrekážku = true;
// (Presunieme prekážku na spodok kreslenia, aby pôsobila, že je za
// ostatnými, ktoré sa mezitým posunuli na obrazovke nižšie.)
naSpodok();
}
@Override public void kresliTvar()
{
/*# (Pridané uloženie veľkosti do lokálnej premennej, lebo bude
*# často používaná.) #*/
double veľkosť = veľkosť();
hrúbkaČiary(veľkosť / 8);
farba(biela);
vyplňObdĺžnik();
farba(čierna);
kresliObdĺžnik();
/*# (Pridané kreslenie „zástavky“.) #*/
if (zľava)
{
skoč(-veľkosť * pomer(), -veľkosť);
choď(-veľkosť * 6, 0);
}
else
{
skoč(veľkosť * pomer(), -veľkosť);
choď(veľkosť * 6, 0);
}
}
@Override public boolean koliduje(GRobot iný)
{
// Blok try-finally spolu s riadkom kódu pred ním slúžia na
// zálohovanie a obnovenie uhla prekážky, pretože jej uhol sa musí
// v čase detekcie kolízie rovnať 90°.
//
// Inak by detekcia bola odchýlená, pretože by porovnávala tvar
// obdĺžnikovej oblasti orientovanej v skutočnom smere prekážky.
//
// Skutočný smer prekážky sa od kresleného smeru líši, pretože
// prekážka má aktivovaný gyroskop. Gyroskop vždy pootočí tvar
// kreslenia na zadaný uhol (v tomto prípade 90°).
double uhol = uhol();
Bod poloha = poloha(); /*# (Pridané zálohovanie polohy.) #*/
try
{
uhol(90.0);
if (bodVObdĺžniku(iný)) return true; /*# (Upravené.) #*/
/*# (Pridané – detekcia kolízie so „zástavkou.“) #*/
double veľkosť = veľkosť();
if (zľava)
skoč(-veľkosť * pomer() - veľkosť * 3, -veľkosť);
else
skoč(veľkosť * pomer() + veľkosť * 3, -veľkosť);
return bodVObdĺžniku(iný, veľkosť * 3, 10);
}
finally
{
uhol(uhol);
poloha(poloha); /*# (Pridané obnovenie polohy.) #*/
}
}
@Override public void aktivita()
{
if (žiadajNovúPrekážku && polohaY() < Svet.najväčšieY() * 0.8) /*# (Úprava hustoty prekážok.) #*/
{
žiadajNovúPrekážku = false;
// Vytvorenie novej prekážky na tomto mieste by spôsobilo zmeny
// vo vnútornom zozname robotov. Tento zoznam by nikdy nemal byť
// upravovaný v rámci „pracovných reakcií,“ preto je vytvorenie
// odložené na spracovanie v čase nečinnosti.
Svet.vykonaťNeskôr(() -> Uhýbač.nováPrekážka());
}
// (Automatická úprava veľkosti podľa vertikálnej súradnice.)
veľkosť(
(-polohaY() + Svet.najväčšieY()) * 100 /
(Svet.najväčšieY() - Svet.najmenšieY()));
}
}