domingo, 1 de abril de 2012

Desplegando enemigos

Carrera de XNA – Capítulo 4 – Artículo 6

enemies_mineHasta ahora tenemos una nave volando a través de unas hermosas nubes, con la sensación de avance infinito. Hemos logrado utilizar animaciones para el jugador y el fondo, modificando sus posiciones, pero nos falta un desafío, algo que vuelva interesante a nuestro juego.

Y de esto se tratan los Enemigos. La idea es crear una clase que los represente para luego hacerlos aparecer de forma aleatoria en la pantalla.

Crearemos una nueva clase, llamada Enemy.cs en nuestro proyecto del juego.

En la clase Enemy.cs

Modificamos nuestra sección de usings, por lo siguiente:

using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

Ahora definiremos dentro de la clase los siguientes campos y métodos que iremos completando en este artículo, como es de costumbre sigue con la lógica de Initialize, Update y  Draw.

// Animation representing the enemy
public Animation EnemyAnimation;

// The position of the enemy ship relative to the top left corner of thescreen
public Vector2 Position;

// The state of the Enemy Ship
public bool Active;

// The hit points of the enemy, if this goes to zero the enemy dies
public int Health;

// The amount of damage the enemy inflicts on the player ship
public int Damage;

// The amount of score the enemy will give to the player
public int Value;

// Get the width of the enemy ship
public int Width
{
get { return EnemyAnimation.FrameWidth; }
}

// Get the height of the enemy ship
public int Height
{
get { return EnemyAnimation.FrameHeight; }
}

// The speed at which the enemy moves
float enemyMoveSpeed;

public void Initialize()
{
}

public void Update()
{
}

public void Draw()
{
}

Reemplazamos el método Initialize por lo siguiente.

public void Initialize(Animation animation,Vector2 position)
{
    // Load the enemy ship texture
    EnemyAnimation = animation;

    // Set the position of the enemy
    Position = position;

    // We initialize the enemy to be active so it will be update in the game
    Active = true;


    // Set the health of the enemy
    Health = 10;

    // Set the amount of damage the enemy can do
    Damage = 10;

    // Set how fast the enemy moves
    enemyMoveSpeed = 6f;


    // Set the score value of the enemy
    Value = 100;

}

Como verán, solo establecemos algunas variables (salud total, velocidad, animación y posición) que luego son necesarias para dibujar y serán modificadas en cada Update.

A continuación, reemplazamos el método Update()  por el siguiente código.

public void Update(GameTime gameTime)
{
    // The enemy always moves to the left so decrement it's xposition
    Position.X -= enemyMoveSpeed;

    // Update the position of the Animation
    EnemyAnimation.Position = Position;

    // Update Animation
    EnemyAnimation.Update(gameTime);

    // If the enemy is past the screen or its health reaches 0 then deactivateit
    if (Position.X < -Width || Health <= 0)
    {
        // By setting the Active flag to false, the game will remove this objet from the active game list
        Active = false;
    }
}

Simplemente, movemos el enemigo dependiendo la velocidad y actualizamos la posición. A su vez, si detectamos que está fuera de la pantalla, se pone en inactivo para que no sea dibujado.

El método Draw() lo reemplazaremos con el siguiente fragmento.

public void Draw(SpriteBatch spriteBatch)
{
    // Draw the animation
    EnemyAnimation.Draw(spriteBatch);
}

Con esto, reutilizando lo que teníamos hasta ahora, fue sencillo crear nuestra clase Enemigo. Ahora procederemos a utilizarla desde nuestro Game1.

animacionMina

En la clase Game1.cs

Será necesario instanciar nuestros Enemigos, para esto definiremos una List donde pondremos cada uno de ellos. Utilizaremos dos instancias de tipo TimeSpan (tiempo) para definir el tiempo de Respawn (es decir, cada cuanto reaparecen los enemigos). Por último, usaremos una instancia de la clase Random para generar números aleatorios.

Las variables son las siguientes.

// Enemies

Texture2D enemyTexture;
List<Enemy> enemies;

// The rate at which the enemies appear

TimeSpan enemySpawnTime;
TimeSpan previousSpawnTime;

// A random number generator

Random random;

Ahora dentro del Initialize()  de nuestro Game1, colocaremos el siguiente código para instanciar la lista de enemigos, los TimeSpan y el generador de aleatorios.

// Initialize the enemies list
enemies = new List<Enemy> ();

// Set the time keepers to zero
previousSpawnTime = TimeSpan.Zero;

// Used to determine how fast enemy respawns
enemySpawnTime = TimeSpan.FromSeconds(1.0f);

// Initialize our random number generator
random = new Random();

Dentro del LoadContent(), cargaremos nuestra animación del enemigo, de la siguiente forma:

enemyTexture = Content.Load<Texture2D>("Imagenes/animacionMina");

Para crear cada enemigo, será necesario instanciar una animación, inicializarla, definir la posición del enemigo de forma aleatoria, instanciar la clase Enemy y por último setear los valores en la misma. Todo esto lo encapsulamos en un nuevo método llamado AddEnemy.

private void AddEnemy()
{
    // Create the animation object
    Animation enemyAnimation = new Animation();

    // Initialize the animation with the correct animation information
    enemyAnimation.Initialize(enemyTexture, Vector2.Zero, 47, 61, 8, 30,Color.White, 1f, true);

    // Randomly generate the position of the enemy
    Vector2 position = new Vector2(GraphicsDevice.Viewport.Width +enemyTexture.Width / 2, random.Next(100, GraphicsDevice.Viewport.Height -100));

    // Create an enemy
    Enemy enemy = new Enemy();

    // Initialize the enemy
    enemy.Initialize(enemyAnimation, position);

    // Add the enemy to the active enemies list
    enemies.Add(enemy);
}

Lo más relevante del código anterior es la posición que elegimos para mostrar al enemigo, que debe ser lo suficientemente lejos de nuestro Jugador para darle tiempo a reaccionar.

De la misma manera, debemos definir nuestra lógica de actualización de enemigos, para lo cual escribimos un método UpdateEnemies.

private void UpdateEnemies(GameTime gameTime)
{
    // Spawn a new enemy enemy every 1.5 seconds
    if (gameTime.TotalGameTime - previousSpawnTime > enemySpawnTime)
    {
        previousSpawnTime = gameTime.TotalGameTime;

        // Add an Enemy
        AddEnemy();
    }

    // Update the Enemies
    for (int i = enemies.Count - 1; i >= 0; i--)
    {
        enemies[i].Update(gameTime);

        if (enemies[i].Active == false)
        {
            enemies.RemoveAt(i);
        }
    }
}

Esto verifica una serie de cosas significativas (como si es necesario agregar o quitar enemigos del juego) dependiendo la cantidad.

Dentro del método Update() llamamos a UpdateEnemies que acabamos de escribir. Justo después de actualizar nuestro background.

// Update the enemies
UpdateEnemies(gameTime);

Por último, nos queda dibujar los enemigos en pantalla. Esto es sencillo recorriendo la lista de enemigos que creamos y llenamos, llamando al método Draw de cada instancia de enemigo.

Entonces, en nuestro método Draw()  justo después de dibujar el fondo, agregamos el siguiente código:

// Draw the Enemies
for (int i = 0; i < enemies.Count; i++)
{
    enemies[i].Draw(spriteBatch);
}

 

Enemigos en pantalla

Así debería verse nuestro juego al correrlo, con enemigos aleatorios apareciendo uno detrás de otro.

image

Descarguen el juego en este estado, desde el siguiente link: http://sdrv.ms/JfxLqZ

5 comentarios:

  1. Te falta un i– en vez de i- aqui:

    private void UpdateEnemies(GameTime gameTime)
    {
    // Spawn a new enemy enemy every 1.5 seconds
    if (gameTime.TotalGameTime – previousSpawnTime > enemySpawnTime)
    {
    previousSpawnTime = gameTime.TotalGameTime;

    // Add an Enemy
    AddEnemy();
    }

    // Update the Enemies
    for (int i = enemies.Count – 1; i >= 0; i–) //aqui es donde faltaba el i– al final
    {
    enemies[i].Update(gameTime);

    if (enemies[i].Active == false)
    {
    enemies.RemoveAt(i);
    }
    }
    }

    ademas sale fallo al no ser un menos (-) sale una ralla mas larga y da fallo

    ResponderEliminar
  2. MUY BUEN POST YA ESTOY APRENDIENDO MAS GRACIAS

    ResponderEliminar
  3. mmmm tengo algunos problemas las animaciones me aparecen y dezaparecen O.o?...
    La velocidad es la correcta pero la imagen aparece y dezaparece dando la empresion de que va muy rapido...
    de antemano muchas gracias

    ResponderEliminar
  4. Jejejej disculpen las molestias ya resolvi el prblema y es que no cargue la animacion, cargue la imgen eso era todo gracias ^^

    ResponderEliminar