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

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

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

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

Zadanie

Naprogramujte jednoduchú hru, v ktorej sa bude na obrazovke (plátne) pohybovať množstvo bublín, ktoré bude mať hráč za úlohu čo najrýchlejšie popraskať ihlou.

Požiadavky:

  • Praskanie musí hráč realizovať nejakou akciou (nesmie ísť o pasívne praskanie len pohybom kurzora myši), napríklad klikaním tlačidiel myši.
  • Bubliny sa musia odrážať od okrajov obrazovky (plátna) podľa zákona rovnosti uhlov odrazu a dopadu.
  • Bublina sa pri ohrození ihlou bude usilovať robiť únikové manévre.

Bonusová požiadavka:

  • Nech je efekt prasknutia bubliny sprevádzaný krátkou animáciou.

Riešenie

~

import knižnica.*;

/**
 * Trieda slúžiaca na spúšťanie aplikácie.
 */
public class HlavnáTrieda extends GRobot
{
	// Zoznam všetkých bublín.
	private final static Zoznam<Bublina> bubliny = new Zoznam<>();

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

	/**
	 * Konštruktor inicializujúci aplikáciu.
	 */
	private HlavnáTrieda()
	{
		// Vykonanie niekoľkých úvodných nastavení (úprava veľkosti plátna,
		// skrytie hlavného robota…).
		super(400, 400, "Bubliny");
		Svet.zbaľ();
		skry();
		Svet.nekresli();

		// Vytvorenie všetkých bublín:
		for (int i = 0; i < 50; ++i)
			bubliny.pridaj(new Bublina());

		// Pridanie položky „Nová hra“ do ponuky:
		nováHra = Svet.pridajPoložkuPonuky("Nová hra",
			Kláves.VK_N, Kláves.VK_N);

		// Dokončenie nastavení (úprava tvaru kurzora a spustenie novej hry).
		zmeňKurzorMyši();
		nováHra();
	}


	// Spustenie novej hry.
	private void nováHra()
	{
		Svet.nekresli();
		for (Bublina bublina : bubliny)
			bublina.aktivuj(false);
		Svet.kresli();
		Svet.spustiČasovač();
	}

	/**
	 * Reakcia na voľbu položky ponuky „Nová hra“ – potvrdzujúcou otázkou
	 * a spustením novej hry v prípade kladnej odpovede.
	 */
	@Override public void voľbaPoložkyPonuky()
	{
		if (nováHra.aktivovaná() && ÁNO ==
			Svet.otázka("Spustiť novú hru?")) nováHra();
	}


	// Úprava tvaru kurzora myši.
	private void zmeňKurzorMyši()
	{
		// Vytvorenie (transparentného) obrázka, ktorý bude použitý na
		// nakreslenie a definíciu nového kurzora myši:
		Obrázok ihla = new Obrázok(32, 32);


		// Kreslenie ihly (do obrázka):

		kresliDoObrázka(ihla);
		hrúbkaČiary(2.5);

		farba(tyrkysová);
		choďNa(-16, -16);

		domov();
		farba(modrá);
		kruh(4.5);


		// Definícia nového kurzora myši a jeho aktivácia:
		Svet.novýKurzorMyši(ihla, -15, -15, "ihla");
		Svet.zmeňKurzorMyši("ihla");
	}


	/**
	 * Metóda slúžiaca na spúšťanie aplikácie.
	 *
	 * @param args  parametre prijaté z konzoly
	 */
	public static void main(String[] args)
	{
		new HlavnáTrieda();
	}
}
  Bublina »

~

import knižnica.*;

/**
 * Trieda implementujúca bublinu.
 */
public class Bublina extends GRobot
{
	// Tvar bubliny je prostý krúžok s polomerom rovným veľkosti bubliny.
	private final static KreslenieTvaru tvar = r -> r.krúžok();

	// Atribút používaný na počítanie za sebou nasledujúcej série odrazov,
	// čím sa dá detegovať uviaznutie.
	private int početOdrazov = 0;

	/**
	 * Konštruktor bubliny. (Nastaví všetky jej požadované vlastnosti.)
	 */
	public Bublina()
	{
		vlastnýTvar(tvar);
		zdvihniPero();
		hrúbkaČiary(1.75);
		farba(svetlotyrkysová);
		unikaj();
	}


	/**
	 * Metóda rezervovaná na implementáciu únikového manévra bubliny pri
	 * ohrození ihlou. Momentálne je manéver veľmi jednoduchý: bublina
	 * náhodne zmení smer a náhodne upraví svoju rýchlosť v rozmedzí ⟨5; 10⟩.
	 */
	public void unikaj()
	{
		náhodnýSmer();
		rýchlosť(Svet.náhodnéCeléČíslo(5, 10), false);
	}


	/**
	 * Metóda slúžiaca na vykonanie odrazenia sa bubliny od vodorovnej steny.
	 */
	public void odrazSaVodorovne()
	{
		uhol(360 - uhol());
		dopredu(rýchlosť());
	}

	/**
	 * Metóda slúžiaca na vykonanie odrazenia sa bubliny od zvislej steny.
	 */
	public void odrazSaZvislo()
	{
		uhol(180 - uhol());
		dopredu(rýchlosť());
	}


	/**
	 * Reakcia na stlačenie tlačidla myši – overí, či je bublina aktívna, či
	 * sa kurzor myši nachádza v bubline a či bolo stlačené ľavé tlačidlo
	 * myši. Ak sú všetky podmienky splnené, bublina praskne.
	 */
	@Override public void stlačenieTlačidlaMyši()
	{
		if (aktívny() && myšVKruhu() && ÚdajeUdalostí.tlačidloMyši(ĽAVÉ))
		{
			Puk.pukni(this);
			deaktivuj();
		}
	}

	/**
	 * Reakcia na aktiváciu bubliny (presunie bublinu na náhodné miesto,
	 * náhodne zmení jej veľkosť a zobrazí ju).
	 */
	@Override public void aktivácia()
	{
		náhodnáPoloha();
		veľkosť(Svet.náhodnéCeléČíslo(8, 22));
		zobraz();
	}

	/**
	 * Reakcia na deaktiváciu bubliny (skryje bublinu).
	 */
	@Override public void deaktivácia()
	{
		skry();
	}

	// Súkromná metóda slúžiaca na odrazenie sa bubliny od okraja a zároveň
	// pomáhajúca pri detekcii uviaznutia bubliny.
	//
	// @return návratová hodnota true signalizuje, že sa bublina odrazila
	private boolean odrazilaSa()
	{
		if (polohaY() + veľkosť() > Svet.hornýOkraj() ||
			polohaY() - veľkosť() < Svet.spodnýOkraj())
		{
			odrazSaVodorovne();
			return true;
		}
		else if (polohaX() + veľkosť() > Svet.pravýOkraj() ||
			polohaX() - veľkosť() < Svet.ľavýOkraj())
		{
			odrazSaZvislo();
			return true;
		}
		return false;
	}

	/**
	 * Vykonávanie činností počas aktívneho stavu bubliny.
	 */
	@Override public void aktivita()
	{
		if (myšVKruhu()) unikaj();

		// Nasledujúci mechanizmus slúži na detekciu uviaznutia bubliny
		// a jej vyslobodenie:
		if (odrazilaSa())
		{
			if (odrazilaSa())
			{
				if (++početOdrazov > 5)
					náhodnáPoloha();
			}
			else početOdrazov = 0;
		}
	}
}
« Hlavná trieda Puk »

~

import knižnica.*;

/**
 * Trieda implementujúca autonómny efekt puknutia bubliny.
 */
public class Puk extends GRobot
{
	// Tvar puku je osmica lúčov rovnomerne rozmiestnených v kruhu
	// vzdialených od stredu o vzdialenosť rovnú aktuálnej veľkosti puku.
	private final static KreslenieTvaru tvar = r ->
	{
		for (int i = 0; i < 8; ++i)
		{
			r.vpravo(45);
			r.skoč(r.veľkosť());
			r.dopredu(10);
			r.odskoč(10 + r.veľkosť());
		}
	};

	// Zoznam všetkých pukov.
	private final static Zoznam<Puk> puky = new Zoznam<>();

	// Atribút uchovávajúci si pôvodnú hodnotu veľkosti bubliny, ktorej
	// prasknutie tento puk animuje.
	private double veľkosť;


	/**
	 * Konštruktor prijímajúci inštanciu bubliny, ktorej prasknutie má
	 * tento puk animovať.
	 *
	 * @param bublina  bublina, ktorej prasknutie bude tento puk animovať
	 */
	public Puk(Bublina bublina)
	{
		vlastnýTvar(tvar);
		zdvihniPero();
		hrúbkaČiary(1.75);
		farba(svetlotyrkysová);
		reset(bublina);
	}


	/**
	 * Resetne puk podľa zadanej bubliny. (To jest bubliny, ktorej prasknutie
	 * má animovať.)
	 *
	 * @param bublina  bublina, ktorej prasknutie bude tento puk animovať
	 */
	public void reset(Bublina bublina)
	{
		skočNa(bublina);
		smer(bublina);
		rýchlosť(bublina.rýchlosť(), false);
		veľkosť(veľkosť = bublina.veľkosť() - 5);
		aktivuj(10, false);
	}


	/**
	 * Reakcia na aktiváciu puku (zobrazí ho).
	 */
	@Override public void aktivácia()
	{
		zobraz();
	}

	/**
	 * Reakcia na deaktiváciu puku (skryje ho).
	 */
	@Override public void deaktivácia()
	{
		skry();
	}

	/**
	 * Vykonávanie činností počas aktívneho stavu puku.
	 */
	@Override public void aktivita()
	{
		veľkosť(veľkosť + 10 - trvanieAktivity());
	}


	/**
	 * Statická metóda hľadajúca neaktívny puk alebo vyrábajúca nový puk, ak
	 * nejestvuje žiadny neaktívny puk. Nájdený alebo vyrobený puk sa aktivuje
	 * pre zadanú bublinu. (To jest pre bublinu, ktorej prasknutie má
	 * animovať.)
	 *
	 * @param bublina  bublina, ktorej prasknutie má nájdený (alebo vyrobený)
	 *     puk animovať
	 */
	public static void pukni(Bublina bublina)
	{
		// Hľadanie neaktívneho puku:
		for (Puk puk : puky)
			if (puk.pasívny())
			{
				// Ak je nájdený, aktivuje (resetne) sa podľa zadanej bubliny
				// a vykonávanie metódy sa skončí:
				puk.reset(bublina);
				return;
			}

		// Ak nie je nájdený žiadny neaktívny puk, tak sa vyrobí nový, ktorý
		// sa automaticky aktivuje pre zadanú bublinu):
		Puk puk = new Puk(bublina);
		puky.pridaj(puk);
	}
}
« Bublina  

 

Výsledok

  
obrázok 
Ukážka vzhľadu hry tesne pred ukončením. 
 

Návrhy na zlepšenia

  • Detekcia ukončenia hry a zobrazenie víťaznej správy.
  • Obnovovanie bublín po určitom dostatočne dlhom časovom intervale (aby mal hráč motiváciu pracovať rýchlo a zároveň aby mal šancu na úspešné dokončenie hry).
  • Ukladanie aktuálneho stavu hry do konfigurácie.