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

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

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

Dátum: 20. 4. 2020, pred štyrmi rokmi

Tento príklad demonštruje tieto koncepty:

  • položky ponuky a základnú prácu s nimi,
  • vstupný riadok a spracovanie jeho obsahu,
  • generovanie zvukov (a ukladanie vygenerovaného obsahu do súboru),
  • neštandardné ovládanie robota (základný pohyb robota):
  • položkami ponuky a ich klávesovými skratkami (Ctrl + «kláves»),
  • príkazmi zadávanými prostredníctvom vstupného riadka.

 

obrázok

 

~

import knižnica.*;
import static knižnica.Svet.*;
import static knižnica.Kláves.*;
import static knižnica.ÚdajeUdalostí.*;

public class JazdiaciRobot extends GRobot
{
	// Konštanty prehrávania tónov…

	// Frekvencia najnižšieho tónu:
	private final static int najnižšíTón = 212;

	// Frekvenčný „odstup“ tónov:
	private final static int odstupTónov = 128;

	// Počet tónov v sérii:
	private final static int početTónov = 40;

	// Násobok hlasitosti (spolu s počtom tónov určia mieru útlmu
	// hlasitosti tónov):
	private final static double útlmTónov = 0.025;

	// Trvanie prehrávania jednotlivých tónov:
	private final static double trvanieTónov = 0.0025;


	// Deklarácie položiek ponuky:

	private final PoložkaPonuky vpred;
	private final PoložkaPonuky vzad;
	private final PoložkaPonuky vpravo;
	private final PoložkaPonuky vľavo;

	private final PoložkaPonuky stoj;
	private final PoložkaPonuky vystreľ;


	// Deklarácia zvuku:
	private final Zvuk zvuk;


	// Deklarácie atribútov slúžiacich na spracovanie príkazov:
	private final StringBuffer príkaz = new StringBuffer();
	private double parameter = 0.0;


	// Konštruktor.
	private JazdiaciRobot()
	{
		// Zmení rozmery plátna:
		super(500, 500, "Jazdiaci robot ");

		// Inicializácia položiek ponuky:
		vpred = new PoložkaPonuky("Vpred", VK_D, VK_I);
		vzad = new PoložkaPonuky("Vzad", VK_Z, VK_K);
		vpravo = new PoložkaPonuky("Vpravo", VK_P, VK_L);
		vľavo = new PoložkaPonuky("Vľavo (l)", VK_L, VK_J);

		stoj = new PoložkaPonuky("Stoj", VK_S, VK_S);
		vystreľ = new PoložkaPonuky("Vystreľ", VK_T, VK_D);

		// Čítanie alebo generovanie zvuku:
		zvuk = dajZvuk();

		// Nastavenia sveta:
		aktivujHistóriuVstupnéhoRiadka();
		neskrývajVstupnýRiadok();
		začniVstup();
		zbaľ();

		// Nastavenia robota:
		farba(tmavohnedá);
		hrúbkaPera(3);
		ohranič();

		// Spustenie…
		spustiČasovač(0.04);
		prekresli();
	}

	// Táto metóda prečíta alebo vyrobí zvuk výstrelu. Ak by bol disk
	// chránený proti zápisu alebo by nastalo iné zlyhanie, tak by sa
	// zvuk generoval vždy na požiadanie a to metódou generujZvuk.
	private Zvuk dajZvuk()
	{
		// Ak zvuk nejestvuje, vygenerujeme ho:
		if (!Súbor.jestvuje("laser.wav"))
		{
			// Krátke naladenie generátora (neúspešný pokus o to, aby bol
			// vygenerovaný zvuk stále rovnaký; generátor zvukov je veľmi
			// citlivý na predchádzajúci stav, takže každý uložený zvuk
			// bude odlišný):
			hrajTón(najnižšíTón + odstupTónov * početTónov); čakaj(0.750);
			zastavTón(); čakaj(0.300);

			// Generovanie a uloženie zvuku:
			if (otvorSúborNaUloženieTónu("laser.wav"))
			{
				for (int i = početTónov; i >= 0; --i)
				{
					hrajTón(najnižšíTón + odstupTónov * i, i * útlmTónov);
					čakaj(trvanieTónov);
				}

				zastavTón();
				čakaj(0.200);

				if (!zavriSúborNaUloženieTónu())
					// Vypíše upozornenie na štandardnom chybovom výstupe:
					System.err.println("Súbor zvuku sa " +
						"nepodarilo zapísať.");
			}
			else
				// Vypíše upozornenie na štandardnom chybovom výstupe:
				System.err.println("Súbor na zápis zvuku " +
					"sa nepodarilo otvoriť.");
		}

		try
		{
			// Prečítanie zvuku:
			return čítajZvuk("laser.wav");
		}
		catch (Throwable t)
		{
			// Vypíše podrobné hlásenie na štandardnom chybovom výstupe:
			t.printStackTrace();

			// V prípade zlyhania vráti null:
			return null;
		}
	}

	// Metóda, ktorá by generovala zvuk, keby ho nebolo možné prečítať
	// z pevného disku.
	private void generujZvuk()
	{
		// (Generátor je citlivý na predchádzajúci stav, takže každý
		// nový zvuk bude mierne odlišný od predchádzajúceho.)
		for (int i = početTónov; i >= 0; --i)
			hrajTón(najnižšíTón + odstupTónov * i,
				i * útlmTónov, trvanieTónov);
	}


	// Príkaz vystreľ prijíma jeden parameter, ktorý znamená vzdialenosť
	// dostrelu. Metóda nakreslí žltú čiaru a ak bol úspešne prečítaný
	// zvuk, prehrá ho, ak nebol, vygeneruje zakaždým nový unikátny.
	private void vystreľ(double parameter)
	{
		if (null == zvuk) generujZvuk(); else zvuk.prehraj();

		Bod poloha = poloha();
		Farba farba = farba();
		double smer = smer();
		double hrúbkaPera = hrúbkaPera();

		farba(svetložltá);
		hrúbkaPera(hrúbkaPera / 2.5);
		vľavo(10 * uhlováRýchlosť());
		skoč();
		vpred(parameter);

		hrúbkaPera(hrúbkaPera);
		smer(smer);
		farba(farba);
		poloha(poloha);
	}

	// Metóda pomáhajúca pri rozpoznávaní príkazov.
	private boolean príkazSaZačína(String začiatok)
	{
		int length = začiatok.length();
		if (príkaz.length() < length) return false;
		for (int i = 0; i < length; ++i)
			if (príkaz.charAt(i) != začiatok.charAt(i)) return false;
		return true;
	}

	// Metóda majúca na starosti rozpoznávanie príkazov a ich parametrov.
	private boolean rozpoznajPríkaz(String rozpoznaj) throws Exception
	{
		if (príkazSaZačína(rozpoznaj))
		{
			try
			{
				// Parameter je povinný:
				parameter = Double.parseDouble(
					príkaz.substring(1 + rozpoznaj.length()));
				return true;
			}
			catch (Exception e)
			{
				throw new Exception("Nesprávny parameter!");
			}
		}
		return false;
	}

	// Súkromná metóda slúžiaca na spracovanie príkazov. Toto riešenie
	// poskytuje vyššiu univerzálnosť, lebo príkazy môžu prúdiť aj
	// z iného zdroja, než vstupný riadok.
	private void spracujPríkaz(String reťazec)
	{
		// Nastavenie hodnoty atribútu príkaz, ktorý bude v ďalšom bloku
		// try-catch opakovane využívaný. V OOP sa takýmto spôsobom
		// vyhýbame zbytočnému posielaniu parametrov medzi súkromnými
		// metódami. (Toto riešenie nie je bezpečné pri viacvláknových
		// programoch, nie je tzv. thread-safe, ale dá sa relatívne
		// jednoducho zabezpečiť. Tento program nie je v súvislosti so
		// spracovaním príkazov viacvláknový.)
		príkaz.setLength(0);
		príkaz.append(reťazec.toLowerCase());

		// Test, či je aktuálny príkaz neprázdny:
		if (0 != príkaz.length())
		try
		{
			// Rozpoznávanie a vykonávanie príkazov…
			if (rozpoznajPríkaz("vpred")) vpred(parameter);
			else if (rozpoznajPríkaz("vzad")) vzad(parameter);
			else if (rozpoznajPríkaz("vystreľ") ||
				rozpoznajPríkaz("vystrel")) vystreľ(parameter);
			else if (rozpoznajPríkaz("vpravo")) vpravo(parameter);
			else if (rozpoznajPríkaz("vľavo") ||
				rozpoznajPríkaz("vlavo")) vľavo(parameter);
			else if (rozpoznajPríkaz("vpravo")) vpravo(parameter);
			else if (rozpoznajPríkaz("rýchlosť") ||
				rozpoznajPríkaz("rychlost")) rýchlosť(parameter);
			else if (rozpoznajPríkaz("rotácia") ||
				rozpoznajPríkaz("rotacia") || rozpoznajPríkaz("rotuj"))
				uhlováRýchlosť(parameter);
			else chyba("Neznámy príkaz!");
		}
		catch (Exception e)
		{
			// Táto chyba nastáva pri zadaní nečíselného parametra:
			chyba(e.getMessage());
		}
	}

	// Potvrdenie údajov jednoducho vykoná vyššie definovanú metódu
	// s reťazcom prevzatým zo vstupného riadka:
	@Override public void potvrdenieÚdajov()
	{
		spracujPríkaz(prevezmiReťazec());
	}


	// Kreslenie vlastného tvaru, ktorý odzrkadľuje aktuálny smer aj uhlovú
	// rýchlosť.
	@Override public void kresliTvar()
	{
		farba(tmavozelená);
		kružnica();
		skoč();
		vpred();

		domov();
		farba(čierna);
		vľavo(10 * uhlováRýchlosť());
		skoč(5);
		vpred();
	}

	// Spracovanie príkazov položiek ponuky (ktoré sú zároveň sprístupnené
	// prostredníctvom klávesových skratiek – ovládanie klávesovými skratkami
	// sa odlišuje od ovládania príkazmi; napriek tomu nie sú v príkrom
	// rozpore, vedia fungovať nezávisle od seba, ale ich rozdielnosť by
	// určite miatla neinformovaného používateľa, preto sa takéto riešenia
	// softvéru neodporúčajú ; tu však slúžia na ukážku dvoch rôznych
	// prístupov).
	@Override public void voľbaPoložkyPonuky()
	{
		// (Väčšina volieb je samovysvetľujúcich.)

		if (vpred == položkaPonuky())
		{
			rýchlosť(rýchlosť() + 0.25);
		}
		else if (vzad == položkaPonuky())
		{
			rýchlosť(rýchlosť() - 0.25);
		}
		else if (stoj == položkaPonuky())
		{
			// Vlastné riešenie zastavenia formou postupného spomaľovania
			// (zrýchlenie je resetované v reakcii na zastavenie):
			if (rýchlosť() > 0)
				zrýchlenie(-0.5);
			else
				zrýchlenie(0.5);
			zastavPoSpomalení();

			// Keby sme pohyb riešili prostredníctvom zrýchlenia
			// a maximálnej rýchlosti, tak by na tomto mieste stačilo
			// uviesť príkaz: zabrzdi();
		}
		else if (vystreľ == položkaPonuky())
		{
			vystreľ(60);
		}
		else if (vpravo == položkaPonuky())
		{
			uhlováRýchlosť(uhlováRýchlosť() - 0.5, false);
			prekresli();
		}
		else if (vľavo == položkaPonuky())
		{
			uhlováRýchlosť(uhlováRýchlosť() + 0.5, false);
			prekresli();
		}
	}

	// Reakcia na zastavenie.
	@Override public void zastavenie()
	{
		// Nastaví nulové zrýchlenie, aby sa zrušil prípadný
		// efekt položky ponuky stoj.
		zrýchlenie(0, false);
	}


	// Hlavná metóda.
	public static void main(String[] args)
	{
		new JazdiaciRobot();
	}
}