Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

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:

Robotris, ukázková hra v XNA Game Studio - Od nuly k tetrisu v MonoGame

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:

Robotris, ukázková hra v XNA Game Studio - Od nuly k tetrisu v MonoGame

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:

Robotris, ukázková hra v XNA Game Studio - Od nuly k tetrisu v MonoGame

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

 

Předchozí článek
Vložení obsahu MonoGame hry
Všechny články v sekci
Od nuly k tetrisu v MonoGame
Přeskočit článek
(nedoporučujeme)
Zvuky, hudba, klávesnice a myš v MonoGame
Článek pro vás napsal David Hartinger
Avatar
Uživatelské hodnocení:
14 hlasů
David je zakladatelem ITnetwork a programování se profesionálně věnuje 15 let. Má rád Nirvanu, nemovitosti a svobodu podnikání.
Unicorn university David se informační technologie naučil na Unicorn University - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity