lunes, 28 de octubre de 2013

Acciones

Acciones de un actor.


Saludos voy a dedicar éste articulo a explicar algunas de las acciones, en libGdx las acciones están para facilitarnos el trabajo a los programadores, y permiten a un actor hacer cosas de manera sencilla, mover, escalar, etc...

Acciones.

¿Donde creamos las acciones? Las acciones las podemos crear dentro de una classe actor o bien fuera en la logica del juego, y en cualquier momento podemos añadirle una acción a un actor, la acción se ejecutará y cuando acabe se eliminará.

Acciones de Movimiento.

MoveToAction : Mover hacia una coordenada (X,Y).

Intanciamos la acción.

MoveToAction acc = new MoveToAction();
//Hacia la posición 700x,300y
acc.setPosition(700, 300);
//3 Segundos
acc.setDuration(3f);
//Añadir la acción al actor.
this.addAction(accion);
 
MoveByAction: Mover X e Y unidades un actor.

Intanciamos acción.

MoveByAction acc2 = new MoveByAction();
acc2.setDuration(10f);
//Cantidad de movimiento, en éste caso se moverá 300 unidades hacia abajo.
acc2.setAmount(0, -300);
 
RotateToAction: Rotar hasta un ángulo determinado.

 acc = new RotateToAction();
//Angulo a rotar. Un valor positivo lo hará girar en sentido contrario a las agujas del reloj, y //viceversa.
 acc.setRotation(360);
//Tiempo
acc.setDuration(1f);
//Añadir Acción
this.addAction(acc);
 
RotateByAction: Rotar tantos grados un actor.

 acc = new RotateByAction();
 acc.setAmount(360);
acc.setDuration(1f);
this.addAction(acc);


Origen de Rotación, al yo rotar una imagen tengo que tener en cuenta el punto de origen central, por defecto, el punto de origen de un actor viene a 0, la esquina inferior izquierda, al yo modificar éste punto puedo hacer que gire sobre si mismo, sobre una esquina, basta con usar el método setOriginX(float) y setOriginY(float). Adjunto una imagen explicativa.





IMPORTANTE! No basta únicamente con crear la acción en el actor y a funcionar, una acción cambia los atributos del actor, que quiero decir con ésto, yo en mi actor, tengo un constructor y un método draw en el que dibujo lo que me interese, al dibujarlo, tengo que darle al método draw los atributos del actor, si pongo un número únicamente no me variará en absoluto y la acción se ejecutará bien, pero el método draw seguirá dibujando ese valor, pongo un  breve ejemplo de nuestro pez:

package com.Firedark.libgdxspain;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.actions.MoveByAction;
import com.badlogic.gdx.scenes.scene2d.actions.RotateToAction;

public class Pez extends Actor {
    LibgdxSpain game;
    TextureRegion RegionPez;
    Texture pez;
    RotateToAction rotate;
    MoveByAction move;
    public Pez(LibgdxSpain game){
       
        this.game = game;
        //Atributos del actor. Posicion, Tamaño, y Origen de rotación.
        setPosition(50,50);
        setHeight(64);
        setWidth(64);
        setOriginX(getWidth()/2);
        setOriginY(getHeight()/2);
        //Mi accion Move
        move = new MoveByAction();
        move.setAmount(0, -300);
        move.setDuration(10f);
        //Mia Accion Rotate
        rotate = new RotateToAction();
        rotate.setRotation(-720);
        rotate.setDuration(1f);
        //añadir acciones
        this.addAction(move);
        this.addAction(rotate);
       
        pez = new Texture(Gdx.files.internal("data/Images/pez.png"));
       
        RegionPez = new TextureRegion(pez);
   
    }
   
   
    public void draw(SpriteBatch batch,float parentAlpha){
       
        //Metodo Draw, como veis, me traigo todos los atributos de la classe actor, de ésta manera
        //Si yo creo una acción rotate, el valor de mi actor Rotation variará en los segundos que
        //he asignado.
        //Observar que he usado un método draw mas completo que en situaciones anteriores, existen varios
        //métodos para texturas y regiones de textura.
        batch.draw(RegionPez, getX(), getY(), getOriginX(), getOriginY(), getWidth(), getHeight(), getScaleX(), getScaleY(), getRotation());

       
    }

}


Acciones Paralelas y Repetitivas.

Puede que necesitemos crear una acción repetitiva, que se ejecute continuamente o bien hacer 2 acciones paralelamente dentro de una sequencia, para ello podemos usar los tipos de acción:

Repetir acciones:

//Éste es un ejemplo para repetir continuamente "FOREVER" la acción rotate anterior del pez.
        RepeatAction repeat;
        repeat = new RepeatAction();
        repeat.setCount(repeat.FOREVER);
        repeat.setAction(rotate);
        //Añadimos al actor únicamente la acción repeat, que ya contiene la rotate.
        this.addAction(repeat);
Acciones paralelas:
     
        //Mucho no hay que explicar, és una accion que contiene las 2 acciones anteriores, la cual
        //las ejecuta a la vez.
        ParallelAction paralel;
        paralel = new ParallelAction();
        paralel.addAction(move);
        paralel.addAction(repeat);
       
        this.addAction(paralel);

Aunque parezca que las acciones paralelas no sirvan para nada no es cierto, en el siguiente tutorial vereís que usamos una sequencia de acciones, la cual se ejecutan una detrás de otra, sin las acciones paralelas seria imposible ejecutar 2 acciones a la vez dentro de una secuencia. Aqui teneís el tutorial de la semana:

Tutorial práctico: Splash Screen, acciones alpha y secuencias.

Las accion alpha nos servirá para modificar el canal alpha de una imagen, no podemos tratar directamente con Texturas y perderemos la capacidad de rotación y movimiento, pero nos permitirá hacer cosas interesantes. Como ejemplo práctico vamos a crear una pantalla de transición al empezar nuestro juego, con un logo que crearemos previamente.


1er Paso, Crear nuestra Screen, añadirle el Stage, lógica, etc , podeís mirar el tutorial del articulo anterior:

http://libgdxspain.blogspot.com.es/2013/10/actores-y-escenarios.html

2º Paso, preparar nuestras imagenes:



  Rectangulo Negro de 1024x1024.

 Logo de 1024 x 1024.

Podeís crear una imagen de 1024x1024 y insertar las 2 dentro para aprovechar espacio ya que sólo usaremos 800x480 en cada una de ellas.

3er Paso, Crear nuestro actor.

package com.Firedark.libgdxspain;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.actions.AlphaAction;
import com.badlogic.gdx.scenes.scene2d.actions.DelayAction;
import com.badlogic.gdx.scenes.scene2d.actions.SequenceAction;
import com.badlogic.gdx.scenes.scene2d.ui.Image;

public class SplashBlack extends Actor {
    LibgdxSpain game;
    //Atributos de las acciones alpha, Delay y la acción sequencia.
    AlphaAction alpha,alpha2;
    //La acción delay es una simple acción de espera, no hace nada.
    DelayAction delay;
    //Insertaremos nuestras acciónes en otra accion secuencia que nos ejecutará las cosas en orden.
    SequenceAction sequence;
    //Textura del Rectangulo, Region...
    Texture BlackRectangle;
    TextureRegion br;
    //Imagen, éste es el objeto que nos permite modificar su color alpha.
    Image ImgBR;
    //Nos servirá para saber cuando a terminado la acción.
    boolean fin;
   
    public SplashBlack(LibgdxSpain game){
       
        this.game = game;
        //Instanciamos Secuencia
        sequence = new SequenceAction();
        //Creamos las acciones alpha 1 y 2, como veís solo le damos la cantidad de alpha que queremos
        //alcanzar en 2 segundos de duracion.
        alpha = new AlphaAction();
        //Alpha a 0, Opaco.
        alpha.setAlpha(0f);
        alpha.setDuration(2f);
       
        alpha2 = new AlphaAction();
        //Alpha a 1, Transparente.
        alpha2.setAlpha(1f);
        alpha2.setDuration(2f);
        //La accion de espera de 3 segundos.
        delay = new DelayAction();
        delay.setDuration(3f);
        //Añadimos a la sequencia las tres acciones.
        sequence.addAction(alpha);
        sequence.addAction(delay);
        sequence.addAction(alpha2);
        //Y finalmente añadimos al actor la sequencia.
        addAction(sequence);
        //Cargamos Textura y Region.
        BlackRectangle = new Texture(Gdx.files.internal("data/Images/black.jpg"));
        br = new TextureRegion(BlackRectangle,0,0,800,480);
        //Creamos el objeto Imagen y le pasamos como parametro la region de nuestra textura.
        ImgBR = new Image(br);
        //Colocamos a 1 el valor alpha de nuestra imagen, por lo tanto la hacemos transparente.
        ImgBR.getColor().a = 1;
    }
   
   
    public void draw(SpriteBatch batch,float parentAlpha){
        //Continuamente le cargamos el valor de nuestro actor alpha, al valor de la imagen alpha.
        ImgBR.getColor().a = getColor().a;
        //Así se dibuja una imagen.
        ImgBR.draw(batch, parentAlpha);
        //Las acciones una vez finalizadas se eliminan no? Ésto nos ayuda a que cuando no queden acciones
        //En la secuencia habrá terminado.
        if(sequence.getActions().size == 0){
            //Un pequeño ejemplo para ir de una pantalla a otra, al terminar nuestra acción nos cambiará
            //de pantalla.
            game.setScreen(game.pJuego);
            this.remove();
        }
    }

}


 
4º Paso, añadir en nuestra logica el actor creado:

package com.Firedark.libgdxspain;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.InputListener;
import com.badlogic.gdx.scenes.scene2d.ui.Table;

public class LogicalSplash extends Table {
    LibgdxSpain game;
    //Creamos el atributo para nuestro actor anterior Background
    Texture Tbackground;
    TextureRegion background;
    SplashBlack sb;

    public LogicalSplash(LibgdxSpain game, SplashScreen screen){
       
        //El metodo setbounds coloca un Rectangulo (X,Y,Width,Height)
        Tbackground = new Texture(Gdx.files.internal("data/Images/firegames.jpg"));
        background = new TextureRegion(Tbackground,0,0,800,480);
        setBounds(0, 0, 800,480);
        setClip(true);
        this.game = game;
       
        //Instanciar Actores
   
       
        sb = new SplashBlack(game);
        //Añadiendo Actores
       
   
        addActor(sb);
       
    }
   
   
    //Metodo act se ejecuta al igual que el render, es donde insertaremos la lógica.
    @Override
     public void act(float delta) {
      super.act(delta);
   
    }
   
     @Override
     public void draw(SpriteBatch batch, float parentAlpha) {
      batch.setColor(Color.WHITE);

//Aqui dibujamos nuestro fondo.
      batch.draw(background,0,0);
      super.draw(batch, parentAlpha);
     }

}


 
Y éste será nuestro resultado!





Espero que haya sido un artículo productivo y hayaís aprendido ya a mover, rotar y manejar las acciones de un actor, hay alguna acción mas que podeis estudiaros en la API de libgdx, recomiendo por lo menos mirar para que sirven.


Gracias a todos y se agradecen como siempre, comentarios, quejas, +1, etc... Espero que si estaís haciendo algo interesante me lo enseñeís! Suerte a todos y nos vemos la próxima semana con listeners!! ^^

7 comentarios:

  1. Hola! Acabo de descubrir tu blog en la página de libgdx. Suelo meterme a menudo pero ya veo que llevas en esto desde Septiembre.

    Llevo aproximadamente un año metido con esta librería, tengo ya varios juegos en android, uno en la última Ludum Dare y sus códigos en bitbucket. Me gustaría colaborar con el blog si fuera posible.

    No quiero hacer spam ni enlaces a otros blogs, así que contacta conmigo si te interesa devautlos@gmail.com

    Un saludo :)

    ResponderEliminar
  2. tengo problemas, he intentado probar la app que estamos aciendo i no me va en el movil, como lo ago?? alguien me da el correo o alguna cosa para que me ayude x fa!!!

    ResponderEliminar
  3. Si abres la perspectiva DDMS cuando arrancas la app en el emulador puedes ver facilmente los errores que te da, puedes abrirla en la pestaña window de la parte superior, si nos comentas el error podremos ayudarte.

    ResponderEliminar
  4. No sale nada en eso del DDMS, he probado a hacer varias modificaciones en la app pero hace lo mismo, lo que me sucede es que el movil lo reconoce como app, la instalo y la abro, pero al abrirla el movil se bloquea (blokearse de k no se puede tocar nada pork no responde, no de k se blokea la pantalla y ya esta), se escuxa la musica k le puse y se ve un fondo blanco. A los 30 segundos el movil m dice k "Tu aplicación se ha detenido" y se cierra y todo vuelve a la normalidad sin k la app funcione

    ResponderEliminar
  5. Hola. Primero, antes de nada, quería darte las gracias por el tutorial.
    A lo que voy: ejecuto la aplicación en el emulador (API 12) y por algún motivo se queda la pantalla en negro. He estado haciendo un poco de debugging y parece que nunca se ejecutan los métodos draw() de LogicalSplash ni de SplashBlack, y sospecho que es porque no se agregan correctamente los actores (ya que he mirado en la lista de actores del stage), y eso que las llamadas están ahí, pero la verdad es que no tengo mucha idea de qué pasa...

    ResponderEliminar
  6. Vale, solucionado.
    Resulta que en tus métodos le pasas un SpriteBatch al draw en vez de un Batch, así que salta un error diciendo que no se puede hacer override porque la superclase no tiene ese método (normal). Lo he cambiado por un Batch y bien.
    Por otro lado, parece que lo de if(sequence.getActions().size == 0) no funciona, así que he añadido otra Action personalizada al final de la secuencia, siguiendo los consejos de otro de los tutoriales, resultando en:
    sequence.addAction(new Action() {
    public boolean act( float delta ) {
    game.pJuego=new PlayScreen(game);
    game.setScreen(game.pJuego);
    return true; // returning true consumes the event
    }});

    ResponderEliminar
  7. Como se aplica la rotación automatica de pantalla ???

    ResponderEliminar