4. diel - Zvuky, hudba, klávesnica a myš v MonoGame
V minulej lekcii, Kreslíme a píšeme v MonoGame , sme si ukázali vykresľovanie spritov a písma. Dnes sa pozrieme na hudbu, zvukové efekty a reakciu na klávesy.
Načítanie obsahu
Rovnako ako minule sprity, aj zvuky a hudbu musíme najprv načítať.
Zvukové efekty sú typu SoundEffect
, hudba je typu
Song
. Do triedy s hrou teda pridáme 2 premenné:
private SoundEffect zvukRada; public Song hudba_zardax;
Presuňme sa do metódy LoadContent()
a zvuky načítajú z
obsahu:
zvukRada = Content.Load<SoundEffect>(@"Zvuky\zvuk_rada"); hudba_zardax = Content.Load<Song>(@"Zvuky\hudba_zardax");
Hudba
Prehrávanie hudby nám zabezpečuje statická trieda
MediaPlayer
. Zaujímať nás bude predovšetkým metóda
Play()
, ktorá berie ako parameter objekt typu Song
,
teda hudbu, ktorú chceme prehrať. Play()
zavoláme na konci
metódy LoadContent()
, prototože práve vtedy je hudba
načítaná.
MediaPlayer.Play(hudba_zardax);
vyskúšame
Pre potreby ďalšieho programovania si vytvoríme verejnú metódu
PrepniHudbu()
, ktorá bude brať ako parameter Song
.
Pokiaľ tento song ešte nehrá, spustí ho. Ak už hrá, nechá ho hrať a
neurobí nič. Touto kontrolou sa vyhneme situáciám, kedy napr. Prídeme do
lokácie, kde má hrať hudba čo už hrá a táto hudba by začala hrať
odznovu, hoci môže jednoducho pokračovať. Aktuálne prehrávanej pesničky
nájdeme vo vlastnosti Query.ActiveSong
. Ako je vidieť,
prehrávač má aj akýsi playlist, ten my v seriáli ale nevyužijeme. Metóda
by mohla vyzerať takto:
public void PrepniHudbu(Song hudba) { // Nehraje již ta samá hudba? if (MediaPlayer.Queue.ActiveSong != hudba) MediaPlayer.Play(hudba); }
Pôvodný prehranie hudby zmeníme na volanie tejto metódy. Ešte dodáme,
aby sa hudba opakovala nastavením vlastnosti IsRepeating
. Koniec
metódy LoadContent()
teda vyzerá takto:
MediaPlayer.IsRepeating = true;
PrepniHudbu(hudba_zardax);
Pre zachovanie zdravého rozumu odporúčam obsah metódy
PrepniHudbu()
na účely vývoja zakomentovat, alebo ju budete po
niekoľkých dňoch programovanie a skúšanie hry nenávidieť
Zvukové efekty
Ďalej tu máme zvukové efekty, tie sú veľmi jednoduché. Kedykoľvek je
potrebujeme prehrať, zavoláme na nich iba metódu Play()
. Zvuk si
skúsime spustiť opäť na konci metódy LoadContent()
:
zvukRada.Play();
Vyskúšame.
Klávesnica
Nejakým spôsobom bude hráč hru samozrejme ovládať. XNA nám poskytuje širokú podporu ovládačov, teda klávesnice, myši, ale aj ďalších zariadení, ako joystickov alebo gamepad. My sa teraz zameriame najmä na klávesnici.
Pre prácu s klávesnicou máme k dispozícii triedu Keyboard
.
Zaujímať nás na nej bude najmä statická metóda GetState()
,
ktorá nám vráti stav aktuálne stlačených kláves. Na inštanciu tohto
stavu sa môžeme potom pýtať, či obsahuje konkrétne kláves. Inštancia
stavu kláves je typu KeyboardState
. Verejnú premennú tohto typu
si pridáme do triedy s hrou:
public KeyboardState klavesy;
Už vieme, že miesto, kde sa budeme na stav klávesov pýtať, je práve
metóda Update()
. Presuňme sa do nej a za spracovaním gamepad pre
XBox si uložme aktuálnu inštanciu stavu kláves:
klavesy = Keyboard.GetState();
Teraz máme v klavesy
uložený súčasný stav klávesnice. Na
inštanciu stave máme 3 užitočné metódy:
IsKeyDown()
- Spýta sa, či je stlačená určitá klávesa.IsKeyUp()
- Spýta sa, či je uvoľnená určitá klávesa.GetPressedKeys()
- Vráti pole všetkých stlačených kláves.
Jednotlivé klávesy rozlišujeme pomocou vymenovaného typu
Keys
. Prvok Keys
(teda jednu konkrétnu
kláves) berú ako parameter prvé 2 metódy. 3. metóda vracia pole prvkov
Keys
.
Spýtajme sa, či je stlačená klávesa Enter a ak áno, prehrajte náš zvuk:
if (klavesy.IsKeyDown(Keys.Enter))
zvukRada.Play();
Vyskúšame.
Vidíme, že celý postup má jednu nevýhodu - klávesa sa neustále vyhodnocuje po celý čas, čo ju držíme. Zvukov teda hrajú desiatky cez seba a nám z toho treští hlava. Niekedy naozaj môžeme chcieť, aby hra takto reagovala na určitú kláves, napr. Keď držíme plyn, auto stále akceleruje, akonáhle ho pustíme, otáčky klesajú. Niekedy ale chceme, aby sa klávesa vyhodnotila len raz a druhýkrát len vtedy, keď je pustená a potom znovu stlačená. Ukážme si, ako na to. K našej premenné klavesy si vyššie deklarujte ešte jednu, reprezentujúci minulý stav kláves:
public KeyboardState klavesy, klavesyMinule;
Uloženie stavu klávesov v Update()
upravme taky, aby v
premennej klavesyMinule
bol minulý stav klávesnice:
klavesyMinule = klavesy; klavesy = Keyboard.GetState();
Teraz nie je nič jednoduchšie, než sa opýtať, či bolo Enter minule pustené a teraz je stlačené:
if (klavesy.IsKeyDown(Keys.Enter) && klavesyMinule.IsKeyUp(Keys.Enter))
zvukRada.Play();
Opäť vyskúšame.
Keďže takéto správanie budeme chcieť často a musíme do podmienky
písať tú istú klávesu 2x, vytvoríme si na tento účel metódu
NovaKlavesa()
. Tá bude v parametri brať prvok vymenovaného typu
Keys
a zistí, či je klávesa teraz držaná a minule držaná
nebola:
public bool NovaKlavesa(Keys klavesa) { return klavesy.IsKeyDown(klavesa) && klavesyMinule.IsKeyUp(klavesa); }
Metóda je verejná, pretože ju budeme používať časom aj mimo triedu s
hrou. Upravíme našu reakciu na Enter v Update()
:
if (NovaKlavesa(Keys.Enter))
zvukRada.Play();
Iste uznáte, že teraz je zápis oveľa prehľadnejšie.
Myš
Ešte máme trochu času a aj keď myš v našom tetrisu používať
nebudeme, ukážeme si, ako sa s ňou pracuje. Neprve použijeme štandardné
kurzor Windows. Ten je štandardne na okne s hrou vypnutý, zapneme ho
prepnutím vlastnosti IsMouseVisible
priamo na hre v metóde
Initialize()
:
IsMouseVisible = true;
Taký kurzor je celkom škaredý, preto ho zas vypneme Ako som sa už zmienil, naša hra
používať myš nebude, preto som pre vás nepripravil žiadny sprite s
kurzorom myši. Ak chcete, nejaký si nakreslite a pridajte, ja tu miesto
kurzora vykreslíte písmeno "X"
.
Podobne ako klávesnica mala triedu Keyboard
, pre myš nám XNA
nachystalo triedu Mouse
. Funguje úplne rovnako, opäť tu máme
stav MouseState
. Novú premennú mys
tohto typu si
pridáme do triedy s hrou:
public MouseState mys;
V Update()
si stav uložíme, rovnako ako sme to urobili so
stavom kláves:
mys = Mouse.GetState();
Teraz sa presunieme do metódy Draw()
, kde vykreslíme "kurzor"
a ďalej vypíšeme aktuálny súradnice a stav tlačidla.
Začneme kurzorom, tu stačí použiť vlastností X
a
Y
na inštanciu stavu myši, ktoré označujú polohu kurzora.
Kurzor vykreslíme ako posledný, aby bol nad všetkým ostatným (samozrejme
ale pred spriteBatch.End()
):
spriteBatch.TextSeStinem(fontCourierNew, "X", new Vector2(mys.X, mys.Y), Color.White);
Teraz vykreslíme pozíciu myši a stav tlačidlá:
string text = String.Format("{0},{1} {2}", mys.X, mys.Y, mys.LeftButton); spriteBatch.TextSeStinem(fontCourierNew, text, new Vector2(0, 700), Color.White);
Kolízie kurzora a obdĺžnika
Nakoniec si ešte ukážeme, ako urobiť kolízii obdĺžnika a bodu. Už
vieme, že XNA má štruktúru Vector2
. Ono má podobných
štruktúr viac, my použijeme Rectangle
(obdĺžnik) a
Point
(bod). Rozdiel medzi bodom a vektorom je ten, že bod má
celočíselné súradnice a postráda metódy ako vektorový súčet. Napriek
tomu je v XNA zvykom používať takmer vždy vektor, pretože s nimi pracujú
vnútornou metódy XNA, napr. Metódy vykresľovací.
Vytvorme si obdĺžnik, ktorý nastavíme približne na pozíciu robota na
pozadí. Po kliknutí na robota sa zobrazí text: "neklikajte na me" Teraz samozrejme iba bastlíme, v
praxi by sme pracovali s objektom robot
, to si časom ukážeme na
objekte kostka
. Do triedy si pridajme tieto premenné:
private Rectangle obdelnikRobota;
V Initialize()
obdĺžnik nastavíme približne na súradnice
robota pomocou ľavého horného bodu a dĺžky strán:
obdelnikRobota = new Rectangle(775, 345, 115, 245);
K číslam som došiel tak, že som si pozadie otvoril vo Windows Maľovanie
a oblasť označil, v dolnej lište mi mspaint ukázal jej súradnice a rozmery.
Teraz sa presuňme do Draw()
a pridajme vykreslenie hlášky:
if (obdelnikRobota.Contains(new Point(mys.X, mys.Y)) && (mys.LeftButton == ButtonState.Pressed)) spriteBatch.TextSeStinem(fontBlox, "Neklikej na me", new Vector2(600, 220), Color.Lime);
Stav tlačidla porovnávame pomocou vymenovaného typu
ButtonState
, obsahujúce prvky Pressed
a
Released
(stlačené a uvoľnené). Ideálne by táto kontrola mala
byť v metóde Update()
, ale pre náš pokus to nevadí. Ak by sme
chceli zložitejšie správanie, rovnako ako u klávesov by sme založili
premennú minulaMys
.
Nabudúce, v lekcii Rozdelenie MonoGame hry do komponentov , sa pozrieme, ako hru rozložiť do niekoľkých herných komponentov. Celý projekt s dnešným riešením si opäť môžete stiahnuť nižšie.
Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami
Stiahnuté 360x (11.85 MB)
Aplikácia je vrátane zdrojových kódov v jazyku C#