miércoles, 23 de julio de 2014

Como hacer al Enemigo "Space Invaders con Phaser".


naves en Hmlt5

La llegada del enemigo es inminente pero ya nuestro heroe esta mas que preparado para recibirlos, en esta ocasion veremos como crear al enemigo al finalizar estas naves van a estar en capacidad de moverse y de disparar.


Nuestros enemigos tiene la capacidad de moverse de un lado a otro tal como lo hace nuestra nave con una caracteristica y es que a medida que completan el ciclo estos descienden ademas que en cada movimiento nos van disparando sin compasion. 
Veamos que hay de nuevo. Comenzemos: Nuestras nuevas variables:


//variables Heroe
var jugador,
municion,
tiempoDisparo=0,
teclas,
teclaDisparo,
empieza=false;
//variables Enemigo
municionEnemigo,
tiempoDisparando=0,
enemigosVivos=[],

Vemos las de nuestro heroe y la nuevas que incoporamos mas adelante veremos su utilidad.

Ahora cargamos las nuevas imagenes que necesitamos:

function preload() {
//background
    game.load.image('_FONDO', 'FONDO.png');
//Heroe
    game.load.image('balaHEROE', 'BALAJ.png');
    game.load.image('HEROE', 'NAVE.png');
//enemigos
 game.load.image('balaALIEN', 'BALAE.png');
 game.load.atlas('ALIENIGENAS', 'NAVES.png','NAVES.json');    
}

Ahora tenemos la municion de los enemigos y las naves que son una pequeña animacion la cual hize con InkScape nada del otro mundo.

function create() {
    game.physics.startSystem(Phaser.Physics.ARCADE);
    game.add.image(0,0,"_FONDO");
     //cargamento de nuestra Nave
    municion = game.add.group();
    municion.enableBody = true;
    municion.physicsBodyType = Phaser.Physics.ARCADE;
    municion.createMultiple(30, 'balaHEROE');
    municion.setAll('anchor.x', 0.5);
    municion.setAll('anchor.y', 0.5);
    municion.setAll('outOfBoundsKill', true);

 //los enemigos tambien tienen municion
    municionEnemigo = game.add.group();
    municionEnemigo.enableBody = true;
    municionEnemigo.physicsBodyType = Phaser.Physics.ARCADE;
    municionEnemigo.createMultiple(30, 'balaALIEN');
    municionEnemigo.setAll('anchor.x', 0.5);
    municionEnemigo.setAll('anchor.y', 1);
    municionEnemigo.setAll('outOfBoundsKill', true);
 
    // Los invasores
    navesEnemigas = game.add.group();
    navesEnemigas.enableBody = true;
    navesEnemigas.physicsBodyType = Phaser.Physics.ARCADE;

//Creamos todos los objetos
comienza();
 
    //Nuestro centro de mando
    teclas = game.input.keyboard.createCursorKeys();
    teclaDisparo = game.input.keyboard.addKey(Phaser.Keyboard.SPACEBAR);
};

Creamos dos nuevos grupos que pertenecen a la municion del enemigo y a las naves invasoras pero esta vez en el grupo de navesEnemigas no usamos el metodo createMultiple() ya veremos porque no lo hacemos.


 Desde la funcion Comienza ahora llamamos a la nueva funcion creadorDeAliens() que sera la encargada de dar vida a nuestros enemigos:

function comienza (){
creadorDeAliens();
crearJugador();
empieza=true;
};

Ahora tenemos la funcion creadorDeALiens:

function creadorDeAliens () {
    for (var y = 0; y < 3; y++)
    {
        for (var x = 0; x < 5; x++)
        {
            var alienLocal = navesEnemigas.create(x * 110, y * 100, 'ALIENIGENAS');
            alienLocal.anchor.setTo(0.5, 0.5);
            alienLocal.animations.add('COLOR', [ 0,1,2,3 ], 10, true);
            alienLocal.play('COLOR');
            alienLocal.body.moves = false;
        }
    }

    navesEnemigas.x = 80;
navesEnemigas.y = 50;
    var transicion = game.add.tween(navesEnemigas).to( { x: 250 }, 2000, Phaser.Easing.Linear.None, true, 0, 1000, true);
    transicion.onLoop.add(bajar, this);
};

Aqui vemos un for anidado eso es un for dentro de otro for con la caracteristica que el for interno se ejecuta completamente esto significa que por cada fila aparecen cinco aliens como resultado si se repite 3 veces serian 15 aliens. 
hacer juegos Phaser


Como mencione no utilizamos el metodo createMultiple porque recuerda para recuperar objetos de ese clase de grupos hay que utilizar el metodo getFirstExists(booleano), ademas que su posicion en sus ejes(x,y) es modificada es decir no es muy eficiente para usar. 

 Para crear a los enemigos recuerdas el metodo de los grupos create(x,y,"nombre clave")

var alienLocal = navesEnemigas.create(x * 110, y * 100, 'ALIENIGENAS'); 


Para que las naves mantengan la distancia entre sus respectivos ejes entonces le multiplicamos un valor(ancho de la nave ) a sus posiciones asi en cada ciclo este aumentara relativamente a la nave anterior hagamos el ejercicio: 



Si el for exterior en este caso es el valor de "Y" se ejecuta una vez esto equivale a 5 repeticiones del for interior valor de "X" con lo cual al entrar a este for la variable "X" vale 0 resultado 0x110 =0; esta seria la posicion de la primera nave. 


Cuando vuelva a incrementar la variable "X" es decir a 1 entonces 1x110 = 110; esta es la posicion de la seguna nave con esto ya existe una distancia entre ellas y asi sucesivamente con las demas.

 Con el valor de "Y" ocurre igual en el primer ciclo vale 0(0x100=0) en el segundo ciclo vale 1(1x100=100) es decir desciende con lo cual se matendra la distancia entre ellas.

 Modificamos el valor del anchor,agregamos la animacion e inmediatamente la ejecutamos , ahora aparece: 

alienLocal.body.moves = false; 

El body posee la propiedad moves la cual pasamos el valor "false" asi decimos al sistema de fisicas que vamos a mover a este cuerpo manualmente sin necesidad de fisicas.

Si calculamos vemos que el valor de "Y" cuando sea cero (cero en los ejes (x,y) en canvas equivale a la esquina superior izquierda) nuestras naves de arriba no se van a ver entonces modificamos el valor inicial.

 navesEnemigas.x = 80; navesEnemigas.y = 50; 

 Cuando mencionaba que moveremos a este cuerpo manualmente eso lo hacemos gracias a los Tween:

 var transicion = game.add.tween(navesEnemigas).to( { x: 250 }, 2000, Phaser.Easing.Linear.None, true, 0, 1000, true); 

game.add.tween(objeto).to( {propiedad }, duracion,tipo de efecto, autoArranque,cuanto tarda,duracion de repeticion,yoyo(que se devuelva a su posicion inicial)); 

con esto conseguiremos que las naves se muevan de lado a lado y por si solas pero necesitamos que desciendan: 
transicion.onLoop.add(bajar, this); 

onLoop es una señal y funciona porque hicimos que el tween vaya y venga es decir un "yoyo=true" entonces cada ves que complete el ciclo(lado a lado) la funcion "bajar" sera llamada. 

La funcion bajar no es mas que aumentar la posicion de Y:


function bajar() {
     //bajamos 10px
    navesEnemigas.y += 10;
};

Al modificar la posicion del grupo todo sus hijos tambien se veran afectados. A diferencia de nuestro heroe que dispara cada vez que presionamos la tecla esparceadora con los enemigos tendremos que calcular cada cuanto van a disparar automaticamente:

if (game.time.now > tiempoDisparando)
    {
       fuegoEnemigo();
    };

Aqui entra en juego la variable tiempoDisparando que regula el tiempo entre cada disparo para luego llamar a la funcion fuegoEnemigo() encargarda de comenzar el ataque. 

 Y para finalizar nuestro enemigos no vinieron a visitarnos sino a dispararnos:

function fuegoEnemigo () {
     var balaEnemigo = municionEnemigo.getFirstExists(false);
    enemigosVivos.length=0;
    navesEnemigas.forEachAlive(function(alien){
        enemigosVivos.push(alien);
    });
    if (balaEnemigo && enemigosVivos.length > 0)
    {
        var random=game.rnd.integerInRange(0,enemigosVivos.length-1);
        var disparo=enemigosVivos[random];
        balaEnemigo.reset(disparo.body.x, disparo.body.y);
 //Estos enemigos son muy inteligente y poseen tecnologia de rastreo avanzado
        game.physics.arcade.moveToObject(balaEnemigo,jugador,250);
        tiempoDisparando = game.time.now + 1600;
    }

};

Aqui recuperamos los objetos del grupo municionEnemigo,tenemos otra variable enemigosVivos la cual es un array normal y usaremos para tomar una nave al azar y entonces hacer que esta dispare. 

Primero colocamos el valor del array a cero cada vez que sea llamada la funcion y asegurarnos que este vacio cuando vaya a entrar en el forEachAlive ya que posiblemente hayamos destruido alguna nave asi que ya habra menos de ellas:

enemigosVivos.length=0;

 Con el metodo forEachAlive() que sirve para recorrer un grupo y acceder a sus hijos los cuales tengan la propiedad Alive activada(true),ahora todos los hijos que tenga ese grupo los metemos en el array con su metodo Push  para usarlos luego.

 navesEnemigas.forEachAlive(function(alien){ enemigosVivos.push(alien); }); 

 Ahora comprobamos que tengamos municion disponible y ademas que existan alienigenas vivos: 

 if (balaEnemigo && enemigosVivos.length > 0) { 

 varrandom=game.rnd.integerInRange(0,enemigosVivos.length-1);

 var disparo=enemigosVivos[random]; 

 balaEnemigo.reset(disparo.body.x, disparo.body.y);

game.physics.arcade.moveToObject(balaEnemigo,jugador,250); 

 tiempoDisparando = game.time.now + 1600;
 } 

Si se cumple esa condicion entonces con el metodo: 

game.rnd.integerInRange(minimo,maximo); Obtenemos un valor dentro del rango dado. 

En este caso el rango(desde el primero hasta al ultimo que quede vivo) son los aliens dentro del array enemigosVivos,esto nos devuelve un numero el cual equivale a una posicion dentro del array donde se encuentra alguna nave practiquemos:

 Si var random=game.rnd.integerInRange(0,enemigosVivos.length-1); 

nos devuele 1 y si buscamos esa posicion dentro del array enemigos vivos: 

 var disparo=enemigosVivos[random]; 

esto equivale a:

disparo=enemigosVivos[1]; 

Esto nos devuelve un sprite(una nave), cuando eso suceda queremos que la bala salga disparada precisamente de esa nave para eso usamos:

balaEnemigo.reset(disparo.body.x, disparo.body.y);

Pero aun asi si llegara a disparar esta saldria sin ningun rumbo para arreglar usamos:

game.physics.arcade.moveToObject(balaEnemigo,jugador,250); 

El mismo metodo nos dice lo que hace "mueve al objeto dado otro objeto" en esta oportunidad la bala queremos que sea lanzada al jugador con una velocidad que en este caso es de 250. 

 Y aumentamos el valor de la variable tiempoDisparando sumandole al tiempo actual el valor de 1600 no queremos que parezca un lluvia de balas:

 tiempoDisparando = game.time.now + 1600; 

Nuestro enemigos han empezado la invsasion, parecen fuertes, muy inteligentes en la proxima entrada provocaremos colision entres sus proyectiles, colocaremos vidas y puntaje. 

Aqui el resultado:
Enemigos 

 Mensaje de la Flota:

 Alpha1:Parece que la municion del enemigo es altamente peligrosa y puede causar daños severos.......... 

HASTA LA PROXIMA.

No hay comentarios:

Publicar un comentario