1. diel - Štruktúra MonoGame hry
V úvodnom diele o MonoGame sme si urobili úvod do MonoGame a framework sme si nainštalovali. Dnes sa pozrieme na štruktúru MonoGame hry a vyskúšame si úplné základy práce s frameworkom.
Ešte raz upozorňujem, že tento kurz sa venuje výučbe frameworku MonoGame, nie výučbe jazyka C #. Ak C# neovládate, prečítajte si najprv aspoň prvé 2 sekcia C# tutoriálov a potom prácu so súbormi.
MonoGame sme si už nainštalovali minule, spustite si teda Visual Studio a
založme nový projekt MonoGame (MonoGame Cross Platform Desktop Project),
ktorý pomenujeme Robotris
:
Ak vám názov pripomenul Tetris, máte pravdu, celý kurz sa bude točiť okolo tejto hry. Postupne si vytvoríme hru, herné menu, on-line skóre tabuľku a obrazovku s autormi hry. Naučíte sa základy práce s frameworkom a budete potom schopní vytvoriť akúkoľvek vlastnú hru
Štruktúra projektu
MonoGame hra má svoju špecifickú štruktúru. V novom solution nájdeme
zložky x64/
a x86/
, ktoré spolu s so súbormi
*.dylib
zaisťujú chod Cross-Platform, pre náš tutoriál je
dôležitý súbor Game1.cs
, ktorý je samotná MonoGame hra. A
zložka Content/
je tzv. Obsah. Tak MonoGame
(Pôvodne Microsoft v XNA) nazval obrázky, zvuky a hudbu. Práve do tejto
zložky cez MonoGame Pipeline Tool ich budeme pridávať.
Zamerajme sa najprv na triedu Game1.cs
, ktorú nám Visual
Studio vygenerovalo a popíšme si jej kód, ktorý vyzerá nejako takto:
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; namespace Robotris { /// <summary> /// This is the main type for your game. /// </summary> public class Game1 : Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; } /// <summary> /// Allows the game to perform any initialization it needs to before starting to run. /// This is where it can query for any required services and load any non-graphic /// related content. Calling base.Initialize will enumerate through any components /// and initialize them as well. /// </summary> protected override void Initialize() { // TODO: Add your initialization logic here base.Initialize(); } /// <summary> /// LoadContent will be called once per game and is the place to load /// all of your content. /// </summary> protected override void LoadContent() { // Create a new SpriteBatch, which can be used to draw textures. spriteBatch = new SpriteBatch(GraphicsDevice); // TODO: use this.Content to load your game content here } /// <summary> /// UnloadContent will be called once per game and is the place to unload /// game-specific content. /// </summary> protected override void UnloadContent() { // TODO: Unload any non ContentManager content here } /// <summary> /// Allows the game to run logic such as updating the world, /// checking for collisions, gathering input, and playing audio. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> protected override void Update(GameTime gameTime) { if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape)) Exit(); // TODO: Add your update logic here base.Update(gameTime); } /// <summary> /// This is called when the game should draw itself. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); // TODO: Add your drawing code here base.Draw(gameTime); } } }
Menné priestory
Najprv máme deklarácii niekoľkých menných priestorov. Tu si môžeme
všimnúť, že žiadny MonoGame namespace vlastne nie je a že všetko
je z menného priestoru Microsoft.Xna.Framework
. To vďaka
postavenie MonoGame na XNA frameworku a vývojári sa rozhodli zachovať
pôvodný menný priestor. Máme vysvetlené a teraz prejdime k triede
Game1
.
Trieda Game
Triedu premenujeme na Hra
a to tak, že premiestnime kurzor na
Game1
a stlačíme F2, nasledujúci dialóg tiež
potvrdíme. Vidíme, že trieda dedí z
Microsoft.Xna.Framework.Game
.
Máme založené 2 premenné a síce graphics
a
spriteBatch
.
graphics
je typuGraphicsDeviceManager
a poskytuje metódy napr. pre zmenu veľkosti herného okna, prepnutie fullscreen (celoobrazovkového režimu) a podobne.spriteBatch
je inštancia triedySpriteBatch
, ktorá poskytuje funkcionalitu pre prácu so sprity. Máme tu nový termín - Sprite. Sprite (sprajt, sprit) je vlastne obrázok. Ten je kľúčovým prvkom 2D hier, cez sprity sa rieši v podstate všetko od pozadia, cez postavy v hre až po písmo, kde je každé písmeno jeden sprite. Sprity môžu byť aj animované.
Konštruktor a metóda Initialize ()
Prejdime ku konstruktoru. Tu sa inicializuje premenná graphics
a tiež sa nastaví koreňový priečinok pre Content
. Už vieme,
že je to zložka, v ktorej budú naše herné dáta.
Okrem konstruktoru tu máme aj metódu Initialize()
. To môže
byť mätúce a tiež, že je
MonoGame vlastne nijako nehovorí, kedy použiť k inicializácii konštruktor a
kedy metódu Initialize()
.
Rozdiel je v tom, že konštruktor sa volá hneď pri vytvorení hry (alebo herné komponenty, o tých až neskôr) a mal by nastaviť hru alebo komponent tak, aby bola funkčná. To je u hry vždy a preto sem nič už písať nebudeme. Ďalší význam konstruktoru ich na predkladanie závislostí, to spoznáme u komponentov, z ktorých sa hra potom môže skladať.
Metóda Initialize()
potom slúži na načítanie dát, ktoré
nie sú obsah (Content
, teda nie sú sprity, zvuky alebo hudba),
môžu to byť napr. Nejaké súbory máp. Tiež tu prevedieme všetku
inicializácia hry, vytvorenie potrebných objektov, nastavenie premenných na
predvolené hodnoty a podobne.
V Initialize()
máme vložený riadok kódu:
base.Initialize();
Ten sa stará o spustenie metódy Initialize()
na všetkých
komponentoch hry. O komponentoch ale až neskôr. Podobný riadok nájdeme aj v
ďalších metódach triedy.
LoadContent ()
Ďalej máme v triede metódu LoadContent()
, do tej patrí
načítanie obsahu, teda sprites, zvukov a hudby. Vidíme, že sa tu vytvára i
spriteBatch
. Na koniec metódy môžeme písať logiku, ktorú
potrebujeme spustiť až po načítaní obsahu. Napr. nemôžeme v
Initialize()
zistiť výšku fontu, ktorý ešte nie je
načítaný, preto by kód patril do LoadContent()
.
UnloadContent()
sa volá po skončení hry, pretože my budeme
vždy používať Content
(čo je vlastnosť hry, kde je inštancia
ContentManager
), ktorá si uvoľnenie zdrojov rieši sama, nie je
pre nás metóda dôležitá.
Nasledujú 2 najdôležitejšie metódy.
Update ()
Update()
obsahuje real-time logiku, teda všetko, čo sa
spracováva v reálnom čase. Väčšinou je to klávesnica, prípadne myš
alebo iné ovládače, potom kolízie a pohyb objektov v hre. Všeobecne sem
patrí reakcia na nejaké udalosti a posun objektov, prípadne ich animácie.
Metóda sa vykonáva 60x za sekundu. Ak posunieme postavu v tejto metóde o 1,
bude chodiť rovnako rýchlo aj na inak rýchlom počítači. Iný interval
môžeme nastaviť ako desatinné číslo menšie ako 1 pomocou vlastnosti hry
TargetElapsedTime
, ale to nebudeme potrebovať. Dôležité je
vedieť, že MonoGame za nás bude samo robiť optimalizácia aj keď počítač
nebude hru stíhať a to tak, že bude vynechávať vykresľovanie.
V parametri metódy dostaneme instaci GameTime
. Tu je uložený
herný čas, nájdeme na ňom 2 užitočné vlastnosti:
ElapsedGameTime
-TimeSpan
s časom uběhnutým od posledného update.TotalGameTime
-TimeSpan
s celkovým časom behu hry.
Vďaka týmto hodnotám môžeme v Update pracovať s reálnym časom, urobiť niečo treba každú sekundu, minútu a podobne. Všetko si ukážeme počas seriálu.
Ďalšia vlastnosť na gameTime
je IsRunningSlowly
,
tá je true
, ak sa hra "seká" a MonoGame vynecháva
vykresľovanie. Môžeme tak na túto situáciu reagovať, ale my takto
náročné hry zatiaľ vytvárať nebudeme
V metóde je už doplnená jedna reakcia na tlačidlo Späť na gamepadu,
ktoré ukončí hru. To je dôležitý kód preto, aby išla hra ukončiť na
Xboxe, keby sme ju tam chceli nahrať. Okrem iného vidíme, že ukončenie hry
sa vykoná pomocou metódy Exit()
.
Draw ()
Draw()
sa stará o vykreslenie hry (ako už názov napovedá).
Vykresľovanie prebieha volaním metód na inštanciu SpriteBatch
.
Grafické zariadenie musíme pred každým snímkou (frame) vymazať, aby na
ňom nezostali vykreslené objekty z minula. Toho je docielené metódou
Clear()
a modrou farbou (na farbe vlastne nazáleží, pokiaľ bude
mať hra pozadie). Stretávame sa tu so štruktúrou Color
, tá v
MonoGame slúži na ukladanie farieb. Má na sebe niekoľko statických metód,
ktoré navráti jej inštanciu nastavenú na určitú farbu.
Herné slučka
Je dôležité vedieť, ako vo vnútri hra pracuje. Herný metódy sa volajú v tzv. Hernej slučke a to v tomto poradí:
Initialize()
LoadContent()
Update()
Draw()
UnloadContent()
Update()
a Draw()
sa stále opakujú, až kým nie
je hra ukončená. Cyklus znázornený pomocou vývojového diagramu by vyzeral
takto:
Nabudúce, v lekcii Vloženie obsahu MonoGame hry , si do projektu vložíme sprity, fonty, zvuky a hudbu, pôjde teda o vloženie obsahu
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é 357x (29.14 kB)
Aplikácia je vrátane zdrojových kódov v jazyku C#