[Tutorial ImpactJS] Estructura básica de las entidades.

Hoy voy a hablar un poco de las entidades en ImpactJS, que son, como interactuan con el jugador, etcétera. Pero antes, debes ir al repositorio en github para descargarte la carpeta media, donde están todos los sonidos, música y sprites que vamos a usar durante el desarrollo del juego.

Las entidades vienen a ser cualquier elemento del juego capaz de interactuar con el jugador, con otras entidades o con el sistema en si. Por ejemplo un botón de pause sería una entidad, el personaje del jugador sería otra entidad, los enemigos, las balas, obstáculos, en definitiva todo lo que realice alguna acción de forma activa mediante un evento previo, como un click, un choque con otra entidad, un temporizador, etcétera.

Las entidades en ImpactJS son clases extendidas de ig.Entity y siempre se han de guardar en lib/game/entities/, su estructura básica es esta:

ig.module( 'game.entities.miEntidad' ) 
    .requires( 'impact.entity' ) 
    .defines(function() { 

          EntityMiEntidad = ig.Entity.extend({
          //Constructor 
          init: function(x, y, settings) { 
              this.parent(x, y, settings); 
          } 
        }); 
    });

Revisemos por partes el código, primero tenemos la instrucción ig.module:

ig.module( 'game.entities.miEntidad' )

La cual define el directorio y el nombre del script que contiene la entidad, en este caso game/entities/miEntidad.js, la siguiente instrucción incluye las clases necesarias para que funcione nuestra entidad:

.requires( 'impact.entity' )

Su forma de definir el script es idéntica a la anterior, en este caso requiere el script impact/entity.js, como es lógico es necesaria la clase ig.Entity para poder extender de ella. Por ultimo tenemos:

.defines(function() { 

    EntityMiEntidad = ig.Entity.extend({ 
      //Constructor 
      init: function(x, y, settings) { 
          this.parent(x, y, settings); 
      } 
  }); 
});

Si nos fijamos el nombre de la clase de nuestra entidad es EntityMiEntidad, esto ha de ser siempre así, me refiero a que hay una nomenclatura establecida en el motor, que es “Entity” mas el nombre del script con la primera letra en mayúsculas y sin extensión, si mi script se llama mula.js, el nombre de la entidad debe ser EntityMula, si no lo hacemos así el motor simplemente no funcionará y se quedará en la barra de carga al inicio, dando un error en la consola javascript. Otro dato importante es que las clases se definen en formato JSON.

Siempre que nuestras clases (en este caso una entidad) herede de otra deberemos añadir this.parent() en los métodos ya declarados en la clase padre para que todos funcione como debe, si lo omitimos, el método no hará las funciones para las que por defecto fue definido.

El método init siempre deberá tener 3 parámetros, la posición de la entidad dada en coordenadas (*x,y), * y las propiedades del objeto. Aunque de momento no vamos a explicar esto, pero si que vamos a establecer propiedades básicas en nuestra entidad.

A simple vista podemos ver en el juego que hay 4 entidades bien definidas, el jugador, los escudos, los marcianos y el ovni. Los sprites tienen un tamaño de 50x50 cada uno, pero los personajes tienen un tamaño menor, vamos a ver como trabajar con esto. Empecemos con nuestro personaje:

ig.module( 'game.entities.jugador' ) 
    .requires( 'impact.entity' ) 
    .defines(function() { 

        EntityJugador = ig.Entity.extend({ 

            //Pre-cargamos los sprites 
            animSheet: new ig.AnimationSheet('/space/media/personajes.png',50 , 50),
            //Tamaño de la entidad 
            size: {x : 40 , y : 26 }, 
            //Numero de pixeles que eliminamos de los bordes 
            offset: {x : 5, y : 12}, 

            //Constructor 
            init: function(x, y, settings) {
                this.parent(x, y, settings);
                //Definimos la animación 
                this.addAnim( 'normal' , 9999999 , [6]); 
            } 
        }); 
    });

Por un lado tenemos la propiedad *animSheet, *donde hemos indicado el fichero que contiene los sprites, y el tamaño de cada sprite:

//Pre-cargamos los sprites 
animSheet: new ig.AnimationSheet( '/space/media/personajes.png',50 , 50 ),

Por otro lado le hemos indicado el tamaño de nuestra entidad, que es de 40 de ancho por 26 de alto, pero indicándole mediante la propiedad offset cuando debe de restar a los bordes del sprite. Recuerda que nuestra entidad es más pequeña que el sprite seleccionado, por lo que si no definiéramos el offset el motor mostraría la imagen desde la esquina superior izquierda hasta el numero de pixeles indicados, y por lo tanto nos saldría cortada.

Sprite-offset

//Tamaño de la entidad 
size: {x : 40 , y : 26 }, 
//Numero de pixeles que eliminamos de los bordes 
offset: {x : 5, y : 12},

Una vez le hemos indicado que fichero contiene los sprites, las dimensiones de cada sprite, y las dimensiones de la entidad en si, nos dirigimos al método init para añadir la animación que tendrá nuestro personaje, aunque en este caso no hay animación propiamente dicha porque consta solo de un sprite:

init: function(x, y, settings) { 
    this.parent(x, y, settings); 
    //Definimos la animación 
    this.addAnim( 'normal' , 9999999 , [6]); 
}

Usamos this.addAnim para indicarle la animación que queremos, pasandole el nombre que le queremos dar (normal), el tiempo para que cambie a la siguiente (como solo es una he puesto un tiempo largo), y los sprites que queremos que cargue en forma de array y en el orden deseado, en el jugador es solo uno, pero su hubieran más se podrian así [0,1,2]. Hay que tener en cuenta que el motor divide el archivo de sprites por las dimensiones que le pasamos, y numera cada sprite empezando en cero.

Sprites Numerados

 Ahora que tenemos nuestra entidad jugador creada vamos a probarla, nos dirigimos a* lib/game/main.js* y añadimos ‘game.entities.jugador’ en la zona de require, para cargar la entidad el iniciar el juego, esta zona se debería de ver así:

ig.module( 'game.main' ) 
    .requires( 'impact.game', 'impact.font', 'game.entities.jugador' )

Ahora vamos al método init de MyGame para crear nuestra entidad mediante el método ig.game.spawnEntity( NombreClaseEntidad , x , y , propiedades en JSON):

init: function() { 

  //Tecla de disparo 
  ig.input.bind( ig.KEY.SPACE , 'fuego' ); 

  //Teclas de movimiento 
  ig.input.bind( ig.KEY.LEFT_ARROW , 'izquierda' );
  ig.input.bind( ig.KEY.RIGHT_ARROW , 'derecha' );

  //Tecla de reinicio 
  ig.input.bind( ig.KEY.ENTER , 'reinicio' ); 

  //Creamos nuestro jugador 
  ig.game.spawnEntity( EntityJugador, 300, 300, {}); 
},

Una vez hecho al abrir http://localhost/spaceinvaders tendríamos que ver algo similar a esto:

ImpactJS más Entidad

Ahí tenemos nuestra primera entidad creada, pero aun no hace nada, vamos a dotarle de los movimientos básicos derecha e izquierda. Primero nos dirigimos al método update del main.js para eliminar las pruebas de teclado que habiamos hecho anteriormente, de forma que lo dejemos así:

update: function() { 

  // Update all entities and backgroundMaps 
  this.parent(); 
},

Ahora nos dirigimos a la clase de nuestra entidad jugador lib/game/entities/jugador.js. Para controlar el movimiento del personaje debemos de modificar la propiedad this.vel *(velocidad), la cual nos permite indicarle a la entidad hacia donde debe moverse mediante valores en los ejes *x o y, de forma que “x” en un valor negativo movería la entidad hacia la izquierda y en positivo hacia la derecha, de la misma forma “y” en negativo haría subir la entidad y en positivo la haría descender. Vamos a crear nosotros dentro de EntityJugador el método update, y en su interior comprobar que tecla se está pulsando y modificar this.vel.x en consecuencia:

update: function(){ 
    this.parent(); 

    //Movemos el personaje
    if(ig.input.state('izquierda')){ 
        this.vel.x = -100; 
    } if(ig.input.state('derecha')){ 
        this.vel.x = 100; 
    } 

    //Paramos el movimiento al soltar alguna tecla.
    if(ig.input.released('izquierda') || ig.input.released('derecha')){
        this.vel.x = 0; 
    } 
}

Nuevamente nos dirigimos a http://localhost/spaceinvaders y comprobamos como ahora al pulsar las flechas izquierda o derecha de nuestro teclado el personaje responde moviéndose hacia donde le indicamos.

En el próximo artículo empezaremos a trabajar con el editor de niveles donde colocaremos las entidades, creamos un fondo para el tapiz, ectétera.

Anterior:Primeros pasos con la librería.
Código: https://github.com/Nazariglez/spaceinvaders