UNIVERSIDAD CENTRAL DEL ECUADOR Autor: Morocho Rocha Darwin Santiago
Carrera de Ingeniería en computación Grafica
Física para video juegos con XNA
Tutorial juego 2 cañón que destruye asteroides en XNA Vamos a Visual Studio y creamos un nuevo proyecto Windows Game 4.0
y lo llamaremos Juego_2_nave
No ubicamos en la clase Game1.cs y borramos todos los comentarios innecesarios de modo que nos quede algo parecido a esto
Ahora viene la parte en donde debemos e identificar cuáles serán los gráficos que se mostraran en nuestro juego usaremos las siguientes (puedes descargar las imágenes desde el siguiente link )
para nuestro caso
La primera imagen representa el fondo del nuestro juego es decir el espacio, la segunda representa el cañon de nuestra nave, la tercera seria nuestra nave en donde se situara nuestro cañon, la cuarta seria las balas que dispara nuestro cañon , cuando ya hayamos avanzado en nuestro proyecto tendremos algo como esto
Cuando ya hayamos descargado las imágenes anteriores la vamos a agregar a nuestro proyecto
En nuestro explorador de soluciones deberia tener los siguientes elementos
Ahora
creemos una nueva windowsGameLibrary
Ahora vamos al explorador de soluciones y agregamos esta librería a nuestro proyecto
En nuestra clase Game1.cs escribimos la siguiente
sentencia como se muestra a continuación:
Con la sentencia anterior hemos permitido que desde la clase Game1.cs pueda acceder a todas las clases que vayamos a crear en nuestra WindowsgameLibrary. Es hora de definir nuestra clase que soporta los actores del juego. Los actores (héroe, enemigos, balas) del juego son objetos, por tanto debemos generar una clase que soporte ese tipo de objetos, a la que llamaremos ObjetosJuego.cs Nos ubicamos en el explorador de soluciones y renombramos la clase que se nos creó por defecto en nuestra WindowsGameLibrary 1 y en lugar de class1.cs escribiremos ObjetosJuego.cs presionamos la tecla enter y nos mostrara el siguiente mensaje y le damos en aceptar.
Nuestro juego se trata de una nave espacial con un cañón que destruye asteroides así que ahora vamos a nuestra clase ObjetosJuego.cs y definamos los atributos necesarios para nuestra nave. El siguiente código lo pegamos en nuestra clase ObjetosJuego.cs using using using using using using using using using using using
System; System.Collections.Generic; System.Linq; System.Text; Microsoft.Xna.Framework; Microsoft.Xna.Framework.Audio; Microsoft.Xna.Framework.Content; Microsoft.Xna.Framework.GamerServices; Microsoft.Xna.Framework.Graphics; Microsoft.Xna.Framework.Input; Microsoft.Xna.Framework.Media;
Como se muestra a continuación
justo antes de
namespace WindowsGameLibrary1
En nuestra clase ObjetosJuego definimos los siguientes atributos, el constructor
y los métodos get y set .
private Texture2D sprite; //La textura (o imagen) que tendrá nuestra nave private Vector2 posicion; //En qué punto se encuentra ubicado la nave //Constructor public ObjetosJuego(Texture2D textura) { sprite = textura; //Recibe la textura por parámetro posicion = Vector2.Zero; // Posición [0,0] por defecto } //Leyendo los valores de los atributos public Texture2D getTextura() { return sprite; } public Vector2 getPosicion() { return posicion; } //Dando valores a los atributos public void setTextura(Texture2D Textura) { this.sprite = Textura; } public void setPosicion(Vector2 Posicion) { this.posicion = Posicion; }
Ahora vamos al explorador de soluciones y nos ubicamos en WindowsGameLibrary1 MovimientosCañon.cs
En nuestra nueva clase borramos todo el código y pegamos el siguiente using System; using System.Collections.Generic; using System.Linq; using System.Text; 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 WindowsGameLibrary1 { public class MovimientosCañon { Texture2D Textura;//almacenara la textura de nuestro cañon private Vector2 posicion; //En qué punto se encuentra ubicado el cañon private Vector2 Centro; //El centro por donde gira el cañon private float Rotacion; //Angulo de rotación del cañon //Constructor public MovimientosCañon(Texture2D Textura) { posicion = Vector2.Zero;// posicion por defecto (0,0) this.Textura=Textura;// Rotacion = (float)0.0; //Rotación 0.0 en radianes por defecto Centro = new Vector2(Textura.Width / 2, Textura.Height / 2); //El centro dela textura } //Leyendo los valores de los atributos public Texture2D getTextura() { return Textura; } public Vector2 getPosicion() { return posicion; } public Vector2 getCentro() { return Centro; } public float getRotacion() { return Rotacion; } //Dando valores a los atributos public void setCentro(Vector2 Centro) { this.Centro = Centro; } public void setRotacion(float Rotacion) { this.Rotacion = Rotacion; } public void setPosicion(Vector2 Posicion) { this.posicion = Posicion; } } }
y creamos una nueva clase que la llamaremos
Ahora vamos a probar como esta nuestro juego
para esto vamos a la case Game1.cs
y declaremos las siguientes variables
Texture2D texturaFondo; //Variable de tipo textura2D en la cual cargaremos la imagen espacio.png Texture2D texturaCañon; //Variable de tipo textura2D en la cual cargaremos la imagen cañon.png Texture2D texturaNave; //Variable de tipo textura2D en la cual cargaremos la imagen base.png // necesitamos crear objetos de la clase ObjetosJuego y la clase MovimientosCañon para poder acceder a sus atributos y metodos ObjetosJuego nave; //sera la nave de nuestro juego MovimientosCañon objCañon;//sera El cañon de nuestra nave
Vamos al método LoadContent de la clase Game1.cs y procedemos a cargar nuestras texturas, para eso escribimos el siguiente código justo después de la sentencia spriteBatch = new SpriteBatch(GraphicsDevice); texturaFondo = Content.Load
("espacio");//No es necesaria la extensión .png texturaCañon = Content.Load
("cañon");//No es necesaria la extensión .png texturaNave = Content.Load
("base");//No es necesaria la extensión .png // recordemos que en nuestra clase ObjetosJuego y MovimientosCañon tienen un constructor que recibe como parametro un objeto de tipo Texture2D objCañon = new MovimientosCañon(texturaCañon); //Cargar e inicializar el cañon objCañon.setPosicion(new Vector2(110, 450)); //Posición de nuestro cañon nave = new ObjetosJuego(texturaNave); //Cargar e inicializar la nave nave.setPosicion ( new Vector2(70, 460)); //Posición de la nave espacial en donde se encuentra nuestro cañon
En el método Draw de la clase Game.cs escribimos el siguiente código justo después de la sentencia GraphicsDevice.Clear(Color.CornflowerBlue); spriteBatch.Begin();//comenazmos a dibujar spriteBatch.Draw(texturaFondo, new Rectangle(0, 0, Window.ClientBounds.Width, Window.ClientBounds.Height), Color.White);// dibujamos el fondo /* Dibuja el lanzador como tal, estos son los parámetros * Parámetro 1: El sprite del lanzador * Parámetro 2: La posición del lanzador * Parámetro 3: null porque es solo una imagen (no una sucesión de estas) * Parámetro 4: Color.White, combinación de color * Parámetro 5: Angulo de rotación por defecto * Parámetro 6: Centro, el centro * Parametro 8: Dibujar tal como es el sprite (no reflejo vertical ni horizontal) * Parámetro 9: Ponerlo en la capa superior */ spriteBatch.Draw(objCañon.getTextura(), objCañon.getPosicion(), null, Color.White, objCañon.getRotacion(),objCañon.getCentro(), 1.1f, SpriteEffects.None, 0); spriteBatch.Draw(nave.getTextura(), nave.getPosicion(), Color.White);// dibujamos nuestra nav spriteBatch.End();// finaliza el dibujado
Ahora ejecutemos el juego (presionando la tecla F5)
y observaremos lo siguiente
Hagamos un resumen de todo lo que hay en la clase Game1.cs siguiente
el código que debería estar en su clase Game1.cs debería parecerse al
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 WindowsGameLibrary1; namespace Juego_2_nave { public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; Texture2D texturaFondo; //Variable de tipo textura2D en la cual cargaremos la imagen espacio.png Texture2D texturaCañon; //Variable de tipo textura2D en la cual cargaremos la imagen cañon.png Texture2D texturaNave; //Variable de tipo textura2D en la cual cargaremos la imagen base.png // necesitamos crear objetos de la clase ObjetosJuego y la clase MovimientosCañon para poder acceder a sus atributos y metodos ObjetosJuego nave; //sera la nave de nuestro juego MovimientosCañon objCañon;//sera El cañon de nuestra nave //Almacena el estado anterior del ratón
public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; }
protected override void Initialize() {
base.Initialize(); }
protected override void LoadContent() { spriteBatch = new SpriteBatch(GraphicsDevice); texturaFondo = Content.Load
("espacio");//No es necesaria la extensión .png texturaCañon = Content.Load
("cañon");//No es necesaria la extensión .png texturaNave = Content.Load
("base");//No es necesaria la extensión .png // recordemos que en nuestra clase ObjetosJuego y MovimientosCañon tienen un constructor que recibe como parametro un objeto de tipo Texture2D objCañon = new MovimientosCañon(texturaCañon); //Cargar e inicializar el cañon objCañon.setPosicion(new Vector2(110, 450)); //Posición de nuestro cañon
nave = new ObjetosJuego(texturaNave); //Cargar e inicializar la nave nave.setPosicion ( new Vector2(70, 460)); //Posición de la nave espacial en donde se encuentra nuestro cañon
} protected override void UnloadContent() { }
protected override void Update(GameTime gameTime) { if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); base.Update(gameTime); }
protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); spriteBatch.Begin();//comenazmos a dibujar spriteBatch.Draw(texturaFondo, new Rectangle(0, 0, Window.ClientBounds.Width, Window.ClientBounds.Height), Color.White);// dibujamos el fondo /* Dibuja el lanzador como tal, estos son los parámetros * Parámetro 1: El sprite del lanzador * Parámetro 2: La posición del lanzador * Parámetro 3: null porque es solo una imagen (no una sucesión de estas) * Parámetro 4: Color.White, combinación de color * Parámetro 5: Angulo de rotación por defecto * Parámetro 6: Centro, el centro * Parametro 8: Dibujar tal como es el sprite (no reflejo vertical ni horizontal) * Parámetro 9: Ponerlo en la capa superior */ spriteBatch.Draw(objCañon.getTextura(), objCañon.getPosicion(), null, Color.White, objCañon.getRotacion(),objCañon.getCentro(), 1.1f, SpriteEffects.None, 0); spriteBatch.Draw(nave.getTextura(), nave.getPosicion(), Color.White);// dibujamos nuestra nav spriteBatch.End();// finaliza el dibujado base.Draw(gameTime); } } }
El código que debería estar en su clase ObjetosJuego.cs debería parecerse al siguiente 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 WindowsGameLibrary1 { public class ObjetosJuego { private Texture2D sprite; //La textura (o imagen) que tendrá nuestra nave private Vector2 posicion; //En qué punto se encuentra ubicado la nave //Constructor public ObjetosJuego(Texture2D textura) { sprite = textura; //Recibe la textura por parámetro posicion = Vector2.Zero; // Posición [0,0] por defecto } //Leyendo los valores de los atributos public Texture2D getTextura() { return sprite; } public Vector2 getPosicion() { return posicion; } //Dando valores a los atributos public void setTextura(Texture2D Textura) { this.sprite = Textura; } public void setPosicion(Vector2 Posicion) { this.posicion = Posicion; } } }
Ahora definamos los movimientos que puede hacer nuestro cañon, la idea es que nuestro cañon gire de 0 a 90 grados en el senti do contrario a las manecillas del reloj. Vamos a la clase MovimientosCañon.cs y definimos nuestro método Update el cual será llamado desde la clase Game1.cs public void Update(GameTime gameTime) { KeyboardState estadoTeclado = Keyboard.GetState();// variable que nos permite obtener la tecla presionada del teclado if (estadoTeclado.IsKeyDown(Keys.Left))// si se presiona la flecha izquierda this.setRotacion(this.getRotacion() - 0.1f); //Gira el cañon hacia la izquierda if (estadoTeclado.IsKeyDown(Keys.Right)) // si se presiona la flecha derecha this.setRotacion(this.getRotacion() + 0.1f); //Gira el cañon hacia la derecha //la siguiente instrucción limita entre 0 y 90 grados el giro del cañon. Recordar que se hace uso de radianes. this.setRotacion(MathHelper.Clamp(this.getRotacion(), -MathHelper.PiOver2, 0)); }
Ahora en el método Update de la clase Game1.cs escribimos la siguiente instrucción justo después de la sentencia if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); objCañon.Update(gameTime);// llama al metodo Update de la clase MovimientosCañon Ahora ejecute el juego y observe como el cañón se mueve cuando presiona las flechas izquierda y derecha de nuestro teclado.
Ahora haremos que el cañón también gire cuando movamos el mouse en la ventana de juego, entonces en ese caso el código completo de nuestra clase MovimientosCañon.cs seria el siguiente using using using using using using using using using using using
System; System.Collections.Generic; System.Linq; System.Text; Microsoft.Xna.Framework; Microsoft.Xna.Framework.Audio; Microsoft.Xna.Framework.Content; Microsoft.Xna.Framework.GamerServices; Microsoft.Xna.Framework.Graphics; Microsoft.Xna.Framework.Input; Microsoft.Xna.Framework.Media;
namespace WindowsGameLibrary1 { public class MovimientosCañon { Texture2D Textura;//almacenara la textura de nuestro cañon private Vector2 posicion; //En qué punto se encuentra ubicado el cañon private Vector2 Centro; //El centro por donde gira el cañon private float Rotacion; //Angulo de rotación del cañon MouseState anteriorRaton; // almacenara el estado previo del mouse en la ventana del juego //Constructor public MovimientosCañon(Texture2D Textura) { posicion = Vector2.Zero;// posicion por defecto (0,0) this.Textura=Textura;// Rotacion = (float)0.0; //Rotación 0.0 en radianes por defecto Centro = new Vector2(Textura.Width / 2, Textura.Height / 2); //El centro de la textura } //Leyendo los valores de los atributos public Texture2D getTextura() { return Textura; } public Vector2 getPosicion() { return posicion; } public Vector2 getCentro() { return Centro; } public float getRotacion() { return Rotacion; } //Dando valores a los atributos public void setCentro(Vector2 Centro) { this.Centro = Centro; } public void setRotacion(float Rotacion) { this.Rotacion = Rotacion; } public void setPosicion(Vector2 Posicion) { this.posicion = Posicion; }
public void Update(GameTime gameTime) { KeyboardState estadoTeclado = Keyboard.GetState();// variable que nos permite obtener la tecla presionada del teclado if (estadoTeclado.IsKeyDown(Keys.Left))// si se presiona la flecha izquierda this.setRotacion(this.getRotacion() - 0.1f); //Gira el cañon hacia la izquierda if (estadoTeclado.IsKeyDown(Keys.Right)) // si se presiona la flecha derecha this.setRotacion(this.getRotacion() + 0.1f); //Gira el cañon hacia la derecha //Código para leer el mouse MouseState Raton = Mouse.GetState(); if (Raton != anteriorRaton)//Si movió el mouse entonces el cañon cambia de ángulo { int DiferX = Raton.X - anteriorRaton.X; //La diferencia entre la anterior posición del ratón y la nueva. this.setRotacion(this.getRotacion() + (float)DiferX / 100); //El movimiento en X del ratón cambia el ángulo del cañon } anteriorRaton = Raton;//Se actualiza el estado del ratón //la siguiente instrucción limita entre 0 y 90 grados el giro del cañon. Recordar que se hace uso de radianes. this.setRotacion(MathHelper.Clamp(this.getRotacion(), -MathHelper.PiOver2, 0)); } } }
Ejecute el juego y observe como el cañón gira cuando usted mueve el mouse en la ventana de ejecución del juego. Ahora vamos a hacer que nuestro cañón dispare rayos cuando presionamos la tecla space, para esto vamos a crear una nuea clase en nuestra librería WindowsGameLibrary1 a la cual la llamaremos Rayos.cs
Ya creada nuestra nueva clase definimos nuestra nueva clase con el código que se muestra a continuación using using using using using using using using using using using
System; System.Collections.Generic; System.Linq; System.Text; Microsoft.Xna.Framework; Microsoft.Xna.Framework.Audio; Microsoft.Xna.Framework.Content; Microsoft.Xna.Framework.GamerServices; Microsoft.Xna.Framework.Graphics; Microsoft.Xna.Framework.Input; Microsoft.Xna.Framework.Media;
namespace WindowsGameLibrary1 { public class Rayos { Texture2D Textura;//almacenara la textura del rayo private Vector2 Centro; //El centro por donde gira el cañon private float Rotacion; //Angulo de rotación del cañon private bool Activo; //Sabe si esta activo o no el rayo private Vector2 Velocidad; //Dirección y velocidad del rayo private Vector2 posicion; //En qué punto se encuentra ubicado el rayo //Constructor public Rayos(Texture2D Textura) { this.Textura = Textura; Rotacion = (float)0.0; //Rotación 0.0 en radianes por defecto Centro = new Vector2(Textura.Width / 2, Textura.Height / 2); //El centro del sprite Activo = false; //Por defecto no se muestra el rayo Velocidad = Vector2.Zero; //Por defecto el rayo no se mueve } //Leyendo los valores de los atributos public Texture2D getTextura() { return Textura; } public Vector2 getCentro() { return Centro; } public Vector2 getPosicion() { return posicion; } public float getRotacion() { return Rotacion; } public bool getActivo() { return Activo; } public Vector2 getVelocidad() { return Velocidad; } //Dando valores a los atributos public void setCentro(Vector2 Centro) { this.Centro = Centro; } public void setPosicion(Vector2 posicion) { this.posicion = posicion; } public void setRotacion(float Rotacion) { this.Rotacion = Rotacion; } public void setActivo(bool Activo) { this.Activo = Activo; } public void setVelocidad(Vector2 Velocidad) { this.Velocidad = Velocidad; } } }
La idea es que nuestro rayo salga disparado en la dirección de rotación
que se encuentra nuestro cañón actualmente.
Ahora vamos a la case MovimientosCañon.cs y definimos la siguiente variable KeyboardState anteriorTeclado;//almacena el estado anterior del teclado
En la clase game1.cs declaramos las siguientes variables Rayos[] arregloRayos;// creamos un arreglo de tipo Rayos const int MAXRAYOS = 7;// definimos el numero de rayos que pueden estar en pantalla a la vez Rectangle fondoPantalla;// variable que almacenara las dimensiones de la ventana de ejecucion
En el método LoadContent de la clase Game1.cs lo definimos de la siguiente forma protected override void LoadContent() { spriteBatch = new SpriteBatch(GraphicsDevice); texturaFondo = Content.Load
("espacio");//No es necesaria la extensión .png texturaCañon = Content.Load
("cañon");//No es necesaria la extensión .png texturaNave = Content.Load
("base");//No es necesaria la extensión .png // recordemos que en nuestra clase ObjetosJuego y MovimientosCañon tienen un constructor que recibe como parametro un objeto de tipo Texture2D objCañon = new MovimientosCañon(texturaCañon); //Cargar e inicializar el cañon objCañon.setPosicion(new Vector2(110, 450)); //Posición de nuestro cañon nave = new ObjetosJuego(texturaNave); //Cargar e inicializar la nave nave.setPosicion ( new Vector2(70, 460)); //Posición de la nave espacial en donde se encuentra nuestro cañon //pasamos a cargar los elemetos de nuestro arrglo con la textura rayo arregloRayos = new Rayos[MAXRAYOS]; for (int Cont = 0; Cont < MAXRAYOS; Cont++) arregloRayos[Cont] = new Rayos(Content.Load
("rayo")); // pasamos a cargar las dimensioes de la ventana de ejecucion de nuestro juego fondoPantalla = new Rectangle(0, 0, Window.ClientBounds.Width, Window.ClientBounds.Height); }
El método Update de la clase Game1.cs quedaría definido como se muestra a continuación protected override void Update(GameTime gameTime) { if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); bool accion=objCañon.Update(gameTime);//llamamos al metodo Update de la clase MovimientosCañon // que devuelve true si se presiona y sulta la tecla space if (accion == true)// si se presiona y suleta la tecla space DispararRayo();//llama al metodo disparar rayo ActualizaRayos();// actualizamos los rayos base.Update(gameTime); }
Luego
en nuestra clase Game1.cs
después del método Draw creamos los siguientes métodos
DispararRayo y ActualizarRayos
El método DispararRayo lo que va a hacer es que mientras un rayo se encuentre visible en nuestra ventana de ejecución entonces el rayo estará activo caso contrario e rayo estará inactivo, si un rayo está inactivo hay la posibilidad de dibujar otro , nuest ro juego solo nos permite dibujar 7 rayos activos en la ventana de juego.
//Método llamado desde Update public void DispararRayo() { //Busca un rayo inactivo foreach (Rayos Rayo in arregloRayos) { //Si encuentra un rayo inactivo if (Rayo.getActivo() == false) { //Activa el rayo (para que sea dibujado) Rayo.setActivo(true); //El rayo inicia en la posición del lanzador Rayo.setPosicion(objCañon.getPosicion()); //En que dirección y a que velocidad sale el rayo. Hay que tener en cuenta la rotación del lanzador. Rayo.setVelocidad(new Vector2((float)Math.Cos(objCañon.getRotacion()), (float)Math.Sin(objCañon.getRotacion())) * 4.0f); //Rote el sprite del rayo para que coincida con el del lanzador Rayo.setRotacion(objCañon.getRotacion()); return; //permite disparar varios rayos consecutivamente } } } //Método llamado desde Update public void ActualizaRayos() { //Va de rayo en rayo foreach (Rayos Rayo in arregloRayos) if (Rayo.getActivo() == true) { //Solo es actualizar la velocidad porque el vector se actualiza gracias a esa magnitud Rayo.setPosicion(Rayo.getPosicion() + Rayo.getVelocidad()); //Si el rayo se sale de la pantalla entonces se desactiva if (fondoPantalla.Contains(new Point((int)Rayo.getPosicion().X, (int)Rayo.getPosicion().Y)) == false) Rayo.setActivo(false); } }
En el método Draw de la clase Game1.cs escribimos el siguiente código juesto antes de la sentencia spriteBatch.End();// finaliza el dibujado foreach (Rayos Rayo in arregloRayos) if (Rayo.getActivo() == true) spriteBatch.Draw(Rayo.getTextura(), Rayo.getPosicion(), null, Color.White, Rayo.getRotacion(), Rayo.getCentro(), 1f, SpriteEffects.None, 0);
Ahora ejecute el juego y observe como cuando presiona la tecla space se dibujan los rayos que se mueven en a dirección del canon
Actualmente su clase MovimientosCañon.cs deberá parecerse a la que using using using using using using using using using using using
se encuentra codificada a continuación
System; System.Collections.Generic; System.Linq; System.Text; Microsoft.Xna.Framework; Microsoft.Xna.Framework.Audio; Microsoft.Xna.Framework.Content; Microsoft.Xna.Framework.GamerServices; Microsoft.Xna.Framework.Graphics; Microsoft.Xna.Framework.Input; Microsoft.Xna.Framework.Media;
namespace WindowsGameLibrary1 { public class MovimientosCañon { Texture2D Textura;//almacenara la textura de nuestro cañon private Vector2 posicion; //En qué punto se encuentra ubicado el cañon private Vector2 Centro; //El centro por donde gira el cañon private float Rotacion; //Angulo de rotación del cañon MouseState anteriorRaton;// // almacenara el estado previo del mouse en la ventana del juego KeyboardState anteriorTeclado;//almacena el estado anterior del teclado //Constructor public MovimientosCañon(Texture2D Textura) { posicion = Vector2.Zero;// posicion por defecto (0,0) this.Textura=Textura;// Rotacion = (float)0.0; //Rotación 0.0 en radianes por defecto Centro = new Vector2(Textura.Width / 2, Textura.Height / 2); //El centro dela textura } //Leyendo los valores de los atributos public Texture2D getTextura() { return Textura; } public Vector2 getPosicion() { return posicion; } public Vector2 getCentro() { return Centro; } public float getRotacion() { return Rotacion; } //Dando valores a los atributos public void setCentro(Vector2 Centro) { this.Centro = Centro; } public void setRotacion(float Rotacion) { this.Rotacion = Rotacion; } public void setPosicion(Vector2 Posicion) { this.posicion = Posicion; }
public bool Update(GameTime gameTime) { bool disparar=false; KeyboardState estadoTeclado = Keyboard.GetState(); if (estadoTeclado.IsKeyDown(Keys.Left)) this.setRotacion(this.getRotacion() - 0.1f); //Gira el lanzador hacia la izquierda
if (estadoTeclado.IsKeyDown(Keys.Right)) this.setRotacion(this.getRotacion() + 0.1f); //Gira el lanzador hacia la derecha //Código para leer el ratón MouseState Raton = Mouse.GetState(); //Si movió el ratón entonces el lanzador cambia de ángulo if (Raton != anteriorRaton) { int DiferX = Raton.X - anteriorRaton.X; //La diferencia entre la anterior posición del ratón y la nueva. this.setRotacion(this.getRotacion() + (float)DiferX / 100); //El movimiento en X del ratón cambia el ángulo del lanzador } //Se actualiza el estado del ratón anteriorRaton = Raton; if (estadoTeclado.IsKeyDown(Keys.Space) && anteriorTeclado.IsKeyUp(Keys.Space)) disparar=true; anteriorTeclado = estadoTeclado; //Esta instrucción limita entre 0 y 90 grados el giro del lanzador. Recordar que se hace uso de radianes. this.setRotacion(MathHelper.Clamp(this.getRotacion(), -MathHelper.PiOver2, 0)); return disparar; } } }
Actualmente su clase Game1.cs deberá parecerse a la que
se encuentra codificada a continuación
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 WindowsGameLibrary1; namespace Juego_2_nave { public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; Texture2D texturaFondo; //Variable de tipo textura2D en la cual cargaremos la imagen espacio.png Texture2D texturaCañon; //Variable de tipo textura2D en la cual cargaremos la imagen cañon.png Texture2D texturaNave; //Variable de tipo textura2D en la cual cargaremos la imagen base.png // necesitamos crear objetos de la clase ObjetosJuego y la clase MovimientosCañon para poder acceder a sus atributos y metodos ObjetosJuego nave; //sera la nave de nuestro juego MovimientosCañon objCañon;//sera El cañon de nuestra nave Rayos[] arregloRayos;// creamos un arreglo de tipo Rayos const int MAXRAYOS = 7;// definimos el numero de rayos que pueden estar en pantalla a la vez Rectangle fondoPantalla;// variable que almacenara las dimensiones de la ventana de ejecucion
public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; } protected override void Initialize() { base.Initialize(); } protected override void LoadContent() { spriteBatch = new SpriteBatch(GraphicsDevice); texturaFondo = Content.Load
("espacio");//No es necesaria la extensión .png texturaCañon = Content.Load
("cañon");//No es necesaria la extensión .png texturaNave = Content.Load
("base");//No es necesaria la extensión .png // recordemos que en nuestra clase ObjetosJuego y MovimientosCañon tienen un constructor que recibe como parametro un objeto de tipo Texture2D objCañon = new MovimientosCañon(texturaCañon); //Cargar e inicializar el cañon objCañon.setPosicion(new Vector2(110, 450)); //Posición de nuestro cañon nave = new ObjetosJuego(texturaNave); //Cargar e inicializar la nave nave.setPosicion ( new Vector2(70, 460)); //Posición de la nave espacial en donde se encuentra nuestro cañon //pasamos a cargar los elemetos de nuestro arrglo con la textura rayo arregloRayos = new Rayos[MAXRAYOS]; for (int Cont = 0; Cont < MAXRAYOS; Cont++) arregloRayos[Cont] = new Rayos(Content.Load
("rayo")); // pasamos a cargar las dimensioes de la ventana de ejecucion de nuestro juego fondoPantalla = new Rectangle(0, 0, Window.ClientBounds.Width, Window.ClientBounds.Height); } protected override void UnloadContent() { } protected override void Update(GameTime gameTime) { if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); bool accion=objCañon.Update(gameTime);//llamamos al metodo Update de la clase MovimientosCañon // que devuelve true si se presiona y sulta la tecla space if (accion == true)// si se presiona y suleta la tecla space DispararRayo();//llama al metodo disparar rayo ActualizaRayos();// actualizamos los rayos base.Update(gameTime); } protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); spriteBatch.Begin();//comenazmos a dibujar
spriteBatch.Draw(texturaFondo, new Rectangle(0, 0, Window.ClientBounds.Width, Window.ClientBounds.Height), Color.White);// dibujamos el fondo /* Dibuja el lanzador como tal, estos son los parámetros * Parámetro 1: El sprite del lanzador * Parámetro 2: La posición del lanzador * Parámetro 3: null porque es solo una imagen (no una sucesión de estas) * Parámetro 4: Color.White, combinación de color * Parámetro 5: Angulo de rotación por defecto * Parámetro 6: Centro, el centro * Parametro 8: Dibujar tal como es el sprite (no reflejo vertical ni horizontal) * Parámetro 9: Ponerlo en la capa superior */ spriteBatch.Draw(objCañon.getTextura(), objCañon.getPosicion(), null, Color.White, objCañon.getRotacion(),objCañon.getCentro(), 1.1f, SpriteEffects.None, 0); spriteBatch.Draw(nave.getTextura(), nave.getPosicion(), Color.White);// dibujamos nuestra nav foreach (Rayos Rayo in arregloRayos) if (Rayo.getActivo() == true) spriteBatch.Draw(Rayo.getTextura(), Rayo.getPosicion(), null, Color.White, Rayo.getRotacion(), Rayo.getCentro(), 1f, SpriteEffects.None, 0); spriteBatch.End();// finaliza el dibujado base.Draw(gameTime); }
//Método llamado desde Update public void DispararRayo() { //Busca un rayo inactivo foreach (Rayos Rayo in arregloRayos) { //Si encuentra un rayo inactivo if (Rayo.getActivo() == false) { //Activa el rayo (para que sea dibujado) Rayo.setActivo(true); //El rayo inicia en la posición del lanzador Rayo.setPosicion(objCañon.getPosicion()); //En que dirección y a que velocidad sale el rayo. Hay que tener en cuenta la rotación del lanzador. Rayo.setVelocidad(new Vector2((float)Math.Cos(objCañon.getRotacion()), (float)Math.Sin(objCañon.getRotacion())) * 4.0f); //Rote el sprite del rayo para que coincida con el del lanzador Rayo.setRotacion(objCañon.getRotacion()); return;//permite disparar varios rayos consecutivamente } } } //Método llamado desde Update public void ActualizaRayos() { //Va de rayo en rayo foreach (Rayos Rayo in arregloRayos) if (Rayo.getActivo() == true) { //Solo es actualizar la velocidad porque el vector se actualiza gracias a esa magnitud Rayo.setPosicion(Rayo.getPosicion() + Rayo.getVelocidad()); //Si el rayo se sale de la pantalla entonces se desactiva if (fondoPantalla.Contains(new Point((int)Rayo.getPosicion().X, (int)Rayo.getPosicion().Y)) == false) Rayo.setActivo(false); } } } }
Ahora agreguemos una nueva imagen (descarga la imagen del siguiente link) a nuestro proyecto
Vamos a windowsGameibrary1
y crearemos una case a la cual la llamaremos Asteroides.cs la cual debe ser una clase pública.
Nuestra clase Asteroides.cs debe tener la siguiente codificación using using using using using using using using using using using
System; System.Collections.Generic; System.Linq; System.Text; Microsoft.Xna.Framework; Microsoft.Xna.Framework.Audio; Microsoft.Xna.Framework.Content; Microsoft.Xna.Framework.GamerServices; Microsoft.Xna.Framework.Graphics; Microsoft.Xna.Framework.Input; Microsoft.Xna.Framework.Media;
namespace WindowsGameLibrary1 { public class Asteroides { Texture2D textura;//almacena la textura de nuestros asteroides Vector2 posicion;//almacena la posicion de nuestro asteroide Vector2 velocidad;//la velocidad con la ue se mueve el asteroide private bool activo;// para saber si esta e asteroide activo o no public Asteroides(Texture2D textura) { this.textura = textura; activo = false;//por defecto o se muestra el asteroide velocidad = Vector2.Zero;// por defecto el asteroide no se mueve posicion = Vector2.Zero; } public public public public
Texture2D getTextura() { return textura; } bool getActivo() { return activo; } Vector2 getVelocidad() { return velocidad; } Vector2 getPosicion() { return posicion; }
public void setActivo(bool activo) { this.activo = activo; } public void setVelocidad(Vector2 velocidad) { this.velocidad = velocidad; } public void setPosicion(Vector2 posicion) { this.posicion = posicion; } } }
La case anterior se encargará de los asteroides (enemigo). Cada enemigo tiene una vida limitada: nace en la parte derecha de la ventana, viaja por la ventana y desaparece cuando llega al borde izquierdo de esta. Luego es necesario saber cuándo el enemigo se mantiene activo, es decir, cuando se muestra por pantalla. Para eso hacemos uso del atributo de la clase Asteroides.cs de tipo booleano que cuando tiene el valor de "true" significa que el enemigo esta activo y debe mostrarse, caso contrario, mantenerlo oculto. No solamente eso, también hay algo importante con los enemigos: se desplazan por la pantalla, el desplazamiento tiene una dirección y una velocidad, por lo tanto hacemos uso del atributo de velocidad (magnitud y dirección) de la clase Asteroides.cs Ahora viene la programación del enemigo como tal y estas son las cosas que hay que tener en cuenta: 1. El enemigo aparece a la derecha de la ventana en una posición Y aleatoria. 2. El enemigo viaja a una velocidad inicial aleatoria. 3. El enemigo se desplaza de derecha a izquierda, desaparece cuando llegue al borde izquierdo de la ventana. Para lo aleatorio necesitamos la clase Random(); En la clase Game1.cs definimos las siguientes variables Asteroides[] arregloAsteroides= new Asteroides[9];//solo podra mostrarse 9 asteroides en pantalla a la vez Random Aleatorio = new Random(); //Generador de números aleatorios usado para ubicar a una altura al azar los asteroides /*Como el enemigo sale en una posición Y aleatoria, debemos saber entre que rango es el aleatorio (una interpolación lineal entre un Ymin y un Ymax), * lo mismo pasa con la velocidad (entre un Vmin y Vmax). Usamos estas variables en el método que actualiza los asteroides.*/ float AlturaMax = 0.1f; //No pegado del techo float AlturaMin = 0.5f; //La mitad de la pantalla float Velocidax = 5.0f; //Máxima velocidad float Velocid = 1.0f; //Mínima velocidad
En el método LoadContent de la clase Game1.cs pasamos a que lo hicimos con los rayos
lo que es cargar los elementos de nuestro arreglo de asteroides al igual
//pasamos a cargar los elementos de nuestro arreglo de asteroides con la textura asteroides for (int Cont = 0; Cont < 9; Cont++) arregloAsteroides[Cont] = new Asteroides(Content.Load
("asteroides"));
Ahora en el método Update de la clase Game1.cs base.Update(gameTime); //Actualiza los enemigos ActualizaEnemigos(); En la clase Game1.cs definimos el siguiente método
escribimos
la
siguiente
instrucción
justo
antes
de
la
sentencia
//Método llamado desde Update public void ActualizaEnemigos() { foreach (Asteroides asteroides in arregloAsteroides)//recorremos el arreglo de asteroides { if (asteroides.getActivo() == true)// si el asteroide activo { //El enemigo avanza a determinada velocidad asteroides.setPosicion(asteroides.getPosicion() + asteroides.getVelocidad()); //Si el enemigo se sale de la pantalla if (fondoPantalla.Contains(new Point((int)asteroides.getPosicion().X, (int)asteroides.getPosicion().Y)) == false) asteroides.setActivo(false);//el asteroide para a estar inactivo } else { asteroides.setActivo(true);//Activa el enemigo //Interpolación. Posición eje Y aleatoria. asteroides.setPosicion(new Vector2(fondoPantalla.Right, MathHelper.Lerp((float)fondoPantalla.Height * AlturaMin, (float)fondoPantalla.Height * AlturaMax, (float)Aleatorio.NextDouble()))); //Velocidad del enemigo. Aleatoria. asteroides.setVelocidad(new Vector2(MathHelper.Lerp(-Velocid, -Velocidax, (float)Aleatorio.NextDouble()), 0)); } } }
Ahora en el método Draw de la clase Game1.cs escribimos el siguiente código justo antes de la sentencia spriteBatch.End();// finaliza el dibujado //Dibuja cada enemigo foreach (Asteroides asteroide in arregloAsteroides) if (asteroide.getActivo() == true) spriteBatch.Draw(asteroide.getTextura(), asteroide.getPosicion(), Color.White);
Ejecute el juego y observe lo siguiente
El código completo de la clase Game1.cs es el siguiente: 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 WindowsGameLibrary1; namespace Juego_2_nave { public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; Texture2D texturaFondo; //Variable de tipo textura2D en la cual cargaremos la imagen espacio.png Texture2D texturaCañon; //Variable de tipo textura2D en la cual cargaremos la imagen cañon.png Texture2D texturaNave; //Variable de tipo textura2D en la cual cargaremos la imagen base.png // necesitamos crear objetos de la clase ObjetosJuego y la clase MovimientosCañon para poder acceder a sus atributos y metodos ObjetosJuego nave; //sera la nave de nuestro juego MovimientosCañon objCañon;//sera El cañon de nuestra nave Rayos[] arregloRayos;// creamos un arreglo de tipo Rayos const int MAXRAYOS = 7;// definimos el numero de rayos que pueden estar en pantalla a la vez Rectangle fondoPantalla;// variable que almacenara las dimensiones de la ventana de ejecucion Asteroides[] arregloAsteroides= new Asteroides[9];//solo podra mostrarse 9 asteroides en pantalla a la vez Random Aleatorio = new Random(); //Generador de números aleatorios usado para ubicar a una altura al azar los asteroides /*Como el enemigo sale en una posición Y aleatoria, debemos saber entre que rango es el aleatorio (una interpolación lineal entre un Ymin y un Ymax), * lo mismo pasa con la velocidad (entre un Vmin y Vmax). Usamos estas variables en el método que actualiza los asteroides.*/ float AlturaMax = 0.1f; //No pegado del techo float AlturaMin = 0.5f; //La mitad de la pantalla float Velocidax = 5.0f; //Máxima velocidad float Velocid = 1.0f; //Mínima velocidad public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; } protected override void Initialize() { base.Initialize(); } protected override void LoadContent() { spriteBatch = new SpriteBatch(GraphicsDevice); texturaFondo = Content.Load
("espacio");//No es necesaria la extensión .png texturaCañon = Content.Load
("cañon");//No es necesaria la extensión .png texturaNave = Content.Load
("base");//No es necesaria la extensión .png // recordemos que en nuestra clase ObjetosJuego y MovimientosCañon tienen un constructor que recibe como parametro un objeto de tipo Texture2D objCañon = new MovimientosCañon(texturaCañon); //Cargar e inicializar el cañon objCañon.setPosicion(new Vector2(110, 450)); //Posición de nuestro cañon nave = new ObjetosJuego(texturaNave); //Cargar e inicializar la nave nave.setPosicion ( new Vector2(70, 460)); //Posición de la nave espacial en donde se encuentra nuestro cañon //pasamos a cargar los elemetos de nuestro arrglo con la textura rayo arregloRayos = new Rayos[MAXRAYOS]; for (int Cont = 0; Cont < MAXRAYOS; Cont++) arregloRayos[Cont] = new Rayos(Content.Load
("rayo")); // pasamos a cargar las dimensioes de la ventana de ejecucion de nuestro juego fondoPantalla = new Rectangle(0, 0, Window.ClientBounds.Width, Window.ClientBounds.Height); //pasamos a cargar los elementos de nuestro arreglo de asteroides con la textura asteroides for (int Cont = 0; Cont < 9; Cont++) arregloAsteroides[Cont] = new Asteroides(Content.Load
("asteroides")); } protected override void UnloadContent()
{ } protected override void Update(GameTime gameTime) { if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); bool accion=objCañon.Update(gameTime);//llamamos al metodo Update de la clase MovimientosCañon // que devuelve true si se presiona y sulta la tecla space if (accion == true)// si se presiona y suleta la tecla space DispararRayo();//llama al metodo disparar rayo ActualizaRayos();// actualizamos los rayos //Actualiza los enemigos ActualizaEnemigos(); base.Update(gameTime); }
protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); spriteBatch.Begin();//comenazmos a dibujar spriteBatch.Draw(texturaFondo, new Rectangle(0, 0, Window.ClientBounds.Width, Window.ClientBounds.Height), Color.White);// dibujamos el fondo /* Dibuja el lanzador como tal, estos son los parámetros * Parámetro 1: El sprite del lanzador * Parámetro 2: La posición del lanzador * Parámetro 3: null porque es solo una imagen (no una sucesión de estas) * Parámetro 4: Color.White, combinación de color * Parámetro 5: Angulo de rotación por defecto * Parámetro 6: Centro, el centro * Parametro 8: Dibujar tal como es el sprite (no reflejo vertical ni horizontal) * Parámetro 9: Ponerlo en la capa superior */ spriteBatch.Draw(objCañon.getTextura(), objCañon.getPosicion(), null, Color.White, objCañon.getRotacion(),objCañon.getCentro(), 1.1f, SpriteEffects.None, 0); spriteBatch.Draw(nave.getTextura(), nave.getPosicion(), Color.White);// dibujamos nuestra nave //Dibuja cada rayo foreach (Rayos Rayo in arregloRayos) if (Rayo.getActivo() == true) spriteBatch.Draw(Rayo.getTextura(), Rayo.getPosicion(), null, Color.White, Rayo.getRotacion(), Rayo.getCentro(), 1f, SpriteEffects.None, 0); //Dibuja cada enemigo foreach (Asteroides asteroide in arregloAsteroides) if (asteroide.getActivo() == true) spriteBatch.Draw(asteroide.getTextura(), asteroide.getPosicion(), Color.White); spriteBatch.End();// finaliza el dibujado base.Draw(gameTime); }
//Método llamado desde Update public void DispararRayo() { //Busca un rayo inactivo foreach (Rayos Rayo in arregloRayos) { //Si encuentra un rayo inactivo if (Rayo.getActivo() == false) { //Activa el rayo (para que sea dibujado) Rayo.setActivo(true); //El rayo inicia en la posición del lanzador Rayo.setPosicion(objCañon.getPosicion()); //En que dirección y a que velocidad sale el rayo. Hay que tener en cuenta la rotación del lanzador. Rayo.setVelocidad(new Vector2((float)Math.Cos(objCañon.getRotacion()), (float)Math.Sin(objCañon.getRotacion())) * 4.0f); //Rote el sprite del rayo para que coincida con el del lanzador Rayo.setRotacion(objCañon.getRotacion()); return;//permite disparar varios rayos consecutivamente } } } //Método llamado desde Update public void ActualizaRayos() { //Va de rayo en rayo foreach (Rayos Rayo in arregloRayos) if (Rayo.getActivo() == true) { //Solo es actualizar la velocidad porque el vector se actualiza gracias a esa magnitud Rayo.setPosicion(Rayo.getPosicion() + Rayo.getVelocidad()); //Si el rayo se sale de la pantalla entonces se desactiva if (fondoPantalla.Contains(new Point((int)Rayo.getPosicion().X, (int)Rayo.getPosicion().Y)) == false) Rayo.setActivo(false); } } //Método llamado desde Update public void ActualizaEnemigos() { foreach (Asteroides asteroides in arregloAsteroides)//recorremos el arreglo de asteroides { if (asteroides.getActivo() == true)// si el asteroide activo { //El enemigo avanza a determinada velocidad asteroides.setPosicion(asteroides.getPosicion() + asteroides.getVelocidad()); //Si el enemigo se sale de la pantalla if (fondoPantalla.Contains(new Point((int)asteroides.getPosicion().X, (int)asteroides.getPosicion().Y)) == false) asteroides.setActivo(false);//el asteroide para a estar inactivo } else { asteroides.setActivo(true);//Activa el enemigo //Interpolación. Posición eje Y aleatoria. asteroides.setPosicion(new Vector2(fondoPantalla.Right, MathHelper.Lerp((float)fondoPantalla.Height * AlturaMin, (float)fondoPantalla.Height * AlturaMax, (float)Aleatorio.NextDouble()))); //Velocidad del enemigo. Aleatoria. asteroides.setVelocidad(new Vector2(MathHelper.Lerp(-Velocid, -Velocidax, (float)Aleatorio.NextDouble()), 0)); } } }
} }
Hasta ahora si disparamos los rayos, estos siguen, pueden pasar por encima del enemigo y no sucede nada. El juego no tiene emoción. Debemos añadirle que cuando un rayo acierte al enemigo, ambos desaparezcan. Eso se le conoce en el medio con el nombre de "colisión". Pero ¿Cómo se hace la colisión?. Un primer acercamiento es comparar las coordenadas del rayo, con las coordenadas del enemigo, si coinciden, hay una colisión. Sin embargo, lograr tal coincidencia es muy difícil durante el juego. La comparación es entonces por áreas rectangulares, se compara si el área rectangular del rayo toca el área rectangular del enemigo. Eso es mucho más posible. XNA nos ofrece la función para comparar si dos rectángulos se interceptan. El método que actualiza los rayos en Game1.cs tiene ahora este código (no se modifica ningún otro código): //Método llamado desde Update public void ActualizaRayos() { //Va de rayo en rayo foreach (Rayos Rayo in arregloRayos) { if (Rayo.getActivo() == true) { //Solo es actualizar la velocidad porque el vector se actualiza gracias a esa magnitud Rayo.setPosicion(Rayo.getPosicion() + Rayo.getVelocidad()); //Chequea la colisión //Deduce el rectángulo del rayo y debe tener en cuenta el tamaño con que se esté dibujando en pantalla en Draw() Rectangle RectRayo = new Rectangle((int)Rayo.getPosicion().X, (int)Rayo.getPosicion().Y, (int)(Rayo.getTextura().Width * 0.2), (int)(Rayo.getTextura().Height * 0.2)); //Chequea de enemigo en enemigo si el cohete lo colisiona foreach (Asteroides asteroide in arregloAsteroides) { //Deduce el rectángulo del enemigo y debe tener en cuenta el tamaño con que se esté dibujando en pantalla en Draw() Rectangle RectEnemigo = new Rectangle((int)asteroide.getPosicion().X, (int)asteroide.getPosicion().Y, (int)(asteroide.getTextura().Width), (int)(asteroide.getTextura().Height)); //Si ambos rectángulos se intersectan if (RectRayo.Intersects(RectEnemigo) == true) { asteroide.setActivo(false);//inactiva el enemigo Rayo.setActivo(false); //inactiva el rayo break; //salimos del bucle } } } //Si el rayo se sale de la pantalla entonces se desactiva if (fondoPantalla.Contains(new Point((int)Rayo.getPosicion().X, (int)Rayo.getPosicion().Y)) == false) Rayo.setActivo(false); } }
Ejecute el juego y observe como ahora si el rayo toca al asteroide estos dos desaparecen. Es hora de escribir un puntaje a nuestro juego en pantalla en donde nos muestre el nuemro de asteroides eliminados y el numero de asteroides fallidos. Vamos al explorador de soluciones
y agregamos un nuevo elemento SpriteFont
En la clase Game1.cs definimos las siguientes variables SpriteFont fuentetexto;//variable tipo SpriteFont que sera usada para mostrar el texto en pantalla int contadorEliminados = 0;//contador que almacenara el numero de asteroides eliminados int contadorFallidos = 0;//contador que almacenara el numero de asteroides fallidos
Ahora en el método LoadContent de la clase Game1.cs cargamos nuestra fuente de texto fuentetexto = Content.Load<SpriteFont>("SpriteFont1");//cargamos la fuente de nuestro texto Ahora vamos al método ActualizaRayos y escribimos la siguiente instrucción como se muestra a continuación
Ahora vamos al método ActualizaEnemigos y escribimos la siguiente instrucción como se muestra a continuación
Ahora escribimos la siguiente instrucción en el método Draw justo antes de la sentencia spriteBatch.End();// finaliza el dibujado //dibujamos los puntajes spriteBatch.DrawString(fuentetexto,"Eliminados= "+contadorEliminados, new Vector2(10, 10), Color.Red);
//la sentencia anterior nos muesra el texto de los asteroides eliminados en a posicion (10,10) con un texto rojo spriteBatch.DrawString(fuentetexto, "Falidos= " + contadorFallidos, new Vector2(200, 10), Color.Red); //la sentencia anterior nos muesra el texto de los asteroides fallidos en a posicion (200,10) con un texto rojo Ejecute el juego y tendrá algo como esto
Hasta ahora nuestro juego es mudo. Es momento de añadirle más emoción y realismo, y el camino para eso es agregándole sonidos. Estos son los pasos: En el siguiente link descarge los sonidos con extencion .mp3 y .mva . Ahora agréguelos a nuestro juego
Ahora declaremos las siguientes variables en nuestra clase Game1.cs Song melodia;// el sonido de animacion de nuestro juego SoundEffect sonido;// variable de tipo efecto sonido SoundEffectInstance efectoSonido;// instancia del efecto de sonido que hara nuestro juego cuando eliminemos un asteroide
Vamos al método LoadContent de la clase Game1.cs e inicializamos nuestros sonidos melodia = Content.Load<Song>("R5 - Me By");/// cargamos la cancion MediaPlayer.Play(melodia);// reproducimos la cancion al ejecutar el juego MediaPlayer.Volume = 0.5f;// definimos el volumen con el que se reproducira la cancion MediaPlayer.IsRepeating = true;// cuando la cancion termine se repetira sonido = Content.Load<SoundEffect>("beep");// cargamos el efecto de sonido efectoSonido = sonido.CreateInstance();
Vamos al método ActualizarRayos y escribimos el código que se muestra a continuación
Ejecute el juego y escuche los efectos de sonido.
Sugerencias o comentarios al correo
[email protected] Blog oficial http://ingeuce.wix.com/ingeuce2 Encuéntranos en Facebook y YouTube como ingeuce