Vediamo adesso di disegnare il nostro gioco a schermo. Anche in questo caso, e sempre per finalità puramente illustrative, ci siamo presi la libertà di apportare alcune semplificazioni che normalmente dovrebbero essere evitate in un gioco vero e proprio. Prima di procedere, però, ci servono ancora un paio di cose:
La prima è, ovviamente, il nostro SpriteBatch, incluso di default in ogni template di XNA:
SpriteBatch spriteBatch;
Sempre a livello di classe, dichiariamo una variabile intera per memorizzare la posizione del background:
int background_y = 0;
Il gioco è a scorrimento verticale, per dare la sensazione di movimento è necessario che lo sfondo scorra dall'alto verso il basso senza soluzione di continuità. Per ottenere questo effetto è possibile utilizzre un piccolo "escamotage", disegnando la relativa texture due volte, una volta di seguito all'altra, per dare l'impressione di continuità. Bisogna poi riportare la posizione di ciascuna texture ai valori iniziali quando esce dallo schermo (altrimenti la texture, scorrendo verso il basso, lascerebbe parte del fondale "scoperto"):
Per prima cosa, nel metodo Update
aggiorniamo la posizione del background facendolo scorrere verso il basso, e usiamo la proprietà Viewport del GraphicsDevice per assicurarci che, una volta che la texture abbia raggiunto il margine inferiore dello schermo, torni nella posizione iniziale:
background_y += 5;
background_y %= GraphicsDevice.Viewport.Height;
Ora siamo finalmente pronti per disegnare. Cominciamo con l'indispensabile
spriteBatch.Begin();
e disegnamo la nostra texture di background (b1_stars
) per due volte, una di seguito all'altra a una distanza pari all'altezza della texture medesima:
var background = Content.Load("b1_stars");
var viewport = GraphicsDevice.Viewport;
spriteBatch.Draw(background, new Rectangle(0, background_y, viewport.Width, viewport.Height), Color.White);
spriteBatch.Draw(background, new Rectangle(0, background_y - viewport.Height, viewport.Width,
viewport.Height), Color.White);
A questo punto, possiamo disegnare lo sprite del giocatore, a meno che il gioco non sia terminato:
if (!game_over)
spriteBatch.Draw(player.Texture, playerPosition, Color.White);
Per quanto riguarda invece gli asteroidi, possiamo continuare a disegnarli anche se il gioco è finito, giusto per dare un effetto tipico da "coin-up" al nostro semplice demo. In questo modo continueranno a "cadere" anche se il gioco è finito, fintantoché il giocatore non decida di inizare una nuova partita
foreach (var asteroidPosition in asteroidPositions)
spriteBatch.Draw(asteroid.Texture, asteroidPosition, Color.White);
Infine, preoccupiamoci delle scritte. Per farlo, anziché ricorrere direttamente al classico metodo SpriteBatch.DrawString, ci serviremo di un helper (DrawStringCentered
) per disegnare una stringa che sia sempre centrata, orizzontalmente e verticalmente, rispetto ad un punto p passato come parametro.
private void DrawStringCentered(Vector2 p, string text, SpriteFont font)
{
var size = font.MeasureString(text);
p -= size * 0.5f;
spriteBatch.DrawString(font, text, p, Color.Yellow);
}
Per disegnare il punteggio, è ora sufficiente richiamare nel nostro metodo principale Draw il suddetto helper, passandogli come parametri la posizione in cui scrivere, il punteggio e il font necessario per disegnare la scritta:
DrawStringCentered(new Vector2(400, 40), "score " + score, Content.Load("large_font"));
Useremo lo stesso metodo anche per disegnare la scritta "Game Over. Tap to restart" al termine del gioco, in modo che il giocatore sappia cosa deve fare per iniziare una nuova partita. Infine, scriveremo i migliori punteggi raggiunti sino a quel momento, salvati nella relativa lista high_scores (ce ne occuperemo a breve):
if (game_over)
{
DrawStringCentered(new Vector2(400, 240), "Game Over", Content.Load<SpriteFont>("large_font"));
DrawStringCentered(new Vector2(400, 280), "(Tap to restart)", Content.Load<SpriteFont>("small_font"));
for (int i = 0; i < high_scores.Count; i++)
{
DrawStringCentered(new Vector2(400, 320 + i * 40), high_scores[i].ToString(), Content.Load<SpriteFont>("small_font"));
}
}
Per concludere, non ci resta che aggiungere l'immancabile
spriteBatch.End();