TlačiťTlačiť Slovenčina English Hľadať RSS

© 2005 – 2024 Roman Horváth, všetky práva vyhradené. Dnes je 26. 4. 2024.

Stránka sa načítava, prosím čakajte…

Dátum: 9. 8. 2020, pred štyrmi rokmi

Hra Lovec ponoriek je o námornej lodi, ktorá má cieľ zlikvidovať nepriateľské ponorky s pomocou sudov s náložami.

Obrana a útok: Sudy s náložami nemajú časovač a vybuchujú pri kontakte s ponorkou – v plochom vertikálne orientovanom dvojrozmernom priestore. Oceán nemá dno a sudy po opustení hracej plochy zanikajú. Ponorky majú možnosť sa brániť vypúšťaním torpéd. Princíp výbuchu je rovnaký ako pri sudoch s náložami – kontakt torpéda s loďou znamená vznik explózie a poškodenie lode (prípadne jej zničenie – pozri úroveň zdravia a opravy nižšie).

Pohyb: Loď sa môže (logicky) pohybovať iba na hladine a môže v rámci dovoleného priestoru manévrovať doľava a doprava. Ponorky sa pohybujú len jedným smerom konštantnou rýchlosťou. Niektoré smerom doľava, niektoré doprava. Keď ponorka úplne opustí pravý alebo ľavý okraj hracej plochy, začne opätovne prichádzať z protiľahlého okraja plochy. Sudy sa tesne po vyhodení z lode pohybujú po malej parabole a po náraze na hladinu rovnomerne pomaly sa otáčajúc klesajú. Torpéda tesne po vypustení rýchlo zrýchlia na

Úroveň zdravia a opravy: Loď aj ponorky majú určitú úroveň zdravia, ktorá je graficky zobrazená tesne nad nimi. Explózia suda pri náraze na ponorku alebo torpéda pri náraze na loď znamená poškodenie cieľa alebo jeho zničenie pri poklese úrovne zdravia na nulu. Poškodená loď alebo ponorka sa po určitom čase od poslednej explózie, ktorá ju poškodila začne samovoľne opravovať. Pomalý proces opráv nie je ničím obmedzený. Každá ponorka aj loď môže opäť nadobudnúť plnú úroveň zdravia.

Výhra, prehra, remíza: Činnosť prvkov v hre sa nezastavuje ani po skončení hry. Sudy klesajú, kým neopustia hraciu plochu a torpéda stúpajú, kým nenarazia na hladinu. Keď sú zničené všetky ponorky, loď začne rýchlo spomaľovať, kým sa nezastaví (zabrzdí) a nedá sa ďalej ovládať. Okolo lode sa zdvihne obranný štít, ktorý zabráni prípadným torpédam v pohybe, aby ju dodatočne poškodili. Tento stav sa chápe ako výhra. Keď je zničená loď, znamená to vo väčšine prípadov prehru. Keďže však činnosť hry pokračuje, prípadné sudy klesajú a ponorky pokračujú vo svojom rovnomernom pohybe, vzniká malá šanca, že zostávajúce sudy zničia zostávajúce ponorky a tento stav je chápaný ako remíza.

Grafika: Grafická stránka tejto verzie je minimalistická. Každý prvok prečíta svoj tvar z SVG súboru a vyplní ho jednou farbou alebo farebným prechodom (výnimočne je použité aj reslenie obrysu tvaru). Niektoré objekty používajú rotáciu alebo zrkadlenie. SVG súbory sú k dispozícii v balíčku na prevzatie (nižšie; spolu so zdrojovými súbormi tried). Vyzerajú takto:

obrázok

Tvar lode je výsledkom prispôsobenia tohto súboru: User:GDJ. otvárané v novom okne
(obvykle ide o externý odkaz) Cruise Ship Silhouette. otvárané v novom okne
(obvykle ide o externý odkaz) Openclipart, 2018. (Naposledy pristúpené: 13. 8. 2020.)

Tvar ponorky bol vyňatý z tejto montáže: User:Firkin. otvárané v novom okne
(obvykle ide o externý odkaz) Bomb pattern. otvárané v novom okne
(obvykle ide o externý odkaz) Openclipart, 2016. (Naposledy pristúpené: 13. 8. 2020.)

Sud bol vytvorený nanovo, ale bol inšpirovaný týmto obrázkom: User:Alastair. otvárané v novom okne
(obvykle ide o externý odkaz) Oil barrel. otvárané v novom okne
(obvykle ide o externý odkaz) Openclipart, 2013. (Naposledy pristúpené: 13. 8. 2020.)

Výbuch bol tiež vytvorený nanovo a bol inšpirovaný týmto obrázkom: User:dominiquechappard. otvárané v novom okne
(obvykle ide o externý odkaz) Explosion. otvárané v novom okne
(obvykle ide o externý odkaz) Openclipart, 2010. (Naposledy pristúpené: 13. 8. 2020.)

Ostatné obrázky boli vytvorené bez zdrojov inšpirácie.

(Podrobnosti implementácie sú reprezentované komentovanými zdrojovými kódmi nižšie.)

  
obrázok 
Ukážka hry. 
  
ikonaZdrojové súbory projektu s SVG obrázkami na prevzatie. 14,31 kB (13,98 KiB), 12. 8. 2020 
 

Trieda lode (lovca ponoriek) je zároveň hlavnou triedou. Trieda Predloha je rodičom všetkých ostatných tried projektu (vrátane triedy lovca ponoriek).

 

~

import knižnica.*;

// Triedy Detonácia a Výbuch implementujú grafické reprezentácie dvoch
// rôznych explozívnych udalostí. Detonácia je použitá na znázornenie
// „jalového“ výbuchu torpéda na hladine (čiže, keď minie cieľ).
public class Detonácia extends Predloha
{
	// Oblasť s tvarom detonácie:
	private final static Oblasť tvarDetonácie = čítajSVGTvar("detonacia.svg");

	// Inštancia kreslenia spoločná pre všetky detonácie.
	private final static KreslenieTvaru kreslenieDetonácie =
		r -> r.vyplňOblasť(tvarDetonácie);


	// Konštruktor.
	public Detonácia()
	{
		super(kreslenieDetonácie);
		farba(snehová);
		veľkosť(15);
		mierka(1);
		cieľováFarba(svetlošedá);
		použiKruhovýNáter();
	}


	// Reakcie na udalosti:

	@Override public void aktivita()
	{
		// (Zväčšovanie sa detonácie až do jej zániku.)
		vpred(1);
		veľkosť(veľkosť() + 2.5);
		if (veľkosť() > 40) deaktivuj();
	}

	@Override public void aktivácia()
	{
		// (Reset detonácie.)
		veľkosť(5);
		super.aktivácia();
	}
}
  Lovec ponoriek »

~

import knižnica.*;

public class LovecPonoriek extends Predloha
{
	// Tieto konštanty sú použité pri ovládaní vyhadzovania jednotlivých
	// sudov (doprava alebo doľava):
	private final static String vyhoďVľavo = "vyhoďVľavo";
	private final static String vyhoďVpravo = "vyhoďVpravo";

	// Oblasť s tvarom lode:
	private final static Oblasť tvarLovca = čítajSVGTvar("lovec-ponoriek.svg");


	// Zoznamy ostatných objektov v hre:
	private final Zoznam<Ponorka> ponorky = new Zoznam<>();
	private final Zoznam<Sud> sudy = new Zoznam<>();
	private final Zoznam<Torpédo> torpéda = new Zoznam<>();
	private final Zoznam<Výbuch> výbuchy = new Zoznam<>();

	// Atribút slúžiaci na uchovanie položky ponuky „Nová hra.“
	private final PoložkaPonuky nováHra;

	// Atribúty energie a intervalu opráv lode:
	private int energia = 65;
	private int intervalOpravy = 0;

	// Interval útokov ponoriek:
	private int intervalTorpéd = 0;

	// Príznak úspešného ukončenia hry:
	private boolean výhra = false;


	// Kreslenie lode.
	private void kresliLovca()
	{
		if (výhra)
		{
			// (Po úspešnom ukončení hry je loď obkreslená bielou čiarou.
			// Tá má symbolizovať akúsi ochrannú žiaru, ktorá má signalizovať
			// to, že lodi už nič nemôže ublížiť. To jest, najmä prípadné
			// torpéda v pohybe.)

			hrúbkaČiary(2.5);
			farba(papierová);
			obkresliOblasť(tvarLovca);

			farba(antracitová);
			vyplňOblasť(tvarLovca);
		}
		else
		{
			// (V klasickom režime hrania je nad loďou nakreslený prúžok
			// signalizujúci úroveň zdravia/poškodenia lode.)

			vyplňOblasť(tvarLovca);

			if (energia < 16) farba(svetločervená);
			else if (energia < 32) farba(tmavožltá);
			else farba(svetlozelená);

			skoč(energia - 65, 17);
			vyplňObdĺžnik(energia, 2);
			skoč(65 - energia, 0);

			farba(čierna);
			kresliObdĺžnik(65, 2);
		}
	}


	// Konštruktor.
	private LovecPonoriek()
	{
		// (Loď je len jedna, preto bolo zbytočné definovať statickú
		// inštanciu kreslenia lode, ako to je pri ostatných triedach.)
		super(r -> ((LovecPonoriek)r).kresliLovca());

		// Nakreslenie prostredia:
		farba(tmavotyrkysová);
		odskoč(30);
		vyplňObdĺžnik(400, 270);
		skoč(30);
		Svet.farbaPozadia(tmavooranžová);

		// Úprava vlastností lode:
		veľkosť(16.5);
		mierka(1);

		ohranič(Svet.najväčšieX() - 60, Svet.najväčšieY(), PLOT);
		skoč(250);

		farba(antracitová);
		maximálnaRýchlosťPosunu(2.5);

		// Inicializácia objektov hry:
		for (int i = 0; i < 9; ++i)
			ponorky.pridaj(new Ponorka());

		for (int i = 0; i < 12; ++i)
			sudy.pridaj(new Sud());

		for (int i = 0; i < 12; ++i)
			torpéda.pridaj(new Torpédo());

		for (int i = 0; i < 30; ++i)
			výbuchy.pridaj(new Výbuch());

		// Pridanie klávesových skratiek na ovládanie vyhadzovania sudov
		// jednotlivo doprava alebo doľava a pridanie položky ponuky na
		// spustenie novej hry:
		Svet.pridajKlávesovúSkratku(vyhoďVľavo, Kláves.VĽAVO);
		Svet.pridajKlávesovúSkratku(vyhoďVpravo, Kláves.VPRAVO);
		nováHra = Svet.pridajPoložkuPonuky("Nová hra",
			Kláves.VK_N, Kláves.VK_N);

		// Aktivácia ponoriek a zobrazenie lode (ktorá bola automaticky
		// skrytá konštruktorom predlohy):
		for (Ponorka ponorka : ponorky) ponorka.aktivuj();
		zobraz();
	}


	// Metóda spúšťajúca novú hru.
	private void nováHra()
	{
		výhra = false;
		deaktivuj(); resetuj();
		for (Sud sud : sudy) sud.deaktivuj();
		for (Torpédo torpédo : torpéda) torpédo.deaktivuj();
		for (Ponorka ponorka : ponorky) ponorka.deaktivuj();
		for (Ponorka ponorka : ponorky) ponorka.aktivuj();
	}

	// Metóda volaná vždy pri výhre. Okrem nastavenia príznaku výhry spomalí
	// loď, ktorá so zotrvačnosťou spontánne zastaví.
	private void výhra()
	{
		výhra = true;

		zastavPoSpomaleníPosunu();
		if (rýchlosťPosunu() < 0 && zrýchleniePosunu() < 0)
			zrýchleniePosunu(-zrýchleniePosunu());
		else if (rýchlosťPosunu() > 0 && zrýchleniePosunu() > 0)
			zrýchleniePosunu(-zrýchleniePosunu());
	}

	// Metóda obnovujúca nastavenia lode. (Je volaná pri spúšťaní novej hry.)
	public void resetuj()
	{
		energia = 65;
		intervalOpravy = 0;
		intervalTorpéd = 0;
		polohaX(0);
		rýchlosťPosunu(0);
		zobraz();
	}

	// Metóda udeľujúca poškodenie lodi. Ak je poškodenie veľké, loď je
	// zničená. Návratová hodnota true je signálom zničenia lode.
	public boolean poškoď(int úroveň)
	{
		if (úroveň >= energia)
		{
			energia = 0;
			intervalOpravy = 0;
			deaktivuj();
			return true;
		}

		energia -= úroveň;
		intervalOpravy = 200;
			// (Po zásahu chvíľu trvá, kým sa personál „spamätá.“)
		return false;
	}

	// Metóda vyhadzujúca sud doľava, ak je ešte nejaký sud k dispozícii.
	//
	// (Zoznam sudov je nemeniaci sa zásobník sudov. Vždy je vyhodený prvý
	// neaktívny sud, pričom sudy sú deaktivované automaticky alebo ručne
	// v rôznych situáciách počas hry.)
	private void vyhoďVľavo()
	{
		for (Sud sud : sudy)
			if (sud.neaktívny())
			{
				sud.polohaX(polohaX() - 60);
				sud.aktivujVľavo();
				break;
			}
	}

	// Metóda vyhadzujúca sud doprava – platí to isté, čo je napísané vyššie
	// pri metóde vyhoďVľavo.
	private void vyhoďVpravo()
	{
		for (Sud sud : sudy)
			if (sud.neaktívny())
			{
				sud.polohaX(polohaX() + 60);
				sud.aktivujVpravo();
				break;
			}
	}

	// Aktivuje výbuch na zadanej polohe. V konštruktore je stabilne
	// vytvorených 30 výbuchov. Predpokladá sa, že viac ich nebude treba.
	// Výbuch je však len grafickým efektom. Skutočné poškodenie cieľového
	// objektu sa deje inak (popri aktivácii tohto efektu).
	private void výbuch(Poloha poloha)
	{
		for (Výbuch výbuch : výbuchy)
			if (výbuch.neaktívny())
			{
				výbuch.skočNa(poloha);
				výbuch.aktivuj(10);
				break;
			}
	}


	// Reakcie na udalosti:

	@Override public void voľbaPoložkyPonuky()
	{
		if (nováHra.aktivovaná() && (výhra || energia <= 0 || ÁNO ==
			Svet.otázka("Želáte si začať novú hru?"))) nováHra();
	}

	@Override public void klávesováSkratka()
	{
		// (Reakcia sa vykoná len v prípade, že hra prebieha.)
		if (!výhra && energia > 0)
		{
			String skratka = ÚdajeUdalostí.príkazSkratky();
			// (Vyhadzovanie jednotlivých sudov doprava/doľava.)
			if (skratka == vyhoďVľavo) vyhoďVľavo();
			else if (skratka == vyhoďVpravo) vyhoďVpravo();
		}
	}

	@Override public void stlačenieKlávesu()
	{
		// (Reakcia sa vykoná len v prípade, že hra prebieha.)
		if (!výhra && energia > 0) switch (ÚdajeUdalostí.kláves())
		{
		case Kláves.VPRAVO:
			nezastavujPoSpomaleníPosunu();

			if (zrýchleniePosunu() < 0)
				zrýchleniePosunu(-zrýchleniePosunu());
			else
				zrýchleniePosunu(0.1);

			break;

		case Kláves.VĽAVO:
			nezastavujPoSpomaleníPosunu();

			if (zrýchleniePosunu() > 0)
				zrýchleniePosunu(-zrýchleniePosunu());
			else
				zrýchleniePosunu(-0.1);

			break;
		}
	}

	@Override public void uvoľnenieKlávesu()
	{
		// (Reakcia sa vykoná len v prípade, že hra prebieha.)
		if (!výhra && energia > 0) switch (ÚdajeUdalostí.kláves())
		{
		case Kláves.VPRAVO:
		case Kláves.VĽAVO:
			zastavPoSpomaleníPosunu();

			if (rýchlosťPosunu() < 0 && zrýchleniePosunu() < 0)
				zrýchleniePosunu(-zrýchleniePosunu());
			else if (rýchlosťPosunu() > 0 && zrýchleniePosunu() > 0)
				zrýchleniePosunu(-zrýchleniePosunu());

			break;

		case Kláves.VK_H:
			Svet.zastavČasovač();
			break;

		case Kláves.MEDZERA:
			vyhoďVľavo(); vyhoďVpravo();
			break;
		}
	}

	@Override public void tik()
	{
		// Ukončí reakciu, ak sa hra skončila výhrou.
		if (výhra) return;

		// Overí, či nastala výhra.
		boolean výhra = true;
		for (Ponorka ponorka : ponorky)
			if (ponorka.aktívny())
			{
				výhra = false;
				break;
			}

		// Ukončí reakciu, ak sa práve zistilo, že nastala výhra.
		if (výhra)
		{
			výhra();
			return;
		}

		// Overenie kolízií sudov s ponorkami.
		for (Sud sud : sudy) if (sud.aktívny())
		{
			for (Ponorka ponorka : ponorky) if (ponorka.aktívny() &&
				ponorka.bodVElipse(sud, 6.5))
			{
				sud.deaktivuj();
				výbuch(sud);

				if (ponorka.poškoď(13))
				{
					// (Ak metóda poškoď vráti true, znamená to,
					// že ponorka bola zničená.)
					výbuch(ponorka);
					ponorka.preskočVľavo(33);
					výbuch(ponorka);
					ponorka.preskočVpravo(66);
					výbuch(ponorka);
				}
				break;
			}
		}

		// Zabezpečenie fungovania nepotopenej lode (vykonanie opráv,
		// overenie kolízií s torpédami, ale aj zabezpečenie vypúšťania
		// torpéd ponorkami v určitých časových intervaloch).
		if (energia > 0)
		{
			if (energia < 65)
			{
				if (intervalOpravy > 0) --intervalOpravy; else
				{
					intervalOpravy = 30;
					++energia;
				}
			}

			for (Torpédo torpédo : torpéda)
				if (torpédo.aktívny() && bodVElipse(torpédo, 3.7))
				{
					torpédo.deaktivuj();
					výbuch(torpédo);

					if (poškoď(13))
					{
						// (Ak metóda poškoď vráti true, znamená to,
						// že loď bola zničená.)
						výbuch(this);
						preskočVľavo(33);
						výbuch(this);
						preskočVpravo(66);
						výbuch(this);
					}
				}

			if (intervalTorpéd > 0) --intervalTorpéd; else
			{
				for (Ponorka ponorka : ponorky) if (ponorka.aktívny() &&
					Math.abs(polohaX() - ponorka.polohaX()) < 60)
					for (Torpédo torpédo : torpéda)
						if (torpédo.neaktívny())
						{
							torpédo.skočNa(ponorka);
							torpédo.aktivuj();
							intervalTorpéd = 300;
							break;
						}
			}
		}
	}

	@Override public void aktivácia()
	{
		// Vypnutie predvoleného správania tohto objektu
		// (ktoré je odvodené od predlohy):
		//
		// super.aktivácia();
	}


	// Hlavná metóda. (Vstupný bod programu. Prijíma, ale v našom prípade
	// nespracúva, zoznam argumentov z konzoly, ktorá aplikáciu spúšťa.)
	public static void main(String[] args)
	{
		Svet.skry();
		Svet.použiKonfiguráciu("LovecPonoriek.cfg");
		Svet.nekresli();
		new LovecPonoriek();
		Svet.kresli();
		if (Svet.prvéSpustenie()) Svet.zbaľ();
		Svet.zobraz();
	}
}
« Detonácia Ponorka »

~

import knižnica.*;

public class Ponorka extends Predloha
{
	// Oblasti s tvarmi ponorky orientovanej doprava a doľava:
	private final static Oblasť smerVpravo;
	private final static Oblasť smerVľavo;

	static
	{
		// Inicializácia oblastí:
		smerVpravo = čítajSVGTvar("ponorka.svg");
		smerVľavo = zrkadliPoslednýSVGTvar();
	}

	// Inštancia kreslenia spoločná pre všetky ponorky:
	private final static KreslenieTvaru kresleniePonorky =
		r -> ((Ponorka)r).kresliPonorku();

	// Atribúty energie a intervalu opráv ponorky:
	private int energia = 65;
	private int intervalOpravy = 0;


	// Kreslenie ponorky.
	private void kresliPonorku()
	{
		// (Nakreslí vyplnený tvar ponorky v správnom smere a nad ňou prúžok
		// signalizujúci úroveň jej zdravia/poškodenia.)

		if (rýchlosťPosunu() >= 0)
			vyplňOblasť(smerVpravo);
		else
			vyplňOblasť(smerVľavo);

		if (energia < 16) farba(svetločervená);
		else if (energia < 32) farba(tmavožltá);
		else farba(svetlozelená);

		skoč(energia - 65, 17);
		vyplňObdĺžnik(energia, 2);
		skoč(65 - energia, 0);

		farba(čierna);
		kresliObdĺžnik(65, 2);
	}


	// Konštruktor.
	public Ponorka()
	{
		super(kresleniePonorky);
		farba(tmavošedá.tmavšia(0.5));
		ohranič(Svet.najväčšieX() + 65, Svet.najväčšieY());
	}


	// Metóda udeľujúca ponorke zadanú úroveň poškodenia. Ak je poškodenie
	// veľké, tak je ponorka zničená, čo metóda signalizuje návratovou
	// hodnotou true.
	public boolean poškoď(int úroveň)
	{
		if (úroveň >= energia)
		{
			deaktivuj();
			return true;
		}

		energia -= úroveň;
		intervalOpravy = 200;
		return false;
	}


	// Reakcie na udalosti:

	@Override public void aktivita()
	{
		if (energia < 65)
		{
			// (Iba sa sleduje interval opráv a podľa toho sa ponorka
			// opravuje.)
			if (intervalOpravy > 0) --intervalOpravy; else
			{
				intervalOpravy = 50;
				++energia;
			}
		}
	}

	@Override public void aktivácia()
	{
		// (Inicializácia novej alebo obnovenej ponorky.)
		energia = 65;
		intervalOpravy = 0;

		náhodnáPoloha();
		if (polohaY() > 200) polohaY(200);

		rýchlosťPosunu(Svet.náhodnéReálneČíslo(0.75, 1.25), false);
		if (0 == Svet.náhodnéCeléČíslo(0, 1))
			rýchlosťPosunu(-rýchlosťPosunu(), false);

		super.aktivácia();
	}
}
« Lovec ponoriek Predloha »

~

import knižnica.*;

// V tejto triede je zoskupených zopár záležitostí spoločných pre ostatné
// triedy tohto projektu.
public class Predloha extends GRobot
{
	// Statická metóda, ktorá prečíta SVG súbor so zadaným názvom a vráti
	// prvý nájdený tvar prevedený na oblasť.
	public static Oblasť čítajSVGTvar(String svgSúbor)
	{
		try
		{
			// Vyčistí inštanciu SVG podpory (pretože je používaná
			// opakovane) a prečíta SVG súbor so zadaným názvom:
			svgPodpora.vymaž();
			svgPodpora.čítaj(svgSúbor);

			// Vytvorí novú oblasť z prvého
			// tvaru prečítaného z SVG súboru:
			return new Oblasť(
				SVGPodpora.presuňDoStredu(
					svgPodpora.dajVýsledný(0)));
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}

		return null;
	}

	// Doplňujúca statická metóda, ktorej volanie musí nasledovať až po
	// volaní predchádzajúcej metódy. Táto metóda vráti oblasť so zrkadlovo
	// otočeným obrazom rovnakého tvaru, s ktorým pracuje metóda vyššie.
	public static Oblasť zrkadliPoslednýSVGTvar()
	{
		// Pridá k prvému SVG tvaru (z naposledy prečítaného súboru)
		// transformáciu zrkadlenia podľa osi y (čo zodpovedá jednotkovej
		// zápornej zmene mierky podľa x-ovej súradnice):
		svgPodpora.pridajTransformácie(0, "scaleX(-1)");

		// Vytvorí novú oblasť z upraveného tvaru:
		return new Oblasť(
			SVGPodpora.presuňDoStredu(
				svgPodpora.dajVýsledný(0)));
	}


	// Konštruktor obsahujúcich tie prvky, ktoré sú spoločné pre všetky
	// objekty tohto projektu.
	public Predloha(KreslenieTvaru vlastnýTvar)
	{
		skry();
		zdvihniPero();
		vlastnýTvar(vlastnýTvar);
	}


	// Spoločné správanie pre všetky triedy odvodené od tejto predlohy –
	// automatické skrytie pri deaktivácii a naopak.
	@Override public void aktivácia() { zobraz(); }
	@Override public void deaktivácia() { skry(); }
}
« Ponorka Sud »

~

import knižnica.*;

public class Sud extends Predloha
{
	// Oblasť s tvarom sudu:
	private final static Oblasť tvarSudu = čítajSVGTvar("sud.svg");

	// Inštancia kreslenia spoločná pre všetky sudy:
	private final static KreslenieTvaru kreslenieSudu =
		r -> r.vyplňOblasť(tvarSudu);


	private boolean nadHladinou = false;
	private final Vyšplechnutie vyšplechnutie = new Vyšplechnutie();


	// Konštruktor.
	public Sud()
	{
		super(kreslenieSudu);
		farba(tmavošedá.tmavšia(0.5));
		ohranič(Svet.najväčšieX() + 65, Svet.najväčšieY() + 10);
	}


	public void aktivujVpravo()
	{
		nadHladinou = true;
		otáčajTvar(-3.0, false);
		rýchlosťPosunu(3, false);
		zrýchleniePosunu(-0.05, false);
		aktivuj();
	}

	public void aktivujVľavo()
	{
		nadHladinou = true;
		otáčajTvar(3.0, false);
		rýchlosťPosunu(-3, false);
		zrýchleniePosunu(0.05, false);
		aktivuj();
	}


	// Reakcie na udalosti:

	@Override public void aktivita()
	{
		if (rýchlosťPosunu() >= -0.5 && rýchlosťPosunu() <= 0.5)
		{
			// (Automaticky zastaví horizontálny posun po poklese rýchlosti
			// posunu pod určitú hranicu – po tomto poklese sud padá priamo
			// nadol.)
			zrýchleniePosunu(0, false);
			rýchlosťPosunu(0, false);
		}

		// (Sleduje náraz na hladinu.)
		if (nadHladinou && polohaY() < 240)
		{
			// (Spustí animáciu vyšplechnutia po náraze na hladinu.)
			vyšplechnutie.skočNa(this);
			vyšplechnutie.aktivuj(15);
			nadHladinou = false;

			// (Pod hladinou sa sud otáča pomalšie a klesá rovnomernou
			// rýchlosťou.)
			if (otáčanieTvaru() > 180)
				otáčajTvar(-0.5, false);
			else if (otáčanieTvaru() < 180)
				otáčajTvar(0.5, false);
			zrýchlenie(0, false);
			rýchlosť(-2, false);
		}
	}

	@Override public void aktivácia()
	{
		// (Nastaví čerstvo vyhodený sud. Počiatočná rýchlosť je kladná –
		// sud tesne po vyhodení stúpa, ale zrýchlenie je záporné, čo spolu
		// s posunom zabezpečí parabolický pohyb až do nárazu na hladinu.)
		polohaY(250);
		pootočenieTvaru(0);
		rýchlosť(3, false);
		zrýchlenie(-0.2, false);
		super.aktivácia();
	}

	@Override public void mimoHraníc()
	{
		// (Sud, ktorý opustí hranice sa automaticky deaktivuje.)
		deaktivuj();
	}
}
« Predloha Torpédo »

~

import knižnica.*;

public class Torpédo extends Predloha
{
	// Oblasť s tvarom torpéda:
	private final static Oblasť tvarTorpéda = čítajSVGTvar("torpedo.svg");

	// Inštancia kreslenia spoločná pre všetky torpéda:
	private final static KreslenieTvaru kreslenieTorpéda =
		r -> ((Torpédo)r).kresliTorpédo();


	// Kreslenie torpéda.
	private void kresliTorpédo()
	{
		// (Okrem vyplnenia oblasti sa na súradniciach torpéda nakreslí
		// biela bodka, aby bolo torpédo lepšie viditeľné. Toto zlepšenie
		// bolo vykonané po krátkom testovaní.)
		vyplňOblasť(tvarTorpéda);
		farba(snehová); kruh(2);
	}

	// Súkromná detonácia tohto torpéda. Aktivuje sa po opustení oblasti
	// vymedzených hraníc torpéda.
	private final Detonácia detonácia = new Detonácia();


	// Konštruktor.
	public Torpédo()
	{
		super(kreslenieTorpéda);
		farba(tmavošedá.tmavšia(0.5));
		odskoč(25);
		ohranič(Svet.najväčšieX() + 65, Svet.najväčšieY() - 25);
		maximálnaRýchlosť(5);
	}


	// Reakcie na udalosti:

	@Override public void aktivácia()
	{
		// (Reset torpéda.)
		rýchlosť(0, false);
		zrýchlenie(0.1, false);
		super.aktivácia();
	}

	@Override public void mimoHraníc()
	{
		// (Deaktivuje torpédo a aktivuje jeho detonáciu.)
		deaktivuj();
		detonácia.skočNa(this);
		detonácia.polohaY(240);
		detonácia.aktivuj();
	}
}
« Sud Vyšplechnutie »

~

import knižnica.*;

public class Vyšplechnutie extends Predloha
{
	// Pomocná trieda Kvapka rieši primitívnu fyziku jednej kvapky
	// vyšplechnutia. Je odvodená od častice, ktorá má preddefinované
	// atribúty x, y a uhol. Dvojica atribútov [x; y] tvorí polohový
	// vektor kvapky. Pridaný je vektory rýchlosti [vx; vy] a [ax; ay]
	// by bol vektorom zrýchlenia, keby ax nebolo permanentne nulové,
	// preto nie je použité.
	//
	// V aktivite sa prepočítava uhol (smer) kvapky podľa aktuálneho
	// vektora rýchlosti. Hneď potom nasledujú jednoduché výpočty riešiace
	// fyziku pohybu. Z fyzikálneho pohľadu je polohový vektor aktualizovaný
	// podľa vektora rýchlosti a vektor rýchlosti je zase aktualizovaný
	// vektorom zrýchlenia. Z algoritmického hľadiska ide o tri (keby ax
	// nebolo nulové, boli by štyri) jednoduché súčty.
	private static class Kvapka extends Častica
	{
		public double vx = 0.0, vy = 3.0, ay = -0.5;

		public void reset(Poloha p, double vx)
		{
			poloha(p);
			uhol = 90;
			this.vx = vx;
			vy = 3.0;
		}

		@Override public void aktivita()
		{
			uhol = Svet.uhol(vx, vy);
			x += vx;
			y += vy;
			vy += ay;
		}
	}


	// Definície súvisiace s grafikou kvapiek. (Kvapky smerujúcie doprava
	// sú zrkadlovo prevrátené.)


	// Oblasti s tvarmi kvapky orientovanej doprava a doľava:
	private final static Oblasť kvapkaVľavo;
	private final static Oblasť kvapkaVpravo;

	static
	{
		// Inicializácia oblastí:
		kvapkaVľavo = čítajSVGTvar("kvapka.svg");
		kvapkaVpravo = zrkadliPoslednýSVGTvar();
	}

	// Inštancia kreslenia spoločná pre všetky vyšplechnutia:
	private final static KreslenieTvaru kreslenieVyšplechnutia =
		r -> ((Vyšplechnutie)r).kresliVyšplechnutie();


	// Vyšplechnutie je tvorené tromi kvapkami smerujúcimi doľava a tromi
	// smerujúcimi doprava:
	private final Kvapka ľavéKvapky[] =
		{new Kvapka(), new Kvapka(), new Kvapka()};
	private final Kvapka pravéKvapky[] =
		{new Kvapka(), new Kvapka(), new Kvapka()};

	// Metóda keslenia kvapky.
	private void kresliVyšplechnutie()
	{
		// Kvapky smerujúce doľava.
		for (Kvapka kvapka : ľavéKvapky)
		{
			// Úprava polohy a smeru robota:
			skočNa(kvapka);
			smer(kvapka);

			// Vyplnenie oblasti kvapky smerujúcej doľava:
			vyplňOblasť(kvapkaVľavo);
		}

		// Kvapky smerujúce doprava.
		for (Kvapka kvapka : pravéKvapky)
		{
			// Úprava polohy a smeru robota:
			skočNa(kvapka);
			smer(kvapka);

			// Vyplnenie oblasti kvapky smerujúcej doprava:
			vyplňOblasť(kvapkaVpravo);
		}
	}


	// Konštruktor.
	public Vyšplechnutie()
	{
		super(kreslenieVyšplechnutia);
		farba(tmavotyrkysová);
	}


	// Reakcie na udalosti:

	@Override public void aktivita()
	{
		for (Kvapka kvapka : ľavéKvapky) kvapka.aktivita();
		for (Kvapka kvapka : pravéKvapky) kvapka.aktivita();
	}

	@Override public void aktivácia()
	{
		// (Resetuje všetky kvapky. O ostatné sa postará fyzika samotných
		// kvapiek.)
		double
		x = -1.75; for (Kvapka kvapka : ľavéKvapky)
			kvapka.reset(this, x += 0.5);
		x = 1.75; for (Kvapka kvapka : pravéKvapky)
			kvapka.reset(this, x -= 0.5);
		super.aktivácia();
	}
}
« Torpédo Výbuch »

~

import knižnica.*;

// Triedy Detonácia a Výbuch implementujú grafické reprezentácie dvoch
// rôznych explozívnych udalostí. Výbuch je použitý pri každom kontakte
// nálože s cieľom (čiže pri kolíziách sudov s ponorkami a torpéd s loďou).
public class Výbuch extends Predloha
{
	// Oblasť s tvarom výbuchu:
	private final static Oblasť tvarVýbuchu = čítajSVGTvar("vybuch.svg");

	// Inštancia kreslenia spoločná pre všetky výbuchy:
	private final static KreslenieTvaru kreslenieVýbuchu =
		r -> r.vyplňOblasť(tvarVýbuchu);


	// Konštruktor.
	public Výbuch()
	{
		super(kreslenieVýbuchu);
		farba(svetložltá);
		veľkosť(15);
		mierka(1);
		cieľováFarba(svetločervená);
		použiKruhovýNáter();
	}


	// Reakcie na udalosti:

	@Override public void aktivita()
	{
		// (Animácia výbuchu je jednoduchá – plynulé zväčšovanie sa
		// a náhodné striedanie smerov.)
		veľkosť(veľkosť() + 2.5);
		náhodnýSmer();
	}

	@Override public void aktivácia()
	{
		Svet.generátorTónov().setWaveType(13);

		// (Generovanie šumu sprevádzajúceho výbuch.)
		for (int i = 15; i >= 0; --i)
		{
			Svet.hrajTón(
				i * 5,
				i * 0.05,
				0.01);
		}

		veľkosť(10);
		super.aktivácia();
	}
}
« Vyšplechnutie  

Návrhy na zlepšenie:

  • Stavy výhry, prehry a remízy by mohli byť oznamované plávajúcim textom. To by zahŕňalo pridanie mechanizmov, ktoré by tieto stavy boli schopné jednoznačne odlíšiť.