játékfejlesztés.hu
FórumGarázsprojectekCikkekSegédletekJf.hu versenyekKapcsolatokEgyebek
Legaktívabb fórumozók:
Asylum:    5448
FZoli:    4892
Kuz:    4455
gaborlabor:    4449
kicsy:    4304
TPG:    3402
monostoria:    3284
DMG:    3172
HomeGnome:    2919
Matzi:    2520

Pretender:    2498
szeki:    2440
Seeting:    2306
Geri:    2188
Orphy:    1893
Joga:    1791
Bacce:    1783
MaNiAc:    1735
ddbwo:    1625
syam:    1491
Xna 03 2010.10.25 14:19


Üdv!

Képek kirajzolása előtt szükség van egy kis kitérőre.

Screen manager

Egy játék ún. screenekből ("képernyőkből") áll. Próbáltam minél jobban leegyszerűsíteni: úgy kell elképzelni, mint külön álló lapokat, amiket egymásra tudunk helyezni, és mindig csak a legfelsőt látjuk, és tudjuk levenni. Ez nekünk azt jelenti, hogy egyszerre egy screent frissítünk és rajzolunk csak ki.

A Screen osztály

Szükségünk lesz egy osztályra, amiből örököltetni fogjuk a többi screen-t (pl. Gameplay, Options, MainMenu, stb.). Az előző leckében találkoztunk a "virtual" metódussal. Most egy ehhez hasonlót fogunk használni, azzal a különbséggel, hogy itt kötelezően meg kell valósítanunk az adott metódust. Ez nem más, mint az "abstract", azonban abstract metódus csak abstract osztályban lehetséges. Hozzunk létre egy új osztályt Screen néven, és a publikussága mellett legyen abstract.
Kód:
public abstract class Screen
{
}

Szükségünk lesz továbbra egy "hivatkozásra" a Game osztályra. Figyelem: a mi saját Game osztályunk kell, nem a Microsoft.Xna.Framework.Game!
Kód:
private Game m_Game;

Amit szeretnénk, hogy olvasni tudjunk akár kívülről is:
Kód:
public Game Game
{
    get { return m_Game; }
}

Jöhet a konstruktor, ahol majd "átadjuk" a Game-t
Kód:
public Screen(Game p_Game)
{
    m_Game = p_Game;
}

Mit is kell csinálnia egy screen-nek? Szükségünk lesz Load, Unload, Update és Draw metódusokra. Az abstract metódusokat nem lehet megvalósítani az ősosztályban!
Kód:
public abstract void Load();
public abstract void Unload();
public abstract void Update();
public abstract void Draw();


A Screen manager osztály

Mint mondtam úgy kell elképzelni, mint egy listát. A különbség az, hogy itt mindig csak a legfelső elemmel tudunk műveletet végrehajtani. Készítsünk egy új osztályt ScreenManager néven. Itt is szükségünk lesz a Game-re, így ennek megfelelően készítsük el a konstruktort is!
Kód:
private Game m_Game;

public ScreenManager(Game p_Game)
{
    m_Game = p_Game;
}

Kellene továbbá maga a "lista", amihez nem a generikus List-t fogjuk használni, hanem a Stack-t. A különbség annyi, hogy nem kérhetjük el, vagy vehetjük ki csak a legfelső elemet. (elkérni: Peek(), hozzáadni: Push(T), kivenni Pop())
Kód:
private Stack<Screen> m_Screens;

A kostruktorban pedig:
Kód:
m_Screens = new Stack<Screen>();

Ez lesz a Screen-jeink gyűjteménye. Kell még néhány metódus: hozzá kell tudni adni, levenni a legfelsőt (esetleg kivenni mindet), szintén frissíteni, és rajzolni.
A hozzáadás a következőképpen néz ki:
Kód:
public void AddScreen(Screen p_Screen)
{
    m_Screens.Push(p_Screen);
    m_Screens.Peek().Load();
}

A metóduson belüli első sor adja hozzá magát a screent a listához, az utána lévő pedig lekéri az utolsó elemet, és meghívja annak a Load-ját. A remove hasonlóan néz ki, csak ott nyilván előbb kell meghívni az Unload-ot:
Kód:
public void RemoveLastScreen()
{
    m_Screens.Peek().Unload();
    m_Screens.Pop();
}

Kell még az Update és a Draw, amit a Game osztályon belül fogunk meghívni. Csak a legfelül lévő screent kell frissítani, és kirajzolni, így:
Kód:
public void Update()
{
    if (m_Screens.Count > 0)
        m_Screens.Peek().Update();
}

public void Draw()
{
    if (m_Screens.Count > 0)
        m_Screens.Peek().Draw();
}

Az ellenőrzést kivehetjük, ha biztosak vagyunk benne, hogy nem fog olyan eset előfordulni, hogy 0db screen lesz a stack-ben.
Ez a nagyon egyszerű screen manager lényegében ennyi lenne, nézzük hogy fogjuk használni:
Kell maga a screen manager, és egy start screen változó is, mégpedig a következő miatt: amikor a Program.cs-ben meghívjuk a game.Run()-t, akkor az meghívja a maga kis Initialize, LoadContent metódusait, azután belefut egy while ciklusba, amiből csak a program bezárásakor lép ki, így a game.Run() után írottak csak ekkor érvényesülnének. A game.Run() előtt pedig azért nem mondhatjuk, hogy screenManager.AddScreen(Screen), mert akkor még nincs device és content manager sem. Szeretnénk, ha a ScreenManager-t látnánk kívülről is, a StartScreen-t pedig állítani is szeretnénk.
Kód:
protected ScreenManager m_ScreenManager;
protected Screen m_StartScreen;

public ScreenManager ScreenManager
{
    get { return m_ScreenManager; }
}
public Screen SetStartScreen
{
    get { return m_StartScreen; }
    set { m_StartScreen = value; }
}

Az Initialize metódusban (mondjuk az Input után) hozzuk létre:
Kód:
m_ScreenManager = new ScreenManager(this);

A base.Initialize() után pedig egy feltételvizsgálattal adjuk hozzá a startscreent. (szintén nem kötelező a feltételvizsgálat, ha biztosak vagyunk benne, hogy lesz "start screen")
Kód:
if (m_StartScreen != null)
    m_ScreenManager.AddScreen(m_StartScreen);

Kell még nekünk az Update és a Draw. Ezeket a megfelelő helyeken hívjuk meg. Update-t az m_Input.Update() után, Draw-t a Clear után (de mindkettőt még a base.Update() előtt)
Kód:
m_ScreenManager.Update();
m_ScreenManager.Draw();


A game projecten belül

Mi egyelőre egy Gameplay screent fogunk csak használni. Készítsük el az SGameplay publikus osztályt a Screen-ből örököltetve.
Kód:
public class SGameplay : Screen
{
}

Amikor beírtuk a "Screen"-t, megjelenik a szöveg bal alsó sarkában egy kis téglalap. Arra ha rákattintunk, majd a feliratra ("Implement abstract class 'Screen' "), akkor az az abstract metódusokat létre is hozza nekünk. A bennük található sorokat töröljük ki! Kelleni fog még egy paraméteres konstruktor is.
Kód:
public SGameplay(Game p_Game) : base(p_Game)
{
}

Ebben az osztályban fogjuk megvalósítani magát a játékmenetet. A Program.cs-n belül a game.Run() előtt írjük be a következő sort:
Kód:
game.SetStartScreen = new SGameplay(game);

Amivel megadtuk a game-nek, hogy melyik screennel szeretnénk indítani. Hogy tapasztaljuk is a hatást, az SGameplay osztály Update metódusába írjuk be a következő sorokat:
Kód:
if (Game.Input.KeyIsPressed(Keys.Escape))
    Game.Exit();

Ha lenyomjuk az ESC-t, ki fog lépni. Próbáljuk ki!

A következő lecke mostmár tényleg a sprite-okról fog szólni!:) Várom a kérdéseket, hozzászólásokat!

Üdv,
Pretender

Értékelés: 0

Új hozzászólás
Nincs megjegyzés