Lekce 13 - MonoGame: Herní menu
V minulé lekci, MonoGame: Správa herních obrazovek, jsme si naprogramovali správu herních obrazovek a připravili komponentu pro herní menu.
Nic nám nebrání v tom, abychom se do menu dnes pustili 
Menu budeme chtít samozřejmě hezké a s nějakými efekty. Nejprve si do
naší komponenty KomponentaMenu přidáme pozadí. Zde si ho
stáhněte:

a přidejte do složky Sprity/ ve hře. Přidáme příslušný
atribut:
private Texture2D pozadi;
Načtení do LoadContent():
pozadi = hra.Content.Load<Texture2D>(@"Sprity\pozadi_menu");
A vykreslení do Draw():
hra.spriteBatch.Begin(); hra.spriteBatch.Draw(pozadi, new Vector2(0, 0), Color.White); hra.spriteBatch.End();
Výsledek:

Menu si rozdělíme do dvou komponent, aby jsme ho měli znovupoužitelné a
dalo se použít bez velkých změn i v jiné hře nebo obrazovce.
KomponentaMenu se bude starat o vykreslení těch částí menu,
které jsou specifické pro hru Robotris. Přidejme si ještě jednu
univerzální komponentu, která bude spravovat jednotlivé položky menu.
Komponenta bude vykreslitelná a bude se jmenovat
KomponentaPolozkyMenu. Opět pro úplnost uvedu její prázdný
zdrojový kód (nezapomeňte, že namespace má být opět jen
Robotris, i když je ve složce 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); } } }
Zatím ji ponecháme prázdnou a přidáme další třídu, jejíž instance
bude reprezentovat jednu položku menu. Třídu přidáme mezi další třídy
přímo v projektu Robotris.
Položka menu
Třída se bude jmenovat PolozkaMenu. Bude obsahovat údaje o
své pozici (souřadnicích na obrazovce), velikosti a textu. Velikosti proto,
že vybranou položku budeme škálovat a to včetně animace. Třída je velmi
jednoduchá, uveďme si rovnou 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žití struktury Vector2 dodáme using na XNA
framework:
using Microsoft.Xna.Framework;
Přesuňme se do KomponentaPolozkyMenu. Tato komponenta bude
správce položek menu, bude je uchovávat, přepínat a vykreslovat.
Konkrétní události (co která položka po stisknutí vykoná) vložíme
později do KomponentaMenu, protože to je závislé na konkrétní
hře.
Přidáme list položek jako atribut, dále aktuálně vybranou položku a pozici menu:
private List<PolozkaMenu> polozky; public PolozkaMenu vybranaPolozka; private Vector2 pozice;
Komponentu se pokusíme udělat co nejvíce uzpůsobitelnou, proto přidáme ještě barvu vybrané a nevybrané položky a výšku položky (tam poté uložíme výšku písma):
private Color nevybranaBarva; private Color vybranaBarva; private int vyska;
Přesuneme se do konstruktoru, kterému přidáme další parametry a kde inicializujeme atributy:
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žek menu
Přidejme několik metod pro práci s kolekcí položek menu. Začněmě přidáním nové položky. Metoda bude brát v parametru text položky. Uvnitř vytvoří novou položku, té nastaví pozici pod již existující položky v menu, podle jejich výšky. Položku následně přidá do interní kolekce a pokud není žádná vybraná, vybere právě ji (vybraná tedy bude vždy 1. položka v menu). Metoda by mohla vypadat 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 přidání položek bude třeba vybírat další a předchozí položku. V metodě pro vybrání další položky nebude mimo přechodu z poslední zpět na první nic zajímavého. Protože si neudržujeme index aktuální položky, ale jen její instanci, musíme její index vždy znovu zjistit, ale to nás v našem případě nijak netrápí.
public void VyberDalsi() { int index = polozky.IndexOf(vybranaPolozka); if (index < polozky.Count - 1) vybranaPolozka = polozky[index + 1]; else vybranaPolozka = polozky[0]; }
Metoda pro výběr předchozí položky bude obdobná:
public void VyberPredchozi() { int index = polozky.IndexOf(vybranaPolozka); if (index > 0) vybranaPolozka = polozky[index - 1]; else vybranaPolozka = polozky[polozky.Count - 1]; }
Obsluha položek
Obsluhu položek nastavíme na klávesy dolů a nahoru. Budeme tak přepínat
další a předchozí položku. Přesuňme se do Update() a dodejme
reakci na tyto klávesy:
// reakce na klávesy if (hra.NovaKlavesa(Keys.Up)) VyberPredchozi(); if (hra.NovaKlavesa(Keys.Down)) VyberDalsi();
Vykreslení položek
Protože u položek budeme potřebovat specifikovat i velikost, nevystačíme
si s naší metodou TextSeStinem(). Proto si třídu
LepsiSpriteBatch obohatíme o další metodu, která vykreslí
škálovaný text se stínem pomocí dalšího přetížení metody
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); }
Nyní už je pro nás hračka vykreslit 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();
Zde je závislost na font fontBlox ze hry.
Ideálně bychom měli umožnit font předat, ale kvůli tomu, že font existuje
až po volání LoadContent() by se nám práce zkomplikovala a
proto toto zanedbáme.
Vložení komponent do sebe
Komponentu KomponentaPolozkyMenu nyní vložíme do komponenty
KomponentaMenu. Takto jsme do sebe komponenty ještě nevkládali,
pojďme si to vyzkoušet. Přesuňme se do KomponentaMenu.cs, kde
přidejme atribut s instancí komponenty KomponentaPolozkyMenu:
private KomponentaPolozkyMenu polozkyMenu;
Samotnou instanci si však vytvoříme v Hra.cs (protože zde
potřebujeme komponentu přidat do obrazovky). Šlo by to samozřejmě navrhnout
i jinak, ale preferujme jednoduchost. Do KomponentaMenu instanci
dostaneme konstruktorem, který modifikujeme:
public KomponentaMenu(Hra hra, KomponentaPolozkyMenu polozkyMenu) : base(hra) { this.hra = hra; this.polozkyMenu = polozkyMenu; }
Přesuňme se do Hra.cs a v Initialize() a
přidejme vytvoření instance komponenty
KomponentaPolozkyMenu:
KomponentaPolozkyMenu polozkyMenu = new KomponentaPolozkyMenu(this, new Vector2(700, 250), Color.Red, Color.Yellow, 80);
A za ní rovnou přidání několika položek do menu:
polozkyMenu.PridejPolozku("StArT"); polozkyMenu.PridejPolozku("SkOrE"); polozkyMenu.PridejPolozku("AuToRi"); polozkyMenu.PridejPolozku("KoNeC");
Střídám v názvu položek velká a malá písmena, protože to s fontem
Blox vypadá dobře 
Do volání konstruktoru KomponentaMenu doplníme instanci
polozkyMenu.
KomponentaMenu menu = new KomponentaMenu(this, polozkyMenu);
A stejně tak ji dodáme i do vytváření obrazovky
obrazovkaMenu:
obrazovkaMenu = new HerniObrazovka(this, mraky, menu, polozkyMenu);
Otevřete si font_blox.spritefont ve složce Fonty/
a změňte Style z Regular na Bold. Projekt spustíme, měli byste dospět
takovéhoto výsledku:

Vidíme, že i přepínání položek funguje dobře.
Příště, v lekci MonoGame: Skrolující text (autoři hry), zprovozníme klikání na položky a vytvoříme si obrazovku autoři se skrolujícím textem.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 332x (13.21 MB)
Aplikace je včetně zdrojových kódů v jazyce C#

David se informační technologie naučil na