norberto rojas - xna (el mago)
TRANSCRIPT
Ejemplo en 2D, movimiento, salto y fuego ”El Mago”
Tecnología: XNA Games Studio
Introducción
XNA Game Studio permite a estudiantes y programadores de juegos, crear juegos usando .NET,
para que funcionen en Windows y su Xbox 360. El sistema XNA Framework es el sistema de
bibliotecas de clases de .NET con las cuales los programadores disfrutaran construir sus juegos.
Esta disponible aquí para su descarga gratuita XNA Games Studio
El objetivo fundamental es hacer fácil el desarrollar de los juegos. Usando el XNA Framework los
juegos funcionan en Windows y en Xbox 360. Aun así existen funcionalidades distintas entre una y
otra plataforma pero el objetivo primordial fue unificarlas en la medida de lo posible. De esta
manera podemos resumir que el objetivo principal de XNA que es: “hacer fácil el desarrollo de
video juegos”.
Creación del Proyecto Para Windows
Lo primero que hacemos es cargar el C# Express, para esto damos clic en Inicio->Todos los
Programas -> Microsoft Visual C# 2005 Express Edition aquí nos carga el IDE de C#
Aquí creamos un nuevo proyecto y en la ventana de Nuevo Proyecto seleccionamos la opción de:
Windows Game y lo guardamos como TheWizard.
Vamos a crear una clase que se va a llamar “sprite”, damos clic derecho en el solution explorer a
agregamos clase y después agregar item y lo guardamos como sprite.cs.
Introduciendo Código a la clase sprite
Ahora empecemos rellenando algunas propiedades de la clase. El propósito de la clase es
mantener la información importante sobre los varios sprites usados en un juego, y clasifican según
su tamaño. Para que nosotros empecemos con aquéllos. Agregue las propiedades siguientes a la
clase sprite
private Vector2 mPosition;
public Vector2 Position
{
get
{
return mPosition;
}
set
{
mPosition = value;
}
}
Vector2 mStartPosition;
public Vector2 StartPosition
{
get
{
return mStartPosition;
}
set
{
mStartPosition = value;
}
private int mWidth;
public int Width
{
get
{
return mWidth;
}
set
{
mWidth = value;
}
}
private int mHeight;
public int Height
{
get
{
return mHeight;
}
set
{
mHeight = value;
}
}
Ahora, incluso reforcemos más allá la clase sprite y agregue algunas Propiedades que tratan con la
textura de el sprite.
Unas propiedades más importantes para la clase son Destino y Fuente.
private int mTexturePositionX = 0;
public int TexturePositionX
{
get
{
return mTexturePositionX;
}
set
{
mTexturePositionX = value;
}
}
private int mTexturePositionY = 0;
public int TexturePositionY
{
get
{
return mTexturePositionY;
}
set
{
mTexturePositionY = value;
}
}
private int mTextureWidth = 0;
public int TextureWidth
{
get
{
return mTextureWidth;
}
set
{
mTextureWidth = value;
}
}
private int mTextureHeight = 0;
public int TextureHeight
{
get
{
return mTextureHeight;
}
set
{
mTextureHeight = value;
}
}
public Rectangle Destination
{
get
{
return new Rectangle((int)Position.X,
(int)Position.Y, Width, Height);
}
}
public Rectangle Source
{
get
{
return new Rectangle(TexturePositionX,
TexturePositionY, TextureWidth, TextureHeight);
}
}
Finalmente, nosotros agregaremos al constructor de clase sprite
Cuando una nueva clase sprite se crea, deben proporcionarse dos rectángulos dando la situación
inicial y tamaño del sprite así como el área de la textura inicial a ser desplegada para el sprite.
El proyecto todavía no hace mucho. Nosotros tenemos nuestro proyecto listo y una clase para el
sprite, pero ningún objeto real o algo a ser desplegado. Para remediar, prosigamos y agregamos
nuestra imagen al proyecto para que nosotros podemos empezar haciendo el trabajo un poco más
interesante.
Ahora vamos a crear la clase wizard, en donde se alojara nuestro mago
Para crear la case, damos clic derecho en el Solution Explorer y escogemos Agregar->Clase
después agregamos un nuevo ítem. Le damos el nombre de Wizard
public Sprite(Rectangle theLocationAndSize, Rectangle
theTextureLocationAndSize)
{
Position = new Vector2(theLocationAndSize.X,
theLocationAndSize.Y);
Width = theLocationAndSize.Width;
Height = theLocationAndSize.Height;
TexturePositionX =
theTextureLocationAndSize.X;
TexturePositionY =
theTextureLocationAndSize.Y;
TextureWidth =
theTextureLocationAndSize.Width;
TextureHeight =
theTextureLocationAndSize.Height;
mStartPosition = new
Vector2(theLocationAndSize.X, theLocationAndSize.Y);
}
Agregamos algunos objetos
Nosotros inicializaremos y crearemos estos objetos en el constructor de la clase wizard.
Nosotros expondremos una Actualización y un procedimiento que dibuje dentro de la clase
wizard. Los procedimientos se llamarán de la clase principal poner al actualizar y dibujar el Mago y
sus objetos relacionados cuando sea apropiado.
Nosotros necesitamos poder rastrear los varios estados del Mago.
Los juegos pueden estar en los varios estados (cargando, game over, pausa, etc.) y los personajes
también pueden estar en los varios estados (corriendo, saltando, etc.).
Para empezar rastreando el estado del Mago, nosotros agregaremos un estado enum , una
variable para guardar el estado actual y una Propiedad para recuperar y poner el estado actual del
Mago.
Texture2D mWizardTexture;
Sprite.Sprite mWizard;
Dictionary<string, Sprite.Sprite>mFireballs
= new
Dictionary<string,global::TheWizard.Sprite.
Sprite>();
public Wizard(GraphicsDevice theDevice,
ContentManager theLoader)
{
mWizardTexture =
theLoader.Load<Texture2D>("./Images/WizardSheet") as
Texture2D;
mWizard = new Sprite.Sprite(new
Rectangle(20, 500, 50, 100), new Rectangle(0, 0, 90,
220));
mWizard.Visible = true;
}
public void Draw(SpriteBatch theSpriteBatch)
{
theSpriteBatch.Draw(mWizardTexture,
mWizard.Destination, mWizard.Source, Color.White);
foreach (KeyValuePair<string, Sprite.Sprite>
aFireball in mFireballs)
{
if (aFireball.Value.Visible == true)
{
theSpriteBatch.Draw(mWizardTexture,
aFireball.Value.Destination, aFireball.Value.Source,
Color.White);
}
}
}
Usted puede ver en la propiedad de CurrentWizardState que cuando el estado es el cambiado, hay
código que automáticamente dispara para cambiar algo en el Mago. Ése es uno de los beneficios
de poder rastrear un carácter por su estado.
Ahora que nosotros tenemos el estado del Mago agregado a la clase, prosigamos y empezamos
agregando algunos de esos nuevos procedimientos de actualización que se llamaron en la
Update() antes.
protected enum WizardState
{
Standing,
Walking,
Magicking,
Ducking,
Jumping
}
protected WizardState mWizardState = WizardState.Standing;
protected WizardState CurrentWizardState
{
get
{
return mWizardState;
}
set
{
mWizardState = value;
switch (mWizardState)
{
case WizardState.Standing:
{
mWizard.TexturePositionX = 0;
mWizard.TexturePositionY = 0;
break;
}
case WizardState.Walking:
{
mWizard.TexturePositionX = 0;
mWizard.TexturePositionY = 0;
break;
}
case WizardState.Ducking:
{
mWizard.TexturePositionX = 180;
mWizard.TexturePositionY = 220;
break;
}
case WizardState.Magicking:
{
mWizard.TexturePositionX = 180;
mWizard.TexturePositionY = 0;
AddFireball();
break;
}
}
}
}
Primero, nosotros agregaremos en el UpdateWizard () el procedimiento
Cuando el Mago es actualizado, nosotros haremos un chequeo para ver en qué estado el Mago
esta actualmente. Si él está caminando, entonces nosotros ejecutaremos algún código particular
para llamar el UpdateWizardWalking () y si él está saltando, nosotros ejecutaremos algún código
particular para llamar el UpdateWizardJumping ()
UpdateWizardWalking () cuida de la animación para mover al mago para adelante o hacia atrás
sobre el eje x
protected void UpdateWizard(double elapsed)
{
switch (CurrentWizardState)
{
case WizardState.Walking:
{
UpdateWizardWalking(elapsed);
break;
}
case WizardState.Jumping:
{
UpdateWizardJumping(elapsed);
break;
}
}
}
private double mWizardHeadBobElapsed = 0;
private void UpdateWizardWalking(double elapsed)
{
mWizardHeadBobElapsed += elapsed;
if (mWizardHeadBobElapsed > 0.2)
{
mWizardHeadBobElapsed = 0;
if (mWizard.TexturePositionX == 0)
{
mWizard.TexturePositionX = 90;
}
else
{
mWizard.TexturePositionX = 0;
}
}
switch (mWizard.Direction)
{
case Sprite.Sprite.eDirection.Right:
{
mWizard.Position = new Vector2(mWizard.Position.X + 3,
mWizard.Position.Y);
break;
}
case Sprite.Sprite.eDirection.Left:
{
mWizard.Position = new Vector2(mWizard.Position.X - 3,
mWizard.Position.Y);
break;
}
}
}
UpdateWizardJumping () cuida de cambiar la animación cuando el mago esta saltando y moverlo
de arriba abajo sobre el eje y.
private double mWizardJumpElapsed = 0;
private Sprite.Sprite.eDirection mJumpDirection =
Sprite.Sprite.eDirection.None;
private void UpdateWizardJumping(double elapsed)
{
mWizardJumpElapsed += elapsed;
if (mWizardJumpElapsed < .3)
{
mWizard.TexturePositionX = 0;
mWizard.TexturePositionY = 220;
}
else if (mWizardJumpElapsed < .6)
{
mWizard.TexturePositionX = 90;
MoveWizard(mJumpDirection, 1, Sprite.Sprite.eDirection.Up,
5);
}
else if (mWizardJumpElapsed < .9)
{
MoveWizard(mJumpDirection, 2, Sprite.Sprite.eDirection.Up,
5);
}
else if (mWizardJumpElapsed < 1.2)
{
MoveWizard(mJumpDirection, 2,
Sprite.Sprite.eDirection.Down, 5);
}
else if (mWizardJumpElapsed < 1.5)
{
MoveWizard(mJumpDirection, 1,
Sprite.Sprite.eDirection.Down, 5);
}
else if (mWizardJumpElapsed < 1.8)
{
mWizard.TexturePositionX = 0;
mWizard.TexturePositionY = 220;
}
else
{
mWizardJumpElapsed = 0;
mPreviousKeyPressed = Keys.None;
CurrentWizardState = WizardState.Walking;
}
}
private void MoveWizard(Sprite.Sprite.eDirection theXDirection, int
theXDistance, Sprite.Sprite.eDirection theYDirection, int theYDistance)
{
if (theXDirection == Sprite.Sprite.eDirection.Left)
{
theXDistance *= -1;
}
else if (theXDirection == Sprite.Sprite.eDirection.None)
{
theXDistance = 0;
}
if (theYDirection == Sprite.Sprite.eDirection.Up)
{
theYDistance *= -1;
}
else if (theYDirection == Sprite.Sprite.eDirection.None)
{
theYDistance = 0;
}
mWizard.Position = new Vector2(mWizard.Position.X +
theXDistance, mWizard.Position.Y + theYDistance);
}
Ahora, nosotros necesitamos mover las bolas de fuego a lo largo en la pantalla
Para determinar como mover al Mago alrededor, tenemos que ser capaces de leer las teclas que
están siendo presionadas por el usuario y cambian el estado del Mago de manera apropiada.
Hacemos esto por añadiendo el último de los procedimientos de Actualización y creamos
UpdateKeyboard ()
protected void UpdateFireballs(double elapsed)
{
mFireballElapsed -= elapsed;
if (mFireballElapsed < 0)
{
mFireballElapsed = 0;
}
bool aFireballVisible = false;
foreach (KeyValuePair<string, Sprite.Sprite>
aFireball in mFireballs)
{
if (aFireball.Value.Visible == true)
{
if (aFireball.Value.Position.X >
aFireball.Value.StartPosition.X + 400)
{
aFireball.Value.Visible = false;
}
else
{
aFireball.Value.Position = new
Vector2(aFireball.Value.Position.X + 5,
aFireball.Value.Position.Y);
aFireballVisible = true;
}
}
}
if (aFireballVisible == false)
{
mFireballElapsed = 0;
}
}
Keys mPreviousKeyPressed = Keys.None;
protected void UpdateKeyboard(double elapsed)
{
KeyboardState aKeyboard = Keyboard.GetState();
if (aKeyboard.IsKeyDown(mPreviousKeyPressed) == false &&
CurrentWizardState != WizardState.Jumping)
{
mPreviousKeyPressed = Keys.None;
CurrentWizardState = WizardState.Standing;
if (aKeyboard.IsKeyDown(Keys.Space) == true)
{
mPreviousKeyPressed = Keys.Space;
mFireballElapsed = 0;
CurrentWizardState = WizardState.Magicking;
}
else if (aKeyboard.IsKeyDown(Keys.Up) == true)
{
mJumpDirection = Sprite.Sprite.eDirection.None;
if (aKeyboard.IsKeyDown(Keys.Left) == true)
{
mJumpDirection = Sprite.Sprite.eDirection.Left;
}
else if (aKeyboard.IsKeyDown(Keys.Right) == true)
{
mJumpDirection = Sprite.Sprite.eDirection.Right;
}
mPreviousKeyPressed = Keys.Up;
CurrentWizardState = WizardState.Jumping;
}
else if (aKeyboard.IsKeyDown(Keys.Down) == true)
{
mPreviousKeyPressed = Keys.Down;
CurrentWizardState = WizardState.Ducking;
}
else if (aKeyboard.IsKeyDown(Keys.Left) == true)
{
mWizard.Direction = Sprite.Sprite.eDirection.Left;
mPreviousKeyPressed = Keys.Left;
CurrentWizardState = WizardState.Walking;
}
else if (aKeyboard.IsKeyDown(Keys.Right) == true)
{
mWizard.Direction = Sprite.Sprite.eDirection.Right;
mPreviousKeyPressed = Keys.Right;
CurrentWizardState = WizardState.Walking;
}
}
else if (CurrentWizardState == WizardState.Magicking)
{
CurrentWizardState = WizardState.Magicking;
}
else if (CurrentWizardState != WizardState.Jumping &&
aKeyboard.IsKeyDown(Keys.Up) == true)
{
mJumpDirection = Sprite.Sprite.eDirection.None;
if (aKeyboard.IsKeyDown(Keys.Left) == true)
{
mJumpDirection = Sprite.Sprite.eDirection.Left;
}
else if (aKeyboard.IsKeyDown(Keys.Right) == true)
{
mJumpDirection = Sprite.Sprite.eDirection.Right;
}
mPreviousKeyPressed = Keys.Up;
CurrentWizardState = WizardState.Jumping;
}
}
UpdateKeyboard () hace muchas comprobaciónes suplementarias para no sólo ver que teclas que
están siendo presionadas, si no también para rastrear que teclas han sido presionado antes (la vez
pasada se UpdateKeyboard) y determinar como el Mago debería reaccionar dependiendo(según)
lo que el estado el Mago actualmente está (por ejemplo, el Mago no puede encender una bola de
fuego saltando).
Finalmente, para redondear la clase de Mago, tenemos que añadir nuevas bolas de fuego
private double mFireballElapsed = 0;
protected void AddFireball()
{
if (mFireballElapsed == 0)
{
bool aAddFireball = true;
foreach (KeyValuePair<string, Sprite.Sprite> aFireball in mFireballs)
{
if (aFireball.Value.Visible == false)
{
aFireball.Value.StartPosition = new Vector2(mWizard.Position.X + 30,
mWizard.Position.Y);
aFireball.Value.Position = new Vector2(mWizard.Position.X + 30,
mWizard.Position.Y);
aFireball.Value.Visible = true;
mFireballElapsed = (float)0.5;
aAddFireball = false;
break;
}
}
if (aAddFireball == true)
{
string aKey = "Fireball" + (mFireballs.Count + 1).ToString();
mFireballs.Add(aKey, new Sprite.Sprite(new
Rectangle((int)mWizard.Position.X + 30,
(int)mWizard.Position.Y, 50, 100), new Rectangle(270, 0, 90, 220)));
mFireballs[aKey].Visible = true;
mFireballElapsed = (float)0.5;
}
}
} private double mFireballElapsed = 0;
protected void AddFireball()
{
if (mFireballElapsed == 0)
{
bool aAddFireball = true;
foreach (KeyValuePair<string, Sprite.Sprite> aFireball in mFireballs)
{
if (aFireball.Value.Visible == false)
{
aFireball.Value.StartPosition = new Vector2(mWizard.Position.X +
30, mWizard.Position.Y);
aFireball.Value.Position = new Vector2(mWizard.Position.X + 30,
mWizard.Position.Y);
aFireball.Value.Visible = true;
mFireballElapsed = (float)0.5;
aAddFireball = false;
break;
}
}
if (aAddFireball == true)
{
string aKey = "Fireball" + (mFireballs.Count + 1).ToString();
mFireballs.Add(aKey, new Sprite.Sprite(new
Rectangle((int)mWizard.Position.X + 30,
(int)mWizard.Position.Y, 50, 100), new Rectangle(270, 0, 90, 220)));
mFireballs[aKey].Visible = true;
mFireballElapsed = (float)0.5;
}
}
}
Nosotros necesitamos todavía crear un objeto del Mago en nuestra clase lista principal y llamar a
las demás clases.
Agregando el objeto del Mago a la clase main Game:
Para conseguir el sprite del Mago moviéndose alrededor en la pantalla y haciendo todos sus trucos
usted necesitará crear un nuevo objeto del Mago en la clase game. nosostros agregaremos el
objeto spritebatch para dibujar nuestros sprites a la clase.
SpriteBatch mSpriteBatch;
Wizard mWizard;
Ahora, nosotros agregaremos el código al empezar la función para inicializar nuestros objetos
cuando el juego este iniciando.
protected override void Initialize() {
mSpriteBatch = new SpriteBatch(this.graphics.GraphicsDevice);
ContentManager aLoader = new ContentManager(Services);
mWizard = new Wizard(this.graphics.GraphicsDevice, aLoader);
base.Initialize();
}
En Update, nosotros agregaremos algún código para terminar el juego si presionamos Escape y
para actualizar al mago.
Finalmente, nosotros agregaremos nuestro último pedazo de código para dibujar todo realmente
en la pantalla. En Draw, nosotros agregaremos algún código para empezar dibujando con el
SpriteBatch (recordando poner el SpriteBlendMode a AlphaBlend para que nuestras
transparencias del duende trabajen apropiadamente) y entonces nosotros llamamos a Draw ()
para dibujar al mago y todos es los objetos relacionados.
Y hemos acabado, ahora tenemos un mago que camina, salta y usa sus habilidades misteriosas
creando una poderosa bola de fuego si presionas la barra espaciadora, y se sale de el juego si
presionas escape, es hora de ver como quedo!!!
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back
== ButtonState.Pressed)
this.Exit();
KeyboardState aKeyboard = Keyboard.GetState();
if (aKeyboard.IsKeyDown(Keys.Escape) == true)
{
this.Exit();
}
mWizard.Update(gameTime.ElapsedGameTime.TotalSeconds);
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
mSpriteBatch.Begin(SpriteBlendMode.AlphaBlend);
mWizard.Draw(mSpriteBatch);
mSpriteBatch.End();
base.Draw(gameTime);
}