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 1 - Hra JellyBox v MonoGame - Vykreslení hrací plochy a hráče

V následujicí sérii tutoriálu si uděláme hru, kterou jsem nazval JellyBox a budete v ní jakožto multi-želé muset chytat padajicí želé kostičky. Nebude to tak snadné jak to zní.

Hru píšu v MonoGame, ale prakticky nijak se to neliší od XNA, takže pokud nemáte MonoGame po ruce, tak můžete klidně sáhnout po XNA a vše bude fungovat jak má.

Nejprve si založíme nový projekt ve Visual Studiu, já jsem zvovil MonoGame Windows OpenGL Project. Vygeneruje se nám projekt a můžeme začít tvořit.

Textury

V dnešním díle budeme potřebovat pouze 3 textury a to texturu pozadí, hráče a země po které se bude náš hráč pohybovat.

Textury si nahrajeme do složky Content, která se nám v projektu vygenerovala a odkud je také bude nahrávat.

Zem - Hra JellyBox v MonoGame
Pozadí - Hra JellyBox v MonoGame
Hráč - Hra JellyBox v MonoGame

Vykreslení pozadí a země

Nyní si ve třídě Game1 vytvoříme 2 instance třídy Texture2D pro naše pozadí a zem. Kód bude vypadat následovně.

private Texture2D ground, background;

Jejich inicializaci si zajistíme v metodě LoadContent, kde do nich nahrajeme naše textury.

ground = Content.Load<Texture2D>("ground");
background = Content.Load<Texture2D>("Background");

Je zde výhoda, že za názvy souborů nemusíte psát jejich koncovky jako např. Background.png Tímto by jsme měli naše textury připravené k vykreslení, ale než se k tomu dostaneme, tak si nejprve upravíme velikost hracího okna a přidámě nějaké pomocné metody.

Změníme si velikost hrácího okna a to v konstruktoru Game1. Nastavení provedeme díky zdejšímu GraphicDevice­Manageru. Na jeho instanci je dostupná celá řada šikovných nastavení obrazu, ale my zde využijeme pouze PreferredBackBuf­ferHeight a Width, čímž nastavíme výšku a šířku obrazu.

Já jsem zvolil 800x600, protože používám notebook a nemám velký display, ale můžete si vybrat libovolnou velikost.

graphics.PreferredBackBufferHeight = 600;
graphics.PreferredBackBufferWidth = 800;

Nyní si přidáme 2 metody, které nám budou poskytovat užitečné informace. První metodou bude GetSreenSize, která nám bude vracet 2-složkový vektor složený z šířky a výšky herního okna. Druhá metoda bude GetGroundRect, která nám bude vracet rectangle naší země, což využijeme při testování kolizí.

public Vector2 GetScreenSize()
{
     return new Vector2(graphics.PreferredBackBufferWidth,
          graphics.PreferredBackBufferHeight);
}

public Rectangle GetGroundRect()
{
     return new Rectangle(0, (int)ScreenSize().Y - 150, (int)ground.Width,
          (int)ground.Height);
}

Je dobré myslet při psaní hry trochu dopředu a nějaké věci, jako jsou tyto užitečné metody využívat, ušetříte tím pak hodně zbytečných řádků kódu.

Teď, když už jsme si vše připravili, tak se můžeme vrhnout na samotné vykreslení pozadí a země. Při vykreslování je nutné pamatovat na to, že se vykresluje po "vrstvách", takže záleží na pořadí se kterým vykresluje. Tím je jasné že pozadí bude vždy v pořadí jako první, protože je nežádoucí, aby bylo něco vykresleno za pozadím a tím pádem skryto.

spriteBatch.Begin();

spriteBatch.Draw(background, new Vector2(0, 0), Color.White);
spriteBatch.Draw(ground, GetGroundRect(), Color.White);

spriteBatch.End();

Zde je hned vidět využití jedné z našich metod. Použili jsme ji zde k určení pozice, kde se má textura vykreslit. Teď když si hru zapneme, tak můžeme vidět krásné pozadí a ve spodu obrazovky naši zem. Ale to by toho bylo málo, tak tam ještě přidáme naši postavu.

Vykreslení hráče

Než se pustíme do vykreslí hráče, tak bude třeba vytvořit 2 třídy a to třídu Player, kde bude umístěna logika hráče a třídu GameObejct, která bude základním kamenem všech našich objektů ve hře. Bude poskytovat určité základní metody, které budou všechny objekty sdílet, ale sami uvidíte, že objektových návrh a pěkné rozdělení do tříd jen zpříjemňuje programování a redukuje počet něpotřebných řádků v kódu.

Třídy GameObject a Player

Ve třídě GameObject si instanci třídy Texture2D a instanci třídy Vector2. Pojmenujeme si je texture a position. Tyto 2 proměnné je potřeba nastavit na protected, protože budeme z této třídy dědit.

Ve třídě bude hned několik metod. První metodou je GetPosition, která nám vrací pozici objektu. Druhou metodou je GetTexture, která nám vrátí texturu objektu. Třetí metodou je GetRectangle, která nám vrátí rectangle objektu, což se velice hodí při detekci kolize, kde pak nemusíme zdlouhavně vytvářet nový Rectangle. A poslední metodou je GetSize, která nám vrátí výšku a šířku objektu.

protected Texture2D texture;
protected Vector2 position;

public GameObject(Texture2D texture, Vector2 position)
{
     this.texture = texture;
     this.position = position;
}

public Vector2 GetPosition()
{
     return position;
}

public Texture2D GetTexture()
{
     return texture;
}

public Rectangle GetRectangle()
{
     return new Rectangle((int)position.X, (int)position.Y, (int)texture.Width,
           (int)texture.Height);
}

public Vector2 GetSize()
{
     return new Vector2(texture.Width, texture.Height);
}

Nyní, když máme hotovou třídu GameObject, se můžeme pustit do tvorby třídy Player, kde budeme mít vekreslení hráče, ale i jeho logiku.

Jak jsem již zmiňoval, třída Player bude dědit ze třídy GameObject, protože náš hráč je vlastně herní object (vše co má hmotnou představu a může potencionálně kolidovat bude dědit ze třídy GameObject).

class Player : GameObject

Nyní si ve třídě vytvoříme novou instanci třídy Game1, aby jsme měli dostupné naše pomocné metody. Dále si vytvoříme proměnné Lives, Speed, EatedJellies. Tyto proměnné nastavíme public a budou to vlastnosti. Nechávám je public, protože se pravděpodobně dostaneme k jejich modifikacím a úpravám z venčí a proto bude dobré je mít public.

V konstruktoru nadefinuje vše co je třeba a použijeme klíčové slovo : base, protože dědíme z jiné třídy. Proměnnou EatedJellies nastavíme v konstruktoru na 0, tato proměnná bude zaznamenávat počet sněděných želé.

Dále si vytvoříme metodu Update, Collision a Draw. V metodě Update budeme pohybovat naším hráčem a proto zde využíváme KeyboardState a GameTime. KeyboardState zachytává klávesnici, takže zde máte přístup k metodě IsKeyDown, kterou použijeme. Metodu Collision zatím necháme prázdnou a budeme ji editovat až později. A poslední metoda Draw bude sloužit ke skutečnému vykreslení našeho hráče.

private Game1 game;
public int Lives { get; set; }
public int Speed { get; set; }
public int EatedJellies { get; set; }

public Player(Texture2D texture, Vector2 position, int Lives, int Speed, Game1 game)
    : base(texture, position)
{
    this.texture = texture;
    this.position = position;
    this.Lives = Lives;
    this.Speed = Speed;
    this.game = game;
    EatedJellies = 0;
}

public void Update(KeyboardState ks, GameTime gameTime)
{
    if (ks.IsKeyDown(Keys.Left) && position.X > 0)
        position.X -= Speed;
    else if (ks.IsKeyDown(Keys.Right) && position.X < game.GetScreenSize().X - texture.Width)
        position.X += Speed;
}

public void Collision()
{

}

public void Draw(SpriteBatch spriteBatch)
{
    spriteBatch.Draw(texture, position, Color.White);
}

V metodě Update, pokud je stisknuta klávesa Left nebo Right, posuneme hráče vlevo, nebo naopak, ale zároveň v podmínkách hlídáme to, že hráč nevyjel z hrací plochy. Zde třeba uplatníme metodu GetSreenSize, kterou jsme si vytvořili.

A jako posledních už jen pár změn ve třídě Game1. Kde musíme vytvořit novou instanci třídy Player a vykreslit našeho hráče.

private Player player;

A inicializujeme ho v metodě LoadContent. Tento krok se prakticky nemění.

player = new Player(Content.Load<Texture2D>("player"),
                new Vector2(GetScreenSize().X / 2, GetScreenSize().Y - 200), 5, 5, this);

Nastavíme všechny požadované parametry. Pozice je nastavená tak, aby byl hráč pěkně na vrchu naší země. Ovšem můžete použít metodu GetGroundRect a nastavit Y souřadnici tak, aby jeho pozice ladila s jakýmkoliv rozlišením. Všimněte si na konci metody parametru this, tím předáváme instanci třídy Game1, ve které právě pracujeme.

V metodě Update zavoláme naši metodu Update, kterou jsem u hráče vytvořili.

KeyboardState ks = Keyboard.GetState();

player.Update(ks, gameTime);

Pouze si zde vytvoříme novou instanci KeyboardState, kterou budeme v našem projektu využívat.

A poslední úprava bude v metodě Draw, zde zavoláme pouze metodu Draw, kterou jsme hráčovi přidali.

player.Draw(spriteBatch);

Nyní se nám hráč vesele pohybuje. To je dnes vše.

Příště, Hra JellyBox v MonoGame - Želé a Score, budeme pokračovat v tvorbě naší hry.


 

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

 

Všechny články v sekci
Hra JellyBox v MonoGame
Přeskočit článek
(nedoporučujeme)
Hra JellyBox v MonoGame - Želé a Score
Článek pro vás napsal Jakub Lásko[Saarix]
Avatar
Uživatelské hodnocení:
7 hlasů
Věnuji se programování v C#, MonoGame a Unity.
Aktivity