Stránka sa načítava, prosím čakajte…
© 2005 – 2024 Roman Horváth, všetky práva vyhradené. Dnes je 26. 4. 2024.
Dátum: 6. 8. 2020, pred štyrmi rokmi
Zadanie
Naprogramujte jednoduchú zábavnú aplikáciu, ktorá bude umožňovať pridávanie bublín, ktoré bude môcť používateľ praskať vystreľujúcimi ihlami.
Požiadavky:
- Nech má používateľ možnosť pridávať na plochu náhodne generované ihly a bubliny, pričom pri bublinách bude náhodne generovaná ich poloha a pri ihlách orientácia (smer).
- Nech sa vytvorené bubliny, ktoré kolidujú vzájomne odpudzujú, kým nenájdu prázdny priestor.
- Nech ihla, ktorá narazí do bubliny zmizne a spôsobí bubline určité poškodenie, ktoré bude používateľovi indikované zmenou farby.
- Nech po prekročení určitej úrovne poškodenia bublina praskne.
- Nech bubliny, ktoré prasknú vygenerujú nové ihly. (Čím môže vzniknúť kaskáda praskania.)
Bonusové požiadavky:
- Pridajte do aplikácie možnosť voľby počtu naraz pridávaných bublín alebo ihiel.
- Pridajte do aplikácie počítadlo bublín.
- Počítadlo môže náhodne putovať po obrazovke.
- Počítadlo môže hodnotu počtu zobrazovať formou rímskej číslice.
- Pridajte možnosť rovnomerného rozloženia pridávaných ihiel. To znamená, že napríklad tri ihly by sa od spoločnej polohy vzďaľovali so vzájomnou (rovnomernou) odchýlkou 120˚, päť ihiel 72˚ a podobne.
- Spestrite správanie bublín podľa poškodenia tak, aby sa úroveň poškodenia nemenila priamo úmerne, ale náhodne, pričom každý typ poškodenia by mal iný dôsledok. Príklad:
- Ak by všetky bubliny mali pri vytvorení rovnakú farbu (f1), táto farba by znamenala „plné zdravie“ a pri náraze ihly do takejto bubliny by sa farba vždy zmenila na inú stanovenú (f2), ktorá by znamenala „slabé poškodenie.“
- Po náraze ihly s farbou slabého poškodenia (f2) by sa farba bubliny zmenila náhodne (čiže bublina by mala šancu vrátiť sa aj do stavu plného zdravia).
- Ďalšia farba, f3, odlišná od f1 a f2 by znamenala „silné poškodenie.“ Keby ihla narazila do takejto bubliny, tá by ihneď praskla.
- Keď ihla narazí do bubliny, ktorá má ľubovoľnú farbu, okrem f1, f2 a f3, tak bublina zmení svoju farbu na f3. (Čím stratí šancu na „uzdravenie.“)
Návrhy farieb:
- Plné zdravie (f1): akvamarínová.
- Slabé poškodenie (f2): žltá.
- Silné poškodenie (f3): červená.
Riešenie
Toto riešenie má implementované všetky hlavné aj bonusové požiadavky. Je rozdelené do troch tried, pričom dve z nich (Ihla
a Bublina
) sú roboty s minimálne rozšírenou funkčnosťou.
Táto trieda v sebe obsahuje takmer kompletné riešenie projektu. Ďalšie dve triedy môžeme vnímať ako pomocné, riešiace predovšetkým vzhľadovú stránku projektu.
V tejto triede sú definované obidva zoznamy: ihiel a bublín a je tu implementovaná práca s nimi, ktorá zahŕňa napĺňanie zoznamov (tvorbu alebo obnovu ihiel a bublín), ovládanie bublín, kontrolu kolízií a podobne.
Tiež sú tu definované prvky (položky ponuky) slúžiace na požadovanú konfiguráciu: zmenu počtu naraz generovaných bublín a ihiel, prepínanie medzi rovnomerným a nerovnomerným rozložením generovaných ihiel.
Kód by nemal byť náročný na porozumenie.
~
import knižnica.*; public class IhlyABubliny extends GRobot { private final Zoznam<Ihla> ihly = new Zoznam<>(); private final Zoznam<Bublina> bubliny = new Zoznam<>(); private boolean rovnomerne = true; private int početIhiel = 7; private int pridajNaraz = 5; private int viditeľnýchBublín = 100; private final Obrázok ikonaOznačeného = new Obrázok(16, 16); private PoložkaPonuky položkaPočet; private PoložkaPonuky položkaPridaj; private PoložkaPonuky položkaRovnomerne; private IhlyABubliny() { for (int i = 0; i < viditeľnýchBublín; ++i) bubliny.pridaj(new Bublina()); for (int i = 0; i < viditeľnýchBublín * 6; ++i) { Bublina bublina = new Bublina(); bublina.skry(); bubliny.pridaj(bublina); } for (int i = 0; i < viditeľnýchBublín * 49; ++i) ihly.pridaj(new Ihla()); kresliDoObrázka(ikonaOznačeného); kruh(4); položkaPočet = Svet.pridajPoložkuPonuky( "Počet ihiel", Kláves.VK_H, Kláves.VK_N); položkaPridaj = Svet.pridajPoložkuPonuky( "Prírastok bublín", Kláves.VK_B, Kláves.VK_B); položkaRovnomerne = Svet.pridajPoložkuPonuky( "Rovnomerné rozloženie", Kláves.VK_R, Kláves.VK_M); položkaRovnomerne.ikona(ikonaOznačeného); // (Táto trieda je zároveň počítadlom bublín.) farba(šedá); písmo("Cambria", 44); zrýchlenie(0.1, false); gyroskop(90.0); zdvihniPero(); náhodnáPoloha(); náhodnýCieľ(); aktivuj(); } @Override public void voľbaPoložkyPonuky() { if (položkaPočet.aktivovaná()) { Long počet = Svet.upravCeléČíslo(početIhiel, "Počet ihiel"); if (null != počet) { if (počet <= 0) početIhiel = 1; else if (počet > 14) početIhiel = 14; else početIhiel = počet.intValue(); } } else if (položkaPridaj.aktivovaná()) { Long počet = Svet.upravCeléČíslo(pridajNaraz, "Prírastok bublín"); if (null != počet) { if (počet <= 0) pridajNaraz = 1; else if (počet > 100) pridajNaraz = 100; else pridajNaraz = počet.intValue(); } } else if (položkaRovnomerne.aktivovaná()) { rovnomerne = !rovnomerne; if (rovnomerne) položkaRovnomerne.ikona(ikonaOznačeného); else položkaRovnomerne.ikona((Obrázok)null); Svet.pípni(); } } public void náhodnýCieľ() { // (Robot počítadla sa pohybuje náhodne.) cieľ( Svet.náhodnéCeléČíslo( (long)Svet.najmenšieX(), (long)Svet.najväčšieX()), Svet.náhodnéCeléČíslo( (long)Svet.najmenšieY(), (long)Svet.najväčšieY())); } private void pridajBubliny() { // Poznámka: Menovka „ďalší“ umožňuje prerušenie viacerých úrovní // riadiacich štruktúr (cyklov). Bez menovky by sme museli používať // pomocnú premennú alebo rozdeliť algoritmus do dvoch metód ako to // je pri aktivácii ihiel. ďalší: for (int i = 0; i < pridajNaraz; ++i) { for (Bublina bublina : bubliny) if (bublina.skrytý()) { // (Farba bubliny určuje mieru/typ poškodenia.) bublina.farba(akvamarínová); bublina.náhodnáPoloha(); bublina.zobraz(); continue ďalší; } bubliny.pridaj(new Bublina()); } } private void aktivujIhlu(Poloha p, Smer s) { for (Ihla ihla : ihly) if (ihla.neaktívny()) { ihla.poloha(p); ihla.smer(s); ihla.aktivuj(); return; } Ihla ihla = new Ihla(); ihly.pridaj(ihla); ihla.poloha(p); ihla.smer(s); ihla.aktivuj(); } private void aktivujIhly(Poloha p) { double pôvodnýUhol = 360.0 / početIhiel; double pootočenie = Svet.náhodnéReálneČíslo(pôvodnýUhol); if (rovnomerne) { for (int i = 0; i < početIhiel; ++i) aktivujIhlu(p, new Uhol(pôvodnýUhol * i + pootočenie)); } else { // Ani pri vypnutej voľbe rovnomerného rozloženia nie je // orientácia ihiel úplne náhodná. Pohybuje sa v škále násobkov // uhlov rovnomerného rozloženia. (To znamená, že niektoré ihly // sa budú prekrývať.) for (int j = 0; j < početIhiel; ++j) { int i = (int)Svet.náhodnéCeléČíslo(početIhiel); aktivujIhlu(p, new Uhol(pôvodnýUhol * i + pootočenie)); } } } @Override public void kresliTvar() { // (Táto trieda je zároveň počítadlom bublín.) text(Svet.celéNaRímske(viditeľnýchBublín)); } @Override public void zastavenie() { // (Robot počítadla sa pohybuje náhodne.) náhodnýCieľ(); } @Override public void tik() { viditeľnýchBublín = 0; for (Bublina bublina : bubliny) { if (bublina.viditeľný()) { ++viditeľnýchBublín; for (Ihla ihla : ihly) if (ihla.aktívny() && ihla.koliduje(bublina)) { ihla.deaktivuj(); // (Farba bubliny určuje mieru/typ poškodenia.) if (akvamarínová == bublina.farba()) { bublina.farba(žltá); } else if (žltá == bublina.farba()) { bublina.náhodnáFarba(); } else if (červená == bublina.farba()) { --viditeľnýchBublín; bublina.skry(); aktivujIhly(bublina); } else { bublina.farba(červená); } break; } } if (bublina.viditeľný() && bublina.neaktívny()) { for (Bublina bublina2 : bubliny) { if (bublina != bublina2 && bublina2.viditeľný() && bublina2.neaktívny() && bublina2.koliduje(bublina)) { // (Odpudzovanie bublín.) Svet.nekresli(); Poloha p; double posun; bublina2.otočNa(bublina); bublina2.vpravo(180); posun = 4 + bublina.veľkosť() / 2; bublina2.skoč(posun); p = bublina2.poloha(); bublina2.odskoč(posun); bublina2.cieľ(p); bublina.otočNa(bublina2); bublina.vpravo(180); posun = 4 + bublina2.veľkosť() / 2; bublina.skoč(posun); p = bublina.poloha(); bublina.odskoč(posun); bublina.cieľ(p); Svet.kresli(); break; } } } } } @Override public void klik() { if (ÚdajeUdalostí.tlačidloMyši(PRAVÉ)) pridajBubliny(); else aktivujIhly(ÚdajeUdalostí.polohaMyši()); } public static void main(String[] args) { Svet.skry(); Svet.nekresli(); Svet.použiKonfiguráciu("IhlyABubliny.cfg"); new IhlyABubliny(); Svet.zbaľ(); Svet.kresli(); Svet.zobraz(); } }
Bublina » |
Táto trieda je veľmi jednoduchá. Jej úlohou je iba kresliť svoj tvar – tvar bubliny (ktorý má tvar kružnice so štvrťoblúkom vo vnútri).
~
import knižnica.*; public class Bublina extends GRobot { public Bublina() { ohranič(PLOT); veľkosť(20); farba(akvamarínová); hrúbkaČiary(1); náhodnáPoloha(); zrýchlenie(0.1, false); maximálnaRýchlosť(2); gyroskop(90.0); zdvihniPero(); } @Override public void kresliTvar() { krúžok(); preskočVľavo(veľkosť() * 0.66); choďPoOblúku(90, veľkosť() * -0.66); } }
« Ihly a bubliny | Ihla » |
Úlohou tejto triedy je kresliť svoj tvar – tvar ihly (ktorý má formu skokovo sa stenčujúcej čiary), deaktivovať sa po opustení plátna a automaticky sa zobrazovať alebo skrývať podľa stavu aktivity.
~
import knižnica.*; public class Ihla extends GRobot { public Ihla() { ohranič(); veľkosť(20); farba(tmavotyrkysová); zdvihniPero(); rýchlosť(15, false); skry(); } @Override public void kresliTvar() { double hrúbka = veľkosť() / 5; double dĺžka = veľkosť() / 2; odskoč(); for (int i = 0; i < 4; ++i) { if (hrúbka > 0) hrúbkaČiary(hrúbka); else hrúbkaČiary(0.5); hrúbka -= 1.0; vpred(dĺžka); } } @Override public void mimoHraníc() { deaktivuj(); } @Override public void aktivácia() { zobraz(); } @Override public void deaktivácia() { skry(); } }
« Bublina |
Výsledok
Ukážka vzhľadu aplikácie.
Návrhy na zlepšenia
- Vzájomné vzďaľovanie sa kolidujúcich bublín by mohlo byť spresnené tak, aby bubliny skončili v tesnej vzdialenosti od seba (takmer sa dotýkajúc – tak, aby ich vzájomná poloha nebola viac vyhodnocovaná ako kolízia).
- Aktuálny spôsob kreslenia tvaru ihly je najjednoduchším rýchlym riešením. Dal by sa vyriešiť aj iným spôsobom, napríklad vyplneným dlhým tenkým trojuholníkom s oblúkom namiesto najkratšej strany.