1. díl - Hra JellyBox v MonoGame - Vykreslení hrací plochy a hráče

C# .NET XNA game studio Hra JellyBox 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
Pozadí
Hráč

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 a přístě budeme pokračovat v tvorbě naší hry.


 

Stáhnout

Staženo 221x (1.79 MB)
Aplikace je včetně zdrojových kódů v jazyce C#

 

  Aktivity (1)

Článek pro vás napsal Jakub Lásko[Saarix]
Avatar
Věnuji se programování v C#, MonoGame a Unity.

Jak se ti líbí článek?
Celkem (4 hlasů) :
55555


 


Miniatura
Všechny články v sekci
Hra JellyBox v MonoGame

 

 

Komentáře
Zobrazit starší komentáře (14)

Avatar
KlimiCZ
Člen
Avatar
KlimiCZ:

nwm so se děje ale vůbec mi to nejde spustit ,protože mi to píše že mám mít Program Files (x86) a já mám jen Program Files :(

Editováno 28.10.2013 9:21
Odpovědět 28.10.2013 9:19
Nesnaž se zakrýt něco, co jsi provedl úmyslně. Svět je tak malý, že dotyčný se to stejně dozví.
Avatar
Odpovídá na KlimiCZ
Jakub Lásko[Saarix]:

Hm žádné pevné cesty tam nejsou, ale teoreticky by bylo možné že to jede na 64-bitu. Zatím se ale něco takovýho nedostal, takže si nejsem jistý.

Odpovědět 28.10.2013 9:50
Časem je vše možné.
Avatar
Juraj Mlich
Redaktor
Avatar
Odpovídá na KlimiCZ
Juraj Mlich:

Otvor si súbor tvojho projektu a tam prepíš cestu k SDL.dll

Odpovědět 29.10.2013 16:23
Vždy je lepšie učiť sa z cudzích chýb, než z vlastných chýb.
Avatar
Darken141
Člen
Avatar
Darken141:

Potreboval by som poradit
v program.cs
using (Game1 game = new Game1())
{
game.Run(); // presne tu
}

nonstop pri kompilacii a debuggingu

vyhadzuje chybu: "NullReference­Exception was unhandled
Odkaz na objekt není nastaven na instanci objektu."
absolutne netusim ako sa toho zbavim
tento error hadze aj pri zalozeny cisteho noveho projectu

 
Odpovědět 5.11.2013 19:52
Avatar
Darken141
Člen
Avatar
Darken141:

Fixxed :3 konecne...

 
Odpovědět 5.11.2013 20:21
Avatar
Jan Vargovský
Redaktor
Avatar
Odpovídá na Darken141
Jan Vargovský:

Proč se ta třída jmenuje Game1?

 
Odpovědět 5.11.2013 20:24
Avatar
Darken141
Člen
Avatar
Odpovídá na Jan Vargovský
Darken141:

pretoze ten using bol skopceny a nahradeny z noveho projectu z XNA-cka
ista chyba sa ale samozrejme ukazovala i ked tam bol original

using (var game = new Game1())
game.Run();

nastastie ale v tomto chyba nebola...

 
Odpovědět 5.11.2013 21:18
Avatar
Ondrca
Redaktor
Avatar
Ondrca:

Ahoj, mně to nefunguje a vyhazuje mi to tohle:

An unhandled exception of type 'System.DllNotFoundException' occurred in MonoGame.Framework.dll

Additional information: Knihovnu DLL openal32.dll nelze načíst: Uvedený modul nebyl nalezen. (Výjimka na základě hodnoty HRESULT: 0x8007007E)

Může to být tím, že mám VS 2013?

Odpovědět 16.4.2014 18:06
Zase jsem o něco chytřejší
Avatar
Odpovídá na Ondrca
Jakub Lásko[Saarix]:

Máš tam problém s tou knihovnou, mrkni jestli ji vůbec máš.

Odpovědět  +1 16.4.2014 18:31
Časem je vše možné.
Avatar
Ondrca
Redaktor
Avatar
Odpovědět 16.4.2014 18:35
Zase jsem o něco chytřejší
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 24. Zobrazit vše