jueves, 14 de noviembre de 2013

Actores: Listeners

Saludos a tod@s, ésta semana vamos a dedicarla a los listeneres de los actores, intentaré explicarlo de la manera mas fácil posible para que lo entendamos todos.

 Listeners. 

Un Listener como su traducción indica es un oyente, un "escuchador" y captura "eventos" un evento es una notificación de alguien, en terminos de programación y en nuestro caso, el actor dispara eventos "me han tocado", "me han soltado", "me mueven", etc. Pongo una pequeña imagen de explicación que aunque parezca chorra nos ayudará a aclarar términos.

IMPORTANTE:
 Como vereís en la imagen un actor tiene unos llamados "bounds" límites, los límites de un actor se ajustan con varios de los métodos que hemos usado, setX(), setY(),setWidth(),setHeight(), setBounds(x,y,ancho,alto), etc

Un Actor no puede notificar un evento si no se toca sus límites, podemos crear un actor y colocarlo en cualquier sitio ajustando sus coordenadas con SetPosition(x,y), pero si no le ajustamos su ancho y alto sólo será un punto cualquiera y será imposible clickarlo, independientemente de que dibujemos en su método draw una textura, sprite, etc, vereís la textura, pero no os devolverá nada.

Bien vamos a ver como insertar el Listener en 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.InputEvent;
import com.badlogic.gdx.scenes.scene2d.InputListener;
import com.badlogic.gdx.scenes.scene2d.actions.MoveByAction;
import com.badlogic.gdx.scenes.scene2d.actions.ParallelAction;
import com.badlogic.gdx.scenes.scene2d.actions.RepeatAction;
import com.badlogic.gdx.scenes.scene2d.actions.RotateByAction;

public class Pez extends Actor {
    LibgdxSpain game;
    TextureRegion RegionPez;
    Texture pez;
    RotateByAction rotate;
    MoveByAction move;
    RepeatAction repeat;
    ParallelAction paralel;
   
    public Pez(LibgdxSpain game){
       
        this.game = game;
   
        setPosition(50,50);
        setHeight(64);
        setWidth(64);
        setOriginX(getWidth()/2);
        setOriginY(getHeight()/2);
   
       
        move = new MoveByAction();
        move.setAmount(700, 300);
        move.setDuration(10f);
        rotate = new RotateByAction();
        rotate.setAmount(400);
        rotate.setDuration(1f);
        //añadir acciones
        repeat = new RepeatAction();
        repeat.setCount(repeat.FOREVER);
        repeat.setAction(rotate);
       
        paralel = new ParallelAction();
        paralel.addAction(move);
        paralel.addAction(repeat);
       
        this.addAction(paralel);

        pez = new Texture(Gdx.files.internal("data/Images/pez.png"));
       
        RegionPez = new TextureRegion(pez);
        //Añadimos un lister, y creamos el listener dentro del método,
        addListener(new InputListener() {
           
           
              public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
                            //Se ejecuta cuando se hace click sobre el actor.
                      return true;
              }
             
              public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
                    //Se ejecuta cuando se levanta el dedo del actor, se ejecuta sólo cuando el touchDown es true.
              }
             
              public void touchDragged (InputEvent event, float x, float y, int pointer) {
                  //Se ejecuta cuando touchdown = true y se arrastra el actor.
            }

       
            public boolean mouseMoved (InputEvent event, float x, float y) {
                //Se ejuta "solo en desktop" ya que es cuando el raton pasa por encima del actor.
                return true;
            }

           
            public void enter (InputEvent event, float x, float y, int pointer, Actor fromActor) {
                //Se ejuta "solo en desktop" ya que es cuando el raton entra al actor.
            }

       
            public void exit (InputEvent event, float x, float y, int pointer, Actor toActor) {
                //Se ejuta "solo en desktop" ya que es cuando el raton sale del actor.
            }
   
           
             
        });
   
    }
   
   
    public void draw(SpriteBatch batch,float parentAlpha){
       

       
        batch.draw(RegionPez, getX(), getY(), getOriginX(), getOriginY(), getWidth(), getHeight(), getScaleX(), getScaleY(), getRotation());
       
       
    }

}


Como veís teneís por parámetro las coordenadas de los puntos donde se pulsa y el "pointer" es para el multitáctil, 0 el primer dedo, 1 el 2º, etc etc.

Hay 2 tipos de listeners dentro de un actor, el puesto en el código anterior y el gestor de gestos:


 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.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.actions.MoveByAction;
import com.badlogic.gdx.scenes.scene2d.actions.ParallelAction;
import com.badlogic.gdx.scenes.scene2d.actions.RepeatAction;
import com.badlogic.gdx.scenes.scene2d.actions.RotateByAction;
import com.badlogic.gdx.scenes.scene2d.utils.ActorGestureListener;

public class Pez extends Actor {
    LibgdxSpain game;
    TextureRegion RegionPez;
    Texture pez;
    RotateByAction rotate;
    MoveByAction move;
    RepeatAction repeat;
    ParallelAction paralel;
  
    public Pez(LibgdxSpain game){
      
        this.game = game;
        setPosition(50,50);
        setHeight(64);
        setWidth(64);
        setOriginX(getWidth()/2);
        setOriginY(getHeight()/2);

        move = new MoveByAction();
        move.setAmount(700, 300);
        move.setDuration(10f);
        rotate = new RotateByAction();
        rotate.setAmount(400);
        rotate.setDuration(1f);
        repeat = new RepeatAction();
        repeat.setCount(repeat.FOREVER);
        repeat.setAction(rotate);
      
        paralel = new ParallelAction();
        paralel.addAction(move);
        paralel.addAction(repeat);
      
        this.addAction(paralel);

        pez = new Texture(Gdx.files.internal("data/Images/pez.png"));
      
        RegionPez = new TextureRegion(pez);
      
        addListener(new ActorGestureListener(){
          
            public void touchDown (InputEvent event, float x, float y, int pointer, int button) {
                //Mismo caso que en InputListener, al pulsar
            }

            public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
                //Mismo caso que en InputListener, al soltar
            }

            public void tap (InputEvent event, float x, float y, int count, int button) {
                //Al tocar y soltar, seria como al hacer click.
            }

            public boolean longPress (Actor actor, float x, float y) {
                //al mantener pulsado un rato sin mover el dedo
          
                return false;
            }

            public void fling (InputEvent event, float velocityX, float velocityY, int button) {
                //seria un gesto como para lanzar un objeto, lo tocamos y lo movemos hacia un lado
                //soltandolo
              
            }

      
            public void pan (InputEvent event, float x, float y, float deltaX, float deltaY) {
               //Es como un arrastrar
            }

            public void zoom (InputEvent event, float initialDistance, float distance) {
                //Como su nombre indica, es como cuando intentamos aumentar el zoom de la pantalla con
                //los dos dedos
            }

            public void pinch (InputEvent event, Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2) {
                //Este es como el Zoom pero mas complicado, con capacidad de rotación, como cuando en
                //el google maps hacemos grande el mapa a la vez que lo giramos.
            }
          
        });
  
    }
  
  
    public void draw(SpriteBatch batch,float parentAlpha){
      

      
        batch.draw(RegionPez, getX(), getY(), getOriginX(), getOriginY(), getWidth(), getHeight(), getScaleX(), getScaleY(), getRotation());
      
      
    }

}


 IMPORTANTE 2.0

Hace 2 tutoriales escribí esto al crear la screen y añadir el stage dentro.

 @Override
    public void show() {

        //Ésto es necesario para procesar entradas dentro del stage, para listeners y demás.
        Gdx.input.setInputProcessor(stage);

        //Instancio el actor LogicalSplash anterior
        ls = new LogicalSplash(game,this);
        //Se lo añado al Stage.
        stage.addActor(ls);
    }

Es imposible que si os dejaís esa linea el stage sea capaz de capturar algún gesto,  para que se entienda, el stage tiene incluida la interfaz InputProcessor, la cual se pasa al processador de entradas de libgdx para que pueda "procesarlas" y devolvernos el método que toque.

Ya teneís varias maneras de interactuar con los actores, mañana explicaré como implementar el procesador de entradas y el procesador de gestos sin tener que usar actores. Espero que se haya entendido bien ya que para los que no hayan escuchado el tema de los eventos y listeneres puede ser complicado.

Muchas gracias a todos y hasta mañana.

2 comentarios:

  1. Muy bueno cada actor con su listener :) me gusta LIBGDX esta bien echo.

    ResponderEliminar
  2. gracias por fin pude hacer que los actores respondan al ser tocados :D gracias :)

    ResponderEliminar