Nello sviluppare un videogioco ci sono alcune tecniche che è consigliabile utilizzare, come ad esempio mantenere tutta la logica del gioco in una classe dedicata. Questa classe si occuperà principalmente di gestire il game loop (ovvero le operazioni che vengono eseguite ad ogni "frame" del gioco), il salvataggio dei punteggi, la gestione delle opzioni etc.
Creiamo quindi la nostra classe dove implementeremo il game loop e tutte le funzioni del gioco. Per fare ciò clicchiamo sempre con il tasto destro sul progetto, selezionando questa volta Aggiungi > Classe...
e chiamiamo la nostra nuova classe GameModel.cs
.
Visual Studio ci mostra subito il contenuto della classe appena creata, dove troviamo già i principali namespace (System
, System.Collection
, etc.). Noi però abbiamo bisogno di utilizzare nel seguito le classi della libreria MMGameLibrary2D
oltre ad alcuni oggetti dei namespace Foundation
, Animations
e Imaging
, pertanto dobbiamo includere altri riferimenti oltre a quelli già inseriti da Visual Studio, e lo facciamo semplicemente aggiungendo queste righe di codice alla fine dell'elenco dei namespace:
Come è noto a molti, questa semplice operazione ci permette di utilizzare le classi di questi namespace senza doverli specificare ogni volta anteponendoli agli oggetti ed ai metodi.
Iniziamo quindi con il dichiarare alcuni oggetti che ci serviranno per implementare la logica del gioco. Avremo bisogno di:
- un timer per gestire il game loop ed a questo scopo utilizzeremo il timer dell'oggetto Storyboard;
- una variabile per identificare in che stato si trova il gioco (fermo, attivo o in pausa);
- un oggetto di tipo ScrollableBackground che si occuperà di gestire lo sfondo con lo scroll e che conterrà tutti gli oggetti di tipo Sprite (personaggi e nemici) che utilizzeremo in seguito.
Aggiungiamo quindi queste dichiarazioni a livello di classe:
namespace SampleGam
{
class GameModel
{
private ScrollableBackground _gameBackground;
private StoryBoard GameloopStoryBoard;
private enGameState _gameState;
public enum enGamState;
{
PLAY = 1,
PAUSE = 2,
STOP = 3
};
Alcune variabili iniziano con l'underscore ( _
), perché per queste variabili private creeremo delle apposite proprietà per potervi accedere dall'esterno della classe. Aggiungiamo quindi il codice per le proprietà:
public ScrollableBackground GameBackground
{
get { return _gameBackground; }
set { _gameBackground = value; }
}
public enGameState GameState
{
get { return _gameState; }
set { _gameState = value; }
}
Definire il loop
Prima di definire il costruttore che inizializzerà i comportamenti del gioco, creiamo velocemente la funzione GameLoop
(anche se vuota), per evitare che Visual Studio segnali un errore sulla riga in cui la utilizzeremo. Quindi aggiungiamo questo codice in fondo alla classe:
private void GameLoop(Object sender, Object e) { }
Il costruttore
Una volta create le nostre proprietà, passiamo alla creazione del costruttore della classe, dove metteremo il codice che vogliamo venga eseguito ogni volta che si crea una nuova istanza della classe stessa. In questa routine:
- istanziamo il timer del GameLoop;
- inizializziamo lo sfondo del gioco caricando gli appositi assets.
Il costruttore si chiama come la classe quindi aggiungiamo la nostra funzione GameModel
:
public GameModel()
{
// inizializza il timer per il gameloop
GameloopStoryboard = new Storyboard();
GameloopStoryboard.Duration = TimeSpan.FromMilliseconds(0);
// imposta il delegato per l'evento Completed dell'oggetto StoryBoard
GameloopStoryboard.Completed += GameLoop;
// inizializza l'oggetto ScrollableBackground con le dimensioni iniziali
// e lo scorrimento da destra verso sinistra
_gameBackground = new ScrollableBackground(1366, 768,
ScrollableBackground.enScrollDirection.RightToLeft);
// imposta la gestione delle collisioni automatiche
// perché l'oggetto generi un evento ad ogni collisione
_gameBackground.CollisionDetectionLevel = ScrollableBackground.enCollisionDetectionLevel.AUTO_ADVANCED;
// crea il layer per il cielo e lo aggiunge all'istanza del backgound
BitmapImage bi = new BitmapImage( new Uri("ms-appx:///Assets/Images/sky.jpg"));
BackgoundLayer bl = new BakgroundLayer(new Point(0, 0), 1366, 768, bi);
bl.Key = "mountains";
_gameBackground.AddLayer(bl);
// crea il layer per le colline e lo aggiunge all'istanza del background
bi = new BitmapImage( new Uri("ms-appx:///Assets/Images/hills.jpg"));
bl = new BakgroundLayer(new Point(0, 0), 1366, 768, bi);
bl.Key = "hills";
_gameBackground.AddLayer(bl);
}
Analizzando il codice vediamo che viene istanziato un nuovo oggetto Storyboard e viene impostata la durata a 0 millisecondi; questo perché vogliamo che il GameLoop si ripeta continuamente.
Poi viene impostato come delegato per l'evento Completed
dello Storyboard proprio la funzione GameLoop, poiché in questo modo possiamo eseguire tutte le operazioni che ci servono ad ogni loop, prima di far ripartire di nuovo il timer (vedremo in seguito l'implementazione della funzione GameLoop).
Dopodiché viene creato un nuovo oggetto ScrollableBackground
, che fungerà da "contenitore" per tutti gli elementi del gioco e si occuperà di gestire autonomamente lo scroll del background (in questo caso è dimensionato a 1366x768
e sposta lo sfondo da destra verso sinistra). Infine vengono creati tanti oggetti di tipo BackgroundLayer
quanti sono i livelli di parallasse che vogliamo aggiungere al background; ognuno di questi layer contiene l'immagine del proprio livello.
Siamo quasi pronti per iniziare a vedere come si presenta lo sfondo del nostro gioco. Ci mancano solo un paio di cose da aggiungere nella pagina iniziale, che nel nostro caso è MainPage.xaml