Lekce 3 - Kreslíme a píšeme v MonoGame
V minulé lekci, Vložení obsahu MonoGame hry, jsme si ukázali vložení obsahu MonoGame hry.
Nyní máme tedy vše připraveno k tomu, abychom si práci s obsahem
vyzkoušeli. Pojďme na to 
Načtení obsahu
Obsah musíme nejprve načíst. Již víme, že to se dělá v metodě
LoadContent(). Než se k metodě přesuneme, vytvoříme si
potřebné proměnné. Neanimované sprity se v MonoGame ukládají do datového
typu Texture2D. Pro SpriteFonty máme typ
SpriteFont.
Přidáme tedy proměnné:
private Texture2D kostkyPozadi, mraky, pozadi; public SpriteFont fontCourierNew, fontBlox, fontBloxMaly;
S modifikátory přístupu si nelamte hlavu, hudba a fonty jsou veřejné, protože je budeme v budoucnu sdílet mezi komponentami.
Přesuňme se konečně do metody LoadContent(). Za vytvořením
instance spriteBatch začneme načítat obsah. Již víme, že k
tomu použijeme vlastnost Content, přesněji Load().
Metoda je generická, musíme tedy specifikovat typ obsahu, který načítáme.
Zajímavé je, že nezadáváme příponu souboru. Načtěme sprity:
pozadi = Content.Load<Texture2D>(@"Sprity\pozadi_level"); kostkyPozadi = Content.Load<Texture2D>(@"Sprity\pozadi_kostky"); mraky = Content.Load<Texture2D>(@"Sprity\spr_mraky");
A fonty:
fontCourierNew = Content.Load<SpriteFont>(@"Fonty\font_courier_new"); fontBlox = Content.Load<SpriteFont>(@"Fonty\font_blox"); fontBloxMaly = Content.Load<SpriteFont>(@"Fonty\font_blox_maly");
Máme načteno, nebyla to žádná věda. Pojďme kreslit.
Vykreslování spritů
Přesuňme se do metody Draw(). Kód budeme psát za vymazání
zobrazovacího zařízení. Již jsme si říkali, že vykreslování spritů
probíhá pomocí instance spriteBatch. Vykreslování musíme
nejprve zahájit, to uděláme metodou Begin():
spriteBatch.Begin();
Následně vykreslíme sprity. Jistě jste si všimli, že jsou ve formátu PNG. To proto, že PNG obsahuje tzv. alfakanál a umožňuje udělat různé části obrázku různě průhlené. Toho jsem využil a pozadí levelu s robotem je nahoře průhledné. Pod něj vykreslíme pozadí kostek a mezi kostky a robota vykreslíme mraky.
Samotné vykreslení spritu probíhá pomocí metody Draw():
spriteBatch.Draw(kostkyPozadi, new Vector2(0, 0), Color.White); spriteBatch.Draw(mraky, new Vector2(0, 0), Color.White); spriteBatch.Draw(pozadi, new Vector2(0, 0), Color.White);
Vidíme, že první parametr metody je textura k vykreslení. Druhým parametrem je pozice a třetím barva. Metoda má další přetížení, která umožňují např. obrázek roztahovat nebo rotovat, ale ta v našem kurzu nevyužijeme.
Význam textury je jasný. Pozoruhodné může být, že
souřadnice zadáváme pomocí vektoru. Ještě divnější
může být, že to nejsou celá čísla, ale čísla desetinná, přesněji
typu float. S vektory se v MonoGame pracuje proto, že umožňují
velmi jednoduše řešit různé pohyby, směry, úhly, srážky, zjistit
vzdálenost 2 objektů a podobně. My je v tomto seriálu budeme používat jen
jako souřadnice, ale i zde je výhoda, že můžeme objektu např. zadat
reálnou rychlost pohybu místo celočíselné a tuto rychlost ke složkám
vektoru (souřadnicím objektu) přičítat. Barva určuje
obarvení textury, bílá texturu nemění.
Vykreslování nakonec ukončíme metodou End():
spriteBatch.End();
Zkusíme si hru spustit, měli bychom vidět takovýto výsledek:

Díky dodržení pořadí spritů při vykreslení jsou opravdu mraky
vložené mezi 2 pozadí. Ještě u spritů chvilku zůstaneme, zkusíme si
totiž mraky rozpohybovat. Založíme si novou privátní proměnnou
pozice typu Vector2. V Initialize() ji
nastavíme na počátek souřadného systému (levý horní roh obrazovky):
pozice = new Vector2(0, 0);
Nyní změníme řádek s vykreslením mraků. Jako pozici předáme
proměnnou pozice a barvu vynásobíme 0.8f, tím
způsobíme, že mraky budou z 20% průhledné:
spriteBatch.Draw(mraky, pozice, Color.White * 0.8f);
Nyní se mraky vykreslují na pozici, kterou určuje proměnná. V metodě
Update() složku vektoru X vždy o 1
snížíme:
pozice.X--;
Po posunu ošetříme, zda jsme s mraky nevyjely z obrazovky. To uděláme
tak, že se zeptáme, zda je X mraků menší než -šířka
obrázku mraků. Tu získáme pomocí vlastnosti Width na textuře
mraků:
if (pozice.X < -(mraky.Width)) pozice.X = 0;
Pokud jste postupovali správně, budou mraky jezdit doleva a jakmile vyjedou z obrazovky, vrátí se na startovní pozici.
Nyní změníme vykreslování tak, aby se vykreslovalo několik mraků vedle sebe:
for (int i = 0; i < 6; i++) spriteBatch.Draw(mraky, new Vector2(pozice.X + i * mraky.Width, 0), Color.White * 0.8f);
Dostaneme pěkný efekt nekonečné, plující oblohy:

Působivé, že? 
Změna barvy spritů
Ještě si zkusíme měnit barvu mraků. Budeme jednoduše měnit její jednotlivé složky, určitě víme, že barvy v počítači jsou složeny z červené, zelené a modré složky. Udělat změnu barvy tak, abychom vystřídali celé spektrum je složité a efekt bude velmi podobný tomu, když budeme střídat barev jen několik. Do třídy přidáme 2 další proměnné, změnu a směr:
private int zmena; private int smer;
Proměnná zmena se bude měnit mezi hodnotou 0 -
96, jako kyvadlo. Proměnná smer určuje směr změny
této proměnné, 1 rostoucí, -1 klesající.
V Initialize() nastavíme změnu na 0 a směr na
1, tedy rostoucí.
zmena = 0; smer = 1;
V Update() nyní přičteme směr ke změně. Tím docílíme,
že se bude s kladným směrem zvyšovat a se záporným snižovat. Také změnu
pomocí 2 podmínek udržíme mezi 0 a 96:
zmena += smer; if (zmena >= 96) smer = -1; if (zmena <= 0) smer = 1;
Hotovo. Tento kyvadlový princip si zapamatujte, bude se nám ve hrách
hodit, my ho ještě minimálně 2x použijeme jinde. No a pojďme do metody
Draw(). Tam si před for cyklem založíme proměnnou
barva a změníme její složky pomocí proměnné
zmena, ty můžeme zadat jednoduše v pořadí RGB (červená,
zelená, modrá) do konstruktoru barvy. Poté barvu dosadíme do barvy
vykreslení maraků:
Color barva = new Color(128 + zmena, 255 - zmena, 128 + zmena); for (int i = 0; i < 6; i++) spriteBatch.Draw(mraky, new Vector2(pozice.X + i * mraky.Width, 0), barva * 0.8f);
Červená složka bude mít základ 128 + změna, bude se tedy
měnit mezi 128 - 224. Zelená mezi 255 -
159 a modrá opět 128 - 225. Můžete si
s tím pohrát, ale pozor, aby hodnota nebyla vyšší než 255
nebo nižší než 0. Program by nespadl s chybou, ale barva by se
měnila podivně.
Pro lepší efekt bychom si v praxi uložili několik pěkných barev do pole
a potom na ně přecházeli metodou Lerp(). Mraky by také neměly
být modré, aby to do barvy nezasahovalo. Pro naše účely ukázky nám to
však takto stačí.
Vykreslení textu
Víme, že i text vykreslujeme pomocí SpriteBatch, přesněji
metodou DrawString(). Ta má opět několik přetížení pro text
orotovaný a podobně, ale ta si určitě sami prohlídnete. Přesuňme se do
metody Draw() a přidejme před spriteBatch.End();
následující řádky:
spriteBatch.DrawString(fontBlox, "nadpis velky", new Vector2(100, 100), Color.Yellow); spriteBatch.DrawString(fontBloxMaly, "nadpis maly", new Vector2(100, 180), Color.Yellow); spriteBatch.DrawString(fontCourierNew, "Příliš žluťoučký kůň úpěl ďábelské ódy", new Vector2(100, 240), Color.Red);
Výsledek:

Parametry jsou stejné, jako u spritů, pouze je tu jeden navíc s textem. Nezapomínejte, že font Blox neumí české znaky! Ve fontu Courier je to již v pořádku.
Text může být občas špatně vidět, pokusíme se s tím něco udělat,
vykreslíme pod něj stín. Abychom nemuseli stín kreslit stále znovu a znovu,
uděláme si na text se stínem metodu. No a abychom se procvičili, přidáme
ji přímo do spriteBatch, přesněji SpriteBatch
podědíme.
Přidejte si k projektu Robotris novou třídu s názvem
LepsiSpriteBatch, dědící z SpriteBatch. Nejprve
nahoru přídáme potřebné usingy a třídu opatříme
modifikátorem public:
... using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; namespace Robotris { public class LepsiSpriteBatch : SpriteBatch { ...
Při dědění třídy musíme vytvořit konstruktor (ač prázdný), volající konstruktor třídy nadřazené:
public LepsiSpriteBatch(GraphicsDevice graphicsDevice): base(graphicsDevice) { }
Teď přidáme naši metodu TextSeStinem(), která vykreslí
zadaný text 2x. jednou černě s trochou průhlednosti a kousek doprava dolů a
podruhé normálně, jak jsme zvyklí. Parametry opíšeme z původní metody
DrawString().
public void TextSeStinem(SpriteFont spriteFont, string text, Vector2 position, Color color) { DrawString(spriteFont, text, new Vector2(position.X + 2, position.Y + 2), Color.Black * 0.8f); DrawString(spriteFont, text, position, color); }
Nyní se vrátíme do třídy Hra a změníme typ
SpriteBatch (hned na začátku v definici atributů třídy) na
LepsiSpriteBatch:
LepsiSpriteBatch spriteBatch;
Podobnou změnu uděláme ještě na začátku metody
LoadContent():
spriteBatch = new LepsiSpriteBatch(GraphicsDevice);
V metodě Draw() změníme DrawString() na
TextSeStinem() a spustíme. Mnohem lepší, ne?
Metody ve hře jsou trochu českoanglické, ale v programování to jinak
nejde a alespoň trochu češtiny jsem hře chtěl dodat, když už dělám
české tutoriály
Ti
pokročilí z vás si to mohou psát anglicky.
To by nám ke spritům stačilo.
Příště, v lekci Zvuky, hudba, klávesnice a myš v MonoGame, se podíváme na hudbu, zvukové efekty a reakci na klávesy.
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 553x (11.85 MB)
Aplikace je včetně zdrojových kódů v jazyce C#


David se informační technologie naučil na