Introduzione
Continua il percorso formativo sulla creazione di un video gioco completo in XNA, in questa parte vedremo come rendere l’astronave animata, tramite l’effetto di spostamento.
In particolare, vedremo come la parte grafica relativa al fuoco del carburante, cambia forma, permettendo un effetto di oggetto in movimento.
Prima di tutto bisogna creare un immagine, composta da tante immagine, una serie di frame, il tutto come mostrato in figura 1.
Figura 1
Il gioco che andremo a creare è come illustrato in figura 2, la stessa navicella della prima parte, ma con effetto animazione.
Figura 2
Creazione del gioco
Riprendendo il tutorial della prima parte, aggiungiamo una nuova classe, denominata animazione.
Dalla finestra di Esplora soluzione, facciamo click con il tasto destro del mouse, sul nome del progetto, e selezioniamo nuova classe.
La classe la chiamiamo Animazione (file Animazione.cs).
In questa classe abbiamo membri e proprietà per la gestione delle singole immagini (frame) i tempi per la visualizzazione, ed il posizionamento.
I metodi della classe, gestiscono varie attività, una permette di impostare i valori delle varie variabili (metodo initialize) un metodo per la visualizzazione dell’immagine a video (draw) e l’aggiornamento costante (update).
Qui di seguito si riporta il codice completo di tale classe, commentato.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//Spazio di nomi - textbure2d
using Microsoft.Xna.Framework.Graphics;
//spazio di nomi per il colore e rectangle
using Microsoft.Xna.Framework;
namespace XNATutorial
{
class Animazione
{
// insieme d'immagine animazione
Texture2D textureInsiemeImmagini;
//per la visualizzazione del singolo frame
float scala;
//indica il tempo che è passato
int TempoTrascorso;
//tempo per la visualizzazione di ogni singolo frame
int frameDurata;
// numero dei frame (immagini)
int frameTotali;
//indice del frame corrente da visualizzare
int frameCorrente;
//colore del framew da visualizzare
Color colore;
//area per la visualizzazone dell'immagine
Rectangle areaRect = new Rectangle();
//oggetto per la definizione dell'area di destinazione delle immagini
Rectangle AreaDestinazioneRect = new Rectangle();
//larghezza framew
public int FrameWidth;
//altezzaFrame
public int FrameHeight;
//Stato Attivo Animazione
public bool statoAttivo;
//determina se attivare l'animazione oppure no
public bool AttivaDisattivare;
//posizione
public Vector2 Posizione;
public void Initialize(Texture2D texture, Vector2 posizione, int frameWidth, int frameHeight, int Frametotali, int FrameCorrente, Color Colore, float Scala, bool AttivaDisattiva)
{
//inizializzo i vari oggetti
this.colore = Colore;
this.FrameWidth = frameWidth;
this.FrameHeight = frameHeight;
this.frameTotali = Frametotali;
this.frameDurata = FrameCorrente;
this.scala = Scala;
AttivaDisattivare = AttivaDisattiva;
Posizione = posizione;
textureInsiemeImmagini = texture;
//imposto il tempo delle animazione
TempoTrascorso = 0;
frameCorrente = 0;
//attivo l'animazione
statoAttivo = true;
}
public void Update(GameTime gameTime)
{
//Verifico lo stato attivo se animare o no il game
if (statoAttivo == false)
return;
//aggiorno il tempo trascorso
TempoTrascorso += (int)gameTime.ElapsedGameTime.TotalMilliseconds;
// In caso che ho tempo per il singolo frame è passato, passo all'immagine successiva
if (TempoTrascorso > frameDurata)
{
//passo al frame successivo
frameCorrente++;
// se il frame corrente è la fine di tutto l'insieme lo riporto all'inzio
if (frameCorrente == frameTotali)
{
frameCorrente = 0;
//verifico se attivare o no il games
if (AttivaDisattivare == false)
statoAttivo = false;
}
//reimposto il tempo trascorso per il successivo frame
TempoTrascorso = 0;
}
//ottengo l'area per la visualizzazione delle immagini
areaRect = new Rectangle(frameCorrente * FrameWidth, 0, FrameWidth, FrameHeight);
//imposto l'area per il posizionamento dell'immagine
AreaDestinazioneRect = new Rectangle((int)Posizione.X - (int)(FrameWidth * scala) / 2,
(int)Posizione.Y - (int)(FrameHeight * scala) / 2,
(int)(FrameWidth * scala),
(int)(FrameHeight * scala));
}
//Metodo per visualizzare a video l'immagine
public void Draw(SpriteBatch spriteBatch)
{
//solo nel caso che lo stato è attivo
if (statoAttivo)
{
spriteBatch.Draw(textureInsiemeImmagini, AreaDestinazioneRect, areaRect, colore);
}
}
}
}
Modifica Classe player
Terminata la creazione della classe animazione, passiamo alla classe Player, questa classe, già creata nella prima parte, si aggiunge un oggetto di tipo classe Animazione.
Dichiariamo a livello di classe, un oggetto di tipo “Animazione” relativa alla classe precedente.
Qui di seguito tale dichiarazione.
//oggetto per la classe animazione
public Animazione PlayerAnimazione;
Ridefiniamo le proprietà relativa alla larghezza ed altezza dell’immagine, utilizzando l’oggetto PlayerAnimazione, in questo modo, prenderà i valori relativi ad altezza e larghezza.
Qui di seguito tale modifica.
//larghezza per il posizionamento
public int Width
{
get { return PlayerAnimazione.FrameWidth; }
}
//altezza per il posizionamento
public int Height
{
get { return PlayerAnimazione.FrameHeight; }
}
Il metodo “Initialize”, sostituiamo la dichiarazione dell’oggetto player, con questo nuovo relativo alla classe animazione.
Qui di seguito tale dichiarazione.
// PlayerTexture = texture;
//inizializzo l'oggetto
PlayerAnimazione = animazione;
Modifichiamo il metodo Update, impostando un parametro, relativo ad un oggetto di tipo GameTime, e impostando le proprietà “Posizione” con le nuove informazioni.
Qui di seguito tale modifiche.
public void Update(GameTime gameTime)
{
PlayerAnimazione.Posizione = Posizione;
PlayerAnimazione.Update(gameTime);
}
Modifichiamo il metodo Draw, utilizzando il metodo “Draw” della classe animazione.
Qui di seguito tale modifiche.
public void Draw(SpriteBatch spriteBatch)
{
// spriteBatch.Draw(PlayerTexture, Posizione, null, Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0f);
PlayerAnimazione.Draw(spriteBatch);
}
Si riporta il codice completo della classe Player.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//per la classe texture2d
using Microsoft.Xna.Framework.Graphics;
//per la classe Vector2
using Microsoft.Xna.Framework;
namespace XNATutorial
{
class Player
{
// per gestire l'oggetto
public Texture2D PlayerTexture;
// per la posizione
public Vector2 Posizione;
// stato
public bool StatoAttivo;
// totale carburante
public int Carburante;
//oggetto per la classe animazione
public Animazione PlayerAnimazione;
//larghezza per il posizionamento
//commento
//public int Width
//{
// get { return PlayerTexture.Width; }
//}
//larghezza per il posizionamento
public int Width
{
get { return PlayerAnimazione.FrameWidth; }
}
//altezza per il posizionamento
public int Height
{
get { return PlayerAnimazione.FrameHeight; }
}
//altezza per il posizionamento
//public int Height
//{
// get { return PlayerTexture.Height; }
//}
//modifico da Texture2D texture in Animazione animation
public void Initialize(Animazione animazione, Vector2 posizione)
{
// PlayerTexture = texture;
//inizializzo l'oggetto
PlayerAnimazione = animazione;
// imposto la posizione
Posizione = posizione;
//imposto lo stato in true quindi attivo
StatoAttivo = true;
//imposto il punteggio
Carburante = 100;
}
//gestione dell'immagine update
public void Update(GameTime gameTime)
{
PlayerAnimazione.Posizione = Posizione;
PlayerAnimazione.Update(gameTime);
}
/// <summary>
/// Funzione che permette di visualizzare a video il risultato
/// </summary>
/// <param name="spriteBatch"></param>
public void Draw(SpriteBatch spriteBatch)
{
// spriteBatch.Draw(PlayerTexture, Posizione, null, Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0f);
PlayerAnimazione.Draw(spriteBatch);
}
}
}
Classe Game1
Passiamo alla classe game1 apportando le modifiche inserendo l'utilizzo della nuova classe.
In esplora soluzione, facciamo click sulla sezione “Content” ed aggiungiamo l’immagine contenente diversi frame della nostra immagine.
Nell’evento LoadContent, scriviamo il codice per il caricamento della nostra immagine.
Il codice crea un oggetto di tipo Animazione, carica l’immagine animata (quella contenente più frame) e tramite il metodo Initialize, imposta i valori per i membri della classe animazione.
Qui di seguito si riporta il codice delle suddette operazioni
//oggetto per la gestione dell'effetto immagini in movimento
Animazione playerAnimazione = new Animazione();
Texture2D playerTexture = Content.Load<Texture2D>("AstronaveMovimento");
playerAnimazione.Initialize(playerTexture, Vector2.Zero, 115, 69, 8, 30, Color.White, 1f, true);
Nel metodo UpdatePlayer, utilizziamo il metodo update, dell’oggetto player con l’oggetto GameTime, qui di seguito si riporta tale dichiarazione.
//passo l'oggetto gametime
player.Update(gameTime);
Qui di seguito si riporta il codice completo della classe Game1.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
namespace XNATutorial
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
//oggetto della classe Player
Player player;
//Per la gestione della tastiera
KeyboardState StatoCorrenteTastiera;
KeyboardState StatoPrecedenteTastiera;
// la velocità di spostamento
float VelocitaSpostamento;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
/// <summary>
/// Allows the game to perform any initialization it needs to before starting to run.
/// This is where it can query for any required services and load any non-graphic
/// related content. Calling base.Initialize will enumerate through any components
/// and initialize them as well.
/// </summary>
protected override void Initialize()
{
// TODO: Add your initialization logic here
// inizializzo la classe
player = new Player();
//imposola velocità
VelocitaSpostamento = 8.0f;
base.Initialize();
}
/// <summary>
/// LoadContent will be called once per game and is the place to load
/// all of your content.
/// </summary>
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
//oggetto per la gestione dell'effetto immagini in movimento
Animazione playerAnimazione = new Animazione();
Texture2D playerTexture = Content.Load<Texture2D>("AstronaveMovimento");
playerAnimazione.Initialize(playerTexture, Vector2.Zero, 115, 69, 8, 30, Color.White, 1f, true);
// carico la risorsa (immagine)
Vector2 playerPosizione = new Vector2(GraphicsDevice.Viewport.TitleSafeArea.X, GraphicsDevice.Viewport.TitleSafeArea.Y + GraphicsDevice.Viewport.TitleSafeArea.Height / 2);
//ricambio l'oggetto player
player.Initialize(playerAnimazione, playerPosizione);
// player.Initialize(Content.Load<Texture2D>("Astronave"), playerPosizione);
// TODO: use this.Content to load your game content here
}
/// <summary>
/// UnloadContent will be called once per game and is the place to unload
/// all content.
/// </summary>
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
/// <summary>
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input, and playing audio.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
// TODO: Add your update logic here
//tasto precedente prima di questa modifica
StatoPrecedenteTastiera = StatoCorrenteTastiera;
//rilevo l'ultimo pulsante digitato
StatoCorrenteTastiera = Keyboard.GetState();
//Update the player
UpdatePlayer(gameTime);
base.Update(gameTime);
}
private void UpdatePlayer(GameTime gameTime)
{
//passo l'oggetto gametime
player.Update(gameTime);
//nel caso che digito il pulsante esc esco dal gioco
if (StatoCorrenteTastiera.IsKeyDown(Keys.Escape))
base.Exit();
//in riferimento alle freccie della tastiera sposto l'astronave
if (StatoCorrenteTastiera.IsKeyDown(Keys.Left) )
{
player.Posizione.X -= VelocitaSpostamento;
}
if (StatoCorrenteTastiera.IsKeyDown(Keys.Right) )
{
player.Posizione.X += VelocitaSpostamento;
}
if (StatoCorrenteTastiera.IsKeyDown(Keys.Up) )
{
player.Posizione.Y -= VelocitaSpostamento;
}
if (StatoCorrenteTastiera.IsKeyDown(Keys.Down) )
{
player.Posizione.Y += VelocitaSpostamento;
}
//imposto la posizione della navicella
player.Posizione.X = MathHelper.Clamp(player.Posizione.X, 0, GraphicsDevice.Viewport.Width - player.Width );
player.Posizione.Y = MathHelper.Clamp(player.Posizione.Y, 0, GraphicsDevice.Viewport.Height - player.Height + 50);
}
/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.White);
// TODO: Add your drawing code here
//ridisegno il tutto
spriteBatch.Begin();
//aggiorno la visualizzazione
player.Draw(spriteBatch);
//termine del ridisegno
spriteBatch.End();
base.Draw(gameTime);
}
}
}
Conclusioni
Ora non ci resta che testare il nostro video gioco, vedremo l’effetto di movimento o meglio la parte relativa al fuoco che cambia.
L’immagine non è delle migliori, naturalmente nelle società informatiche in ogni progetto per la creazione di un video gioco, ci sono varie figure, come grafico, musicista, analista ed altri ruoli. Non avendo valida preprazione in grafica, è tutto quello che sono riuiscito a fare.
Tramite la parola download si può scaricare il progetto della prima e seconda parte.
Download