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é using
y 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 552x (11.85 MB)
Aplikace je včetně zdrojových kódů v jazyce C#