| Volver al Inicio | Microsoft Student Tech Club: Universidad Libre |
Tutorial de XNA: Mejorando el código para hacerlo más fácilmente de entender
Para agregar un personaje al videojuego requiere poner instrucciones en LoadContent(), Update() y Draw(), el gran problema es que si manejamos una gran cantidad de personajes (sea el protagonista, diversos enemigos, armas, etc..) terminaremos con una gran cantidad de líneas de código en una sola clase que será muy difícil de entender a futuro.
Para resolver el problema, debemos seguir la filosofía de la programación orientada a objetos la cual una de sus directivas es que cada objeto esté separado. Por lo tanto, nuestro personaje tendrá su propia clase que se encargará de cargar las imágenes de la animación, de reaccionar ante las entradas del usuario (teclado, mouse u otro dispositivo para juegos) y de dibujarse en el escenario.
Veamos paso a paso lo que hay que hacerse:
Paso 1: Creamos una nueva clase para nuestro protagonista el cual tendrá el siguiente código
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; using Microsoft.Xna.Framework.Net; using Microsoft.Xna.Framework.Storage; namespace Animacion
{
class Protagonista
{
//Clase principal de donde se obtiene el LoadContent
Game1 ClasePrincipal = null;
//Animaciones
private Texture2D AnimacionCorriendo;
//Total de dibujos que tiene el personaje animado corriendo
int TotalDibujosCorriendo = 10;
int DibujoCorriendoActual = 0;
//Tamaño del rectángulo que muestra un "frame" del personaje animado
int rectPersonajeAncho = 96;
int rectPersonajeAlto = 96;
//Controla el cambio de un "frame" a otro en el tiempo
float CuentaTiempo = 0f;
float CadaCuantoCambia = 100f;
//Rectángulo que ubica que "frame" del archivo .PNG se dibuja
Rectangle rectOrigenPersonaje;
//En que dirección va corriendo el protagonista
SpriteEffects Direccion = SpriteEffects.None;
//Posición del personaje
Vector2 Posicion = new Vector2(0f, 50f);
//Constructor
public Protagonista(Game1 ClasePrincipal)
{
this.ClasePrincipal = ClasePrincipal;
}
//Carga texturas
public void LoadContent()
{
AnimacionCorriendo = ClasePrincipal.Content.Load<Texture2D>("Sprites\\Protagonista\\Correr");
}
public void Actualiza(GameTime gameTime)
{
//Esta es una compilación condicional. El teclado solo es leído si la aplicación ejecuta en un PC
#if !XBOX
//Código para leer el teclado
KeyboardState estadoTeclado = Keyboard.GetState();
//Avanza a la izquierda
if (estadoTeclado.IsKeyDown(Keys.Left))
{
Direccion = SpriteEffects.None; //Protagonista avanza a la izquierda
Posicion.X-=2; //Avanza a la izquierda, obsérvese que se resta en X
}
//Avanza a la derecha
if (estadoTeclado.IsKeyDown(Keys.Right))
{
Direccion = SpriteEffects.FlipHorizontally; //Protagonista avanza a la derecha
Posicion.X += 2; //Avanza a la derecha, obsérvese que se suma en X
}
#endif
//Acumula los milisegundos que lleva ejecutando el juego
CuentaTiempo += (float)gameTime.ElapsedGameTime.TotalMilliseconds;
//Si el acumulado pasa de determinado tiempo
if (CuentaTiempo > CadaCuantoCambia)
{
//Pasa al siguiente "frame"
DibujoCorriendoActual++;
//Se controla no pasarse de todos los "frames" del personaje
if (DibujoCorriendoActual > TotalDibujosCorriendo - 1)
DibujoCorriendoActual = 0;
//Acumulador de tiempo a cero
CuentaTiempo = 0f;
}
//Determina donde ubicar el rectángulo para el siguiente "frame"
rectOrigenPersonaje = new Rectangle(this.DibujoCorriendoActual * this.rectPersonajeAncho, 0, this.rectPersonajeAncho, this.rectPersonajeAlto);
}
public void Dibujar(SpriteBatch TrabajaSprites)
{
/* Los parámetros son:
* 1. Textura a cargar (todo el archivo .png que tiene la animación).
* 2. Posición donde colocar el sprite "animado"
* 3. Rectángulo origen. Carga el "frame" a mostrar que luego es dibujado en el rectángulo destino
* 4. Color de fondo
* 5. Rotación
* 6. Origen
* 7. Escala
* 8. Efecto del sprite. Reflejo horizontal.
* 9. Profundidad en el que se dibuja */
Vector2 Origen = new Vector2(0f, 0f);
TrabajaSprites.Draw(AnimacionCorriendo, Posicion, rectOrigenPersonaje, Color.White, 0.0f, Origen, 1.0f, Direccion, 0.0f);
}
} } |
Paso 2: Esta es la clase principal lo que hace es llamar los diferentes métodos de un objeto de la clase protagonista
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; using Microsoft.Xna.Framework.Net; using Microsoft.Xna.Framework.Storage; namespace Animacion
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
//Protagonista
Protagonista objProtagonista;
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
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);
//Carga texturas del protagonista
objProtagonista = new Protagonista(this);
objProtagonista.LoadContent();
}
/// <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();
//Actualiza el protagonista
objProtagonista.Actualiza(gameTime);
base.Update(gameTime);
}
/// <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.CornflowerBlue);
// TODO: Add your drawing code here
spriteBatch.Begin();
//Dibuja el protagonista
objProtagonista.Dibujar(spriteBatch);
spriteBatch.End(); base.Draw(gameTime);
}
}
}
|
| Volver al Inicio | Célula Microsoft. Universidad Libre |