Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

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.

Robotris, ukážková hra v XNA Game Studio - Od nuly k tetrisu v MonoGame

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é 359x (11.85 MB)
Aplikácia je vrátane zdrojových kódov v jazyku C#

 

Predchádzajúci článok
Kreslíme a píšeme v MonoGame
Všetky články v sekcii
Od nuly k tetrisu v MonoGame
Preskočiť článok
(neodporúčame)
Rozdelenie MonoGame hry do komponentov
Článok pre vás napísal David Hartinger
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
David je zakladatelem ITnetwork a programování se profesionálně věnuje 15 let. Má rád Nirvanu, nemovitosti a svobodu podnikání.
Unicorn university David sa informačné technológie naučil na Unicorn University - prestížnej súkromnej vysokej škole IT a ekonómie.
Aktivity