IT rekvalifikácia. Seniorní programátori zarábajú až 6 000 €/mesiac a rekvalifikácia je prvým krokom. Zisti, ako na to!

13. diel - MonoGame: Herné menu

V minulej lekcii, MonoGame: Správa herných obrazoviek , sme si naprogramovali správu herných obrazoviek a pripravili komponent pre herné menu. Nič nám nebráni v tom, aby sme sa do neho dnes pustili :)

Menu budeme chcieť samozrejme pekné as nejakými efekty. Najprv si do našej komponenty KomponentaMenu pridáme pozadia. Tu si ho stiahnite:

pozadie menu - Od nuly k tetrisu v MonoGame

a pridajte do zložky Sprity/ v hre. Pridáme príslušný atribút:

private Texture2D pozadi;

Načítanie do LoadContent():

pozadi = hra.Content.Load<Texture2D>(@"Sprity\pozadi_menu");

A vykreslenie do Draw():

hra.spriteBatch.Begin();
hra.spriteBatch.Draw(pozadi, new Vector2(0, 0), Color.White);
hra.spriteBatch.End();
Ukážkový Tetris v XNA Game Studio - Od nuly k tetrisu v MonoGame

Menu si rozdelíme do dvoch komponentov, aby sme ho mali znovu použiteľné a dalo sa použiť bez veľkých zmien aj v inej hre alebo obrazovke. KomponentaMenu sa bude starať o vykreslenie tých častí menu, ktoré sú špecifické pre hru Robotris. Pridajme si ešte jednu univerzálnu komponent, ktorá bude spravovať jednotlivé položky menu. Komponent bude vykreslitelná a bude sa volať KomponentaPolozkyMenu. Opäť pre úplnosť uvediem jej prázdny zdrojový kód (nezabudnite, že namespace má byť opäť len Robotris, aj keď je v priečinku Komponenty/):

namespace Robotris
{
    public class KomponentaPolozkyMenu : Microsoft.Xna.Framework.DrawableGameComponent
    {

            private Hra hra;

            public KomponentaPolozkyMenu(Hra hra)
                    : base(hra)
            {
                    this.hra = hra;
            }

            public override void Initialize()
            {
                    base.Initialize();
            }

            protected override void LoadContent()
            {
                    base.LoadContent();
            }

            public override void Update(GameTime gameTime)
            {
                    base.Update(gameTime);
            }

            public override void Draw(GameTime gameTime)
            {
                    base.Draw(gameTime);
            }
    }
}

Zatiaľ ju ponecháme prázdnu a pridáme ďalšiu triedu, ktorej inštancia bude reprezentovať jednu položku menu. Triedu pridáme medzi ďalšie triedy priamo v projekte Robotris.

Položka menu

Trieda sa bude volať PolozkaMenu. Bude obsahovať údaje o svojej pozícii (súradniciach na obrazovke), veľkosti a textu. Veľkosti preto, že vybranú položku budeme škálovať a to vrátane animácie. Trieda je veľmi jednoduchá, uveďme si rovno jej zdrojový kód:

public class PolozkaMenu
{
    public string text;
    public Vector2 pozice;
    public float velikost;

    public PolozkaMenu(string text, Vector2 pozice)
    {
        this.text = text;
        this.pozice = pozice;
        velikost = 0.6f;
    }
}

Kvôli použitie štruktúry Vector2 dodáme using na XNA framework:

using Microsoft.Xna.Framework;

Presuňme sa do KomponentaPolozkyMenu. Tento komponent bude správca položiek menu, bude ich uchovávať, prepínať a vykresľovať. Konkrétne udalosti (čo ktorá položka po stlačení vykoná) vložíme neskôr do KomponentaMenu, pretože to je závislé na konkrétnej hre.

Pridáme list položiek ako atribút, ďalej aktuálne vybratú položku a pozíciu menu:

private List<PolozkaMenu> polozky;
public PolozkaMenu vybranaPolozka;
private Vector2 pozice;

Komponent sa pokúsime urobiť čo najviac prispôsobiteľný, preto pridáme ešte farbu vybrané a nevybrané položky a výšku položky (tam potom uložíme výšku písma):

private Color nevybranaBarva;
private Color vybranaBarva;
private int vyska;

Presunieme sa do konstruktoru, ktorému pridáme ďalšie parametre a kde inicializujeme atribúty:

public KomponentaPolozkyMenu(Hra hra, Vector2 pozice, Color nevybranaBarva, Color vybranaBarva, int vyska): base(hra)
{
    this.pozice = pozice;
    this.hra = hra;
    this.nevybranaBarva = nevybranaBarva;
    this.vybranaBarva = vybranaBarva;
    this.vyska = vyska;
    polozky = new List<PolozkaMenu>();
    vybranaPolozka = null;
}

Správa položiek menu

Pridajme niekoľko metód pre prácu s kolekciou položiek menu. Začnite pridaním nové položky. Metóda bude brať v parametri text položky. Vnútri vytvorí novú položku, tej nastaví pozíciu pod už existujúce položky v menu, podľa ich výšky. Položku následne pridá do internej kolekcie a pokiaľ nie je žiadna vybraná, vyberie práve ju (vybraná teda bude vždy 1. položka v menu). Metóda by mohla vyzerať takto:

public void PridejPolozku(string text)
{
    // nastavení pozice podle pořadí položky
    Vector2 p = new Vector2(pozice.X, pozice.Y + polozky.Count * vyska);
    PolozkaMenu polozka = new PolozkaMenu(text, p);
    polozky.Add(polozka);
    // výběr první položky
    if (vybranaPolozka == null)
        vybranaPolozka = polozka;
}

Po pridaní položiek bude treba vyberať ďalšie a predchádzajúcu položku. V metóde pre vybranie ďalšie položky nebude mimo prechodu z poslednej späť na prvú nič zaujímavé. Pretože si neudržujeme pozíciu aktuálnej položky, ale len jej inštanciu, musíme jej index vždy znovu zistiť, ale to nás v našom prípade nijako netrápi.

public void VyberDalsi()
{
    int index = polozky.IndexOf(vybranaPolozka);
    if (index < polozky.Count - 1)
        vybranaPolozka = polozky[index + 1];
    else
        vybranaPolozka = polozky[0];
}

Metóda pre výber predchádzajúcej položky bude podobná:

public void VyberPredchozi()
{
    int index = polozky.IndexOf(vybranaPolozka);
    if (index > 0)
        vybranaPolozka = polozky[index - 1];
    else
        vybranaPolozka = polozky[polozky.Count - 1];
}

Obsluha položiek

Obsluhu položiek nastavíme na klávesy nadol a nahor. Budeme tak prepínať ďalšie a predchádzajúcu položku. Presuňme sa do Update() a dodajme reakcii na tieto klávesy:

// reakce na klávesy
if (hra.NovaKlavesa(Keys.Up))
    VyberPredchozi();
if (hra.NovaKlavesa(Keys.Down))
    VyberDalsi();

Vykreslenie položiek

Pretože u položiek budeme potrebovať špecifikovať aj veľkosť, nevystačíme si s našou metódou TextSeStinem(). Preto si triedu LepsiSpriteBatch obohatíme o ďalšiu metódu, ktorá vykreslí škálovanie text s tieňom pomocou ďalšieho preťaženie metódy DrawString():

public void TextSeStinemSkalovany(SpriteFont spriteFont, string text, Vector2 position, Color color, float size)
{
    DrawString(spriteFont, text, new Vector2(position.X + 2, position.Y + 2), Color.Black * 0.8f, 0.0f, new Vector2(0, 0), size, SpriteEffects.None, 0);
    DrawString(spriteFont, text, position, color, 0.0f, new Vector2(0, 0), size, SpriteEffects.None, 0);
}

Teraz už je pre nás hračka vykresliť v Draw() položky menu:

hra.spriteBatch.Begin();
foreach (PolozkaMenu polozka in polozky)
{
    Color barva = nevybranaBarva;
    if (polozka == vybranaPolozka)
        barva = vybranaBarva;
    hra.spriteBatch.TextSeStinemSkalovany(hra.fontBlox, polozka.text, polozka.pozice, barva, polozka.velikost);
}
hra.spriteBatch.End();

(Tu je závislosť na font fontBlox z hry. Ideálne by sme mali umožniť font odovzdať, ale kvôli tomu, že font existuje až po volaní LoadContent() by sa nám práca skomplikovala a preto toto zanedbáme).

Vloženie komponentov do seba

Komponent KomponentaPolozkyMenu teraz vložíme do komponenty KomponentaMenu. Takto sme do seba komponenty ešte nevkladali, poďme si to vyskúšať. Presuňme sa do KomponentaMenu.cs, kde pridajme atribút s inštanciou komponentmi KomponentaPolozkyMenu:

private KomponentaPolozkyMenu polozkyMenu;

Samotnú inštanciu si však vytvoríme v Hra.cs (pretože tu potrebujeme komponent pridať do obrazovky). Išlo by to samozrejme navrhnúť aj inak, ale preferujte jednoduchosť. Do KomponentaMenu inštanciu dostaneme konstruktoru, ktorý modifikujeme:

public KomponentaMenu(Hra hra, KomponentaPolozkyMenu polozkyMenu)
    : base(hra)
{
    this.hra = hra;
    this.polozkyMenu = polozkyMenu;
}

Presuňme sa do Hra.cs a v Initialize() a pridajme vytvorenie inštancie komponenty KomponentaPolozkyMenu:

KomponentaPolozkyMenu polozkyMenu = new KomponentaPolozkyMenu(this, new Vector2(700, 250), Color.Red, Color.Yellow, 80);

A za ňou rovno pridanie njěkolika položiek do menu:

polozkyMenu.PridejPolozku("StArT");
polozkyMenu.PridejPolozku("SkOrE");
polozkyMenu.PridejPolozku("AuToRi");
polozkyMenu.PridejPolozku("KoNeC");

Striedam v názve položiek veľké a malé písmená, pretože to s fontom Blox vyzerá dobre :)

Do volanie konstruktoru KomponentaMenu doplníme inštanciu polozkyMenu.

KomponentaMenu menu = new KomponentaMenu(this, polozkyMenu);

A rovnako tak ju dodáme aj do vytvárania obrazovky obrazovkaMenu:

obrazovkaMenu = new HerniObrazovka(this, mraky, menu, polozkyMenu);

Otvorte si font_blox.spritefont v priečinku Fonty/ a zmeňte Style z Regular na Bold. Projekt spustíme, mali by ste dospieť takéhoto výsledku:

Ukážkový Tetris v XNA Game Studio - Od nuly k tetrisu v MonoGame

Vidíme, že aj prepínanie položiek funguje dobre. Nabudúce, v lekcii MonoGame: Skrolující text (autori hry) , sprevádzkujeme klikanie na položky a vytvoríme si obrazovku autori sa skrolujícím textom.


 

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

 

Predchádzajúci článok
MonoGame: Správa herných obrazoviek
Všetky články v sekcii
Od nuly k tetrisu v MonoGame
Preskočiť článok
(neodporúčame)
MonoGame: Skrolující text (autori hry)
Č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