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#