LIBGDX Scene

De MediaWiki
Saltar a: navegación, buscar

UNIDADE 3: Scene2D


Introdución

Información na wiki: https://github.com/libgdx/libgdx/wiki/Scene2d

Clase utilizadas:


Xa vimos nun punto anterior o uso do Scene2D pero aplicado ó deseño de interface para o usuario.

Nota: É importante ter lido o punto anterior xa que imos poñer código xa explicado no mesmo.


Neste parte imos ver como aplicar o Scene2D pero aplicado o desenvolvemento dun xogo (sobre as personaxes que integran o xogo).

O Scene é outra forma de xestionar os elementos gráficos nun xogo. Basease no uso de Actor´s. Cada Actor ven ser un elemento gráfico do xogo sobre o cal queremos ter algún control. Permite debuxar e xestionar o control do elemento dentro da propia clase Actor (mestura Modelo-Vista-Controlador). Fai que o seu control sexa moi sinxelo e como característica que a min máis me gosta, ten a posibilidade de asociar a cada Actor unha serie de accións. As accións poden afectar ó seu aspecto (deformalo, cambiarlle a cor,....) como a súa posición,... Ditas accións pódense programar para que vaian unha detrás doutra, en paralelo, que se executen despois dun tempo, que se repitan....

Scene e o viewport

Información adicional: https://github.com/libgdx/libgdx/wiki/Viewports

Ó igual que sucedía cando deseñamos un xogo, imos necesitar o uso dunha cámara.
O Stage incorpora a súa propia cámara na que podemos definir o viewport.
Dende hai pouco, podemos determinar o aspecto que vai manter o viewport cando hai un cambio de resolución ou se visualizamos o xogo nun dispositivo cunha resolución diferente á deseñada.

Nota: Lembrar que xa vimos os problemas de manter a relación de aspecto neste punto.

No enlace anterior ven perfectamente explicado os diferentes viewports e o efecto que podemos conseguir con cada un.

O proceso é o seguinte:

  • Creamos o tipo de viewport que queremos e o asinamos o Stage.
  1.         private Stage stage;
  2.  
  3.         @Override
  4.         public void create () {
  5.  
  6.                 FitViewport fitViewPort = new FitViewport(480,800);
  7.                 stage = new Stage();
  8.                 stage.setViewport(fitViewPort);

Nota: Có new FitViewport estamos a crear unha nova cámara ortográfica.

  • Agora actualizamos o viewport de acordo á resolución do dispositivo, pero como estamos a utilizar un Viewport que mantén a proporción de aspecto, aparecerán barras no lateral en caso de aumentar de tamaño a pantalla.
  1.         @Override
  2.         public void resize(int width, int height) {
  3.         // TODO Auto-generated method stub
  4.                 stage.getViewport().update(width, height, true);
  5.         }

Nota: Dependendo do xogo, o terceiro parámetro será false, xa que poñendo true facemos que a cámara se sitúe no centro da pantalla.

Un exemplo completo:

C¢digo da clase Stage2D
Obxectivo: Amosar o uso dun viewport no stage.

  1. import com.badlogic.gdx.ApplicationAdapter;
  2. import com.badlogic.gdx.Gdx;
  3. import com.badlogic.gdx.assets.AssetManager;
  4. import com.badlogic.gdx.graphics.Color;
  5. import com.badlogic.gdx.graphics.GL20;
  6. import com.badlogic.gdx.graphics.g2d.TextureAtlas;
  7. import com.badlogic.gdx.scenes.scene2d.Stage;
  8. import com.badlogic.gdx.scenes.scene2d.ui.Label;
  9. import com.badlogic.gdx.scenes.scene2d.ui.Skin;
  10. import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
  11. import com.badlogic.gdx.utils.viewport.FillViewport;
  12.  
  13. public class Stage2D extends ApplicationAdapter {
  14.    
  15.         private AssetManager assetManager;
  16.         private Skin skin;
  17.         private Stage stage;
  18.        
  19.        
  20.         @Override
  21.         public void create () {
  22.  
  23.                 assetManager = new AssetManager();
  24.                 assetManager.load("uiskin.atlas",TextureAtlas.class);
  25.                 assetManager.finishLoading();
  26.                 TextureAtlas atlas = assetManager.get("uiskin.atlas", TextureAtlas.class);
  27.                 skin = new Skin(Gdx.files.internal("uiskin.json"), atlas); // Cargamos os estilos
  28.        
  29.                 FitViewport fitViewPort = new FitViewport(480,800);
  30.                 stage = new Stage();
  31.                 stage.setViewport(fitViewPort);
  32.                
  33.                 Gdx.input.setInputProcessor(stage);
  34.                
  35.                 cargarElementosGraficos();
  36.                
  37.  
  38.         }
  39.        
  40.         private void cargarElementosGraficos(){
  41.                
  42.                 Label titulo = new Label("Texto de exemplo",skin);
  43.                 titulo.setColor(Color.RED);
  44.                 titulo.setFontScale(2);
  45.                 titulo.setBounds(0, 50, Gdx.graphics.getWidth(), 10);
  46.                
  47.                 TextButton boton = new TextButton("Premer aquí", skin);
  48.                 boton.setPosition(0,100);
  49.                 stage.addActor(boton);
  50.                 stage.addActor(titulo);
  51.                
  52.         }
  53.        
  54.  
  55.         @Override
  56.         public void render() {
  57.                 Gdx.gl.glClearColor(1, 1, 1, 1);
  58.                 Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
  59.                
  60.                 stage.act(Gdx.graphics.getDeltaTime());
  61.                 stage.draw();
  62.         }
  63.         @Override
  64.         public void resize(int width, int height) {
  65.         // TODO Auto-generated method stub
  66.                 stage.getViewport().update(width, height, true);
  67.         }
  68.        
  69.         @Override
  70.         public void dispose() {
  71.  
  72.                 Gdx.input.setInputProcessor(null);
  73.                 assetManager.dispose();
  74.                 skin.dispose();
  75.                
  76.                 stage.dispose();
  77.         }
  78. }

Actores

Unha vez temos decidido o tipo de cámara/relación de aspecto que queremos ter no xogo necesitamos engadir as personaxes ó Stage.

Cada personaxe en Stage denomínase Actor.

Un Actor terá información sobre a súa posición (getPosition/setPosition), tamaño (setSize/getSize) e textura asociada entre outra moita información. Ven ser a clase Modelo que estabamos a usar no desenvolvemento do xogo.


  • Imos traballar con esta textura do xogo.
LIBGDX itin1 nave.png

http://opengameart.org/content/spaceship-2
Gráficos: PlatForge project, art by Stafford McIntyre

Descargádea e levala ó cartafol assets da versión Android.


Para engadir un Actor ó Stage primeiro temos que definilo.

  1. public class Personaxe extends Actor{
  2.        
  3.         private Texture textura;
  4.        
  5.         Personaxe(){
  6.                 textura = new Texture(Gdx.files.internal("LIBGDX_itin1_nave.png"));
  7.                 setBounds(480, 0, 40,40);
  8.         }
  9.  
  10.      @Override
  11.      public void draw(Batch batch, float alpha){
  12.          batch.draw(textura,getX(),getY(),getWidth(),getHeight());
  13.      }
  14.      
  15.      @Override
  16.      public void act(float delta){
  17.         super.act(delta);
  18.      }
  19. }
  • Liña 1: Derivamos da clase Actor.
  • Liña 6: Neste caso estamos a cargar a textura que vai debuxar.
  • Liña 7: Indicamos a súa posición (480,0) e tamaño (60,60).

Ni que dicir ten que toda esta información poderíamosla pasar ó constructor cando instanciamos o obxecto.

Agora ben algo moi importante.

  • Liñas 10-13: Este é o método que vai chamar o Stage de forma automática por cada Actor que teña. Lembrar que o facemos chamando ó método draw do Stage.

O mínimo que temos que poñer é:

        batch.draw(textura,getX(),getY());

Pero se o facemos así, o tamaño da textura será o tamaño que teña ela orixinalmente. Non fará caso do width e height asinados na instrución setBounds. Se queremos que faga caso ó tamaño:

        batch.draw(textura,getX(),getY(),getWidth(),getHeight());

Se queremos que faga caso á rotacións ou outro tipo de operacións sobre o debuxo da textura, teremos que facer uso da versión completa do método draw. public void draw (Texture texture, float x, float y, float originX, float originY, float width, float height, float scaleX, float scaleY, float rotation, int srcX, int srcY, int srcWidth, int srcHeight, boolean flipX, boolean flipY);

Como esta forma é bastante complexa, podemos facer uso dunha variante que consiste en utilizar como primeiro parámetro unha TextureRegion en vez dunha Texture. Lembrar que as TextureRegion están explicadas no punto TextureAtlas.

Se decidimos facelo desta forma, debemos de ter unha TextureRegion:

  1. public class Personaxe extends Actor{
  2.        
  3.         private TextureRegion tr;
  4.        
  5.         Personaxe(){
  6.                 Texture textura = new Texture(Gdx.files.internal("LIBGDX_itin1_nave.png"));
  7.                 tr = new TextureRegion(textura);
  8.                 setBounds(480, 0, 40,40);
  9.         }
  10.          @Override
  11.      public void draw(Batch batch, float alpha){
  12.          batch.draw(tr, getX(), getY(), getWidth()/2, getHeight()/2, getWidth(), getHeight(),
  13.                          1, 1, getRotation());
  14.      }

Os parámetro do método draw serán neste caso: textureregion, posX,posY,OriginX,OriginY, TamX, TamY, escalaX, escalaY, ángulo de rotación.

Porque teríamos que elixir este método ? Veremos posteriormente (e xa vimos no punto do Stage2D UI) que ós actores imos poder asociarlles accións. Se eu asocio unha acción que só mova a Texture/TextureRegion chegaría con poñer:

        batch.draw(textura,getX(),getY(),getWidth(),getHeight());

Pero se eu asocio unha acción que leve consigo unha rotación da textura, necesitará implementar este último caso.

O veremos cun exemplo despois.

  • Liñas 15-18: Aquí poñeríamos as instrucións para mover os nosos actores (o que fixemos no xogo no método update de cada personaxe).

Se imos asociar accións a estes actores teremos que chamar ó método super.act.

Exemplo de código

Imos ver un exemplo no que visualizaremos a nave.

Preparación:

  • Descargade o seguinte arquivo e levalo ó cartafol assets da versión Android.

LIBGDX itin1 nave.png.

  • Crear unha nova clase e cambiar os diferentes proxectos para que carguen dita clase.


Código da clase Stage2D_Actor
Obxectivo: Visualizar unha textura utilizando o Stage.

  1. public class Stage2D_Actor extends ApplicationAdapter {
  2.  
  3.         private Stage stage;
  4.  
  5.         @Override
  6.         public void create () {
  7.  
  8.                 StretchViewport viewPort = new StretchViewport(480,800);
  9.                 stage = new Stage();
  10.                 stage.setViewport(viewPort);
  11.                
  12.                 Personaxe nave = new Personaxe();
  13.                 stage.addActor(nave);
  14.        
  15.                 Gdx.input.setInputProcessor(stage);
  16.                
  17.         }
  18.        
  19.  
  20.         @Override
  21.         public void render() {
  22.                 Gdx.gl.glClearColor(0, 0, 0, 1);
  23.                 Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
  24.                
  25.                 stage.act(Gdx.graphics.getDeltaTime());
  26.                 stage.draw();
  27.         }
  28.         @Override
  29.         public void resize(int width, int height) {
  30.         // TODO Auto-generated method stub
  31.                 stage.getViewport().update(width, height, true);
  32.         }
  33.        
  34.         @Override
  35.         public void dispose() {
  36.  
  37.                 Gdx.input.setInputProcessor(null);
  38.  
  39.                 stage.dispose();
  40.         }
  41. }


  1. public class Personaxe extends Actor{
  2.        
  3.         private Texture textura;
  4.        
  5.         Personaxe(){
  6.                 textura = new Texture(Gdx.files.internal("LIBGDX_itin1_nave.png"));
  7.                 setBounds(480, 0, 40,40);
  8.         }
  9.  
  10.          @Override
  11.      public void draw(Batch batch, float alpha){
  12.         batch.draw(textura,getX(),getY(),getWidth(),getHeight());
  13.      }
  14.      
  15.      @Override
  16.      public void act(float delta){
  17.         super.act(delta);
  18.      }
  19. }

Accións nos Actores

Información na wiki: https://github.com/libgdx/libgdx/wiki/Scene2d#actions

É un dos elementos máis espectaculares que ten este tipo de programación.

O uso da clase Stage vainos permitir facer diferentes accións sobre os actors que o compoñen.

Dispoñemos de 3 tipos de accións:

1. Accións animadas.
2. Accións compostas.
3. Outras accións.


As accións animadas modifican varias propiedades dos actor´s, coma a posición, rotación, escala e factor alfa. Son as seguintes.

  • FadeIn – modifica o factor alfa do actor do valor que teña ó valor 1.
  • FadeOut - modifica o factor alfa do actor do valor que teña ó valor 0.
  • FadeTo - modifica o factor alfa do actor do valor que teña ó valor especificado.
  • MoveBy – move o actor unha distancia especificada.
  • MoveTo – move o actor a unha posición específica.
  • RotateBy – rota o actor engadindo ó ángulo especificado.
  • RotateTo – rota o actor ata un ángulo especificado.
  • ScaleTo – escala o actor ó valor indicado.


Accións compostas combinan múltiple accións en unha:

  • Parallel – executa todas as accións en paralelo. Todas á vez.
  • Sequence – executa todas as accións en secuencia. Unha detrás de outra.


Outras accións:

  • Repeat – repite a acción n-veces.
  • Forever – repite a acción indefinidamente.
  • Delay – retrasa a execución dunha acción o tempo especificado.
  • Remove – elimina o Actor especificado do Stage.


As accións poden aplicarse sobre cada Actor ou sobre o Stage completo.

Por exemplo, imos facer que a pantalla apareza toda negra e vaian aparecendo os compoñentes do Stage.

Para iso temos que utilizar as Accións: Actions.fadeOut e Actions.fadeIn.

  1.   stage.addAction(Actions.fadeOut(0));
  2.   stage.addAction(Actions.fadeIn(4));

Pero podemos facelo doutra forma máis elegante, xa que a acción pode estar composta por moitas accións as cales se poden executar en paralelo, secuencial, .... como vimos antes.

  1. stage.addAction(Actions.sequence(Actions.fadeOut(0),Actions.fadeIn(4)));


Nota: Ós propios actores poden ter accións asociadas, chamando o método addAction de cada un deles.


Nota: Para non ter que estar escribindo continuamente Actions.acción podemos facer este import:

import static com.badlogic.gdx.scenes.scene2d.actions.Actions.*;


Agora é cando entra en xogo o método draw utilizado na clase Personaxe.

Imaxinemos que queremos que a nave se mova de forma indefinida de esquerda a dereita (nun tamaño de pantalla fixo de 480x800 unidades).

A acción a engadir á nave será:

nave.addAction(Actions.forever(Actions.sequence(Actions.moveTo(0, nave.getY(),5),Actions.moveTo(480-nave.getWidth(), nave.getY(),5))));

Como vemos temos:

  • Actions.forever: Repite de forma indefinida a acción que ven a continuación.
  • Actions.sequence: Executa na orde indicada o conxunto de accións que veñen a continuación.
  • Actions.moveTo(0, nave.getY(), 5),Actions.moveTo(0, nave.getY(), 5): Move cara a coordenada (0,posición Y da nave) a nave cunha duración de 5 segundos e move cara posición (480-nave.getWidth(),posición Y da nave) cunha duración de 5 segundos.

Isto o vai poder facer xa que no método draw temos:

       batch.draw(textura,getX(),getY(),getWidth(),getHeight());
  1.                 Personaxe nave = new Personaxe();
  2.                 nave.addAction(Actions.forever(Actions.sequence(Actions.moveTo(0, nave.getY(),5),Actions.moveTo(480-nave.getWidth(), nave.getY(),5))));
  3.                 stage.addActor(nave);

Nota: Probádeo.

Agora imaxinemos que o mesmo tempo queremos rotar a nave 360 grados en 5 segundos.

A acción a engadir:

  1.                 Personaxe nave = new Personaxe();
  2.                 nave.addAction(Actions.forever(Actions.sequence(Actions.moveTo(0, nave.getY(),5),Actions.moveTo(480-nave.getWidth(), nave.getY(),5))));
  3.                 nave.addAction(Actions.rotateBy(360, 5));
  4.                 stage.addActor(nave);

Pero que vai pasar ? Que o método draw non ten o rotate polo que non fará nada (de feito da un null pointer exception)

Teremos que cambiar o método draw pola versión completa utilizando un TextureRegion:

  1. import com.badlogic.gdx.Gdx;
  2. import com.badlogic.gdx.graphics.Texture;
  3. import com.badlogic.gdx.graphics.g2d.Batch;
  4. import com.badlogic.gdx.graphics.g2d.TextureRegion;
  5. import com.badlogic.gdx.scenes.scene2d.Actor;
  6.  
  7. public class Personaxe extends Actor{
  8.        
  9.         private TextureRegion tr;
  10.        
  11.         Personaxe(){
  12.                 Texture textura = new Texture(Gdx.files.internal("LIBGDX_itin1_nave.png"));
  13.                 tr = new TextureRegion(textura);
  14.                 setBounds(480, 0, 40,40);
  15.         }
  16.  
  17.          @Override
  18.      public void draw(Batch batch, float alpha){
  19.          batch.draw(tr, getX(), getY(), getWidth()/2, getHeight()/2, getWidth(), getHeight(),
  20.                          1, 1, getRotation());
  21.      }
  22.      
  23.      @Override
  24.      public void act(float delta){
  25.         super.act(delta);
  26.      }
  27. }


O resultado:

LIBGDX UD3 Stage 1.jpg

Xestión de Eventos

Introdución

O Stage xestiona os eventos que se producen entre os actores que o conforman.

No que se refire á xestión dos choques entre elementos, poderíamos xestionar os eventos como fixemos no desenvolvemento do xogo, facendo uso da clase Intersector como vimos anteriormente. Teríamos que percorrer todos os actores que conforman o Stage e comprobar se chocan entre eles ou con outros personaxes que non sexan Actor´s.

Se o facemos desta última forma, teremos que crear un obxecto da clase Rectangle dentro do Actor e actualizalo cando se mova no método act:


C¢digo da clase Personaxe
Obxectivo: Crear un obxecto da clase Rectangle para xestionar os choques.

  1. import com.badlogic.gdx.Gdx;
  2. import com.badlogic.gdx.graphics.Texture;
  3. import com.badlogic.gdx.graphics.g2d.Batch;
  4. import com.badlogic.gdx.graphics.g2d.TextureRegion;
  5. import com.badlogic.gdx.math.Rectangle;
  6. import com.badlogic.gdx.scenes.scene2d.Actor;
  7.  
  8. public class Personaxe extends Actor{
  9.        
  10.         private TextureRegion tr;
  11.         private Rectangle bounds;
  12.        
  13.         Personaxe(){
  14.                 Texture textura = new Texture(Gdx.files.internal("LIBGDX_itin1_nave.png"));
  15.                 tr = new TextureRegion(textura);
  16.                 setBounds(480, 0, 40,40);
  17.                
  18.                 bounds = new Rectangle();
  19.         }
  20.  
  21.          @Override
  22.      public void draw(Batch batch, float alpha){
  23.          batch.draw(tr, getX(), getY(), getWidth()/2, getHeight()/2, getWidth(), getHeight(),
  24.                          1, 1, getRotation());
  25.      }
  26.      
  27.      @Override
  28.      public void act(float delta){
  29.         super.act(delta);
  30.         bounds.set(getX(),getY(),getWidth(),getHeight());
  31.    
  32.      }
  33.  
  34.      public Rectangle getBounds(){
  35.          return bounds;
  36.      }
  37.  
  38.                
  39. }


Como comentamos antes, o Stage xestiona os eventos que se producen nos actores.

  1.         @Override
  2.         public void create () {
  3.                 ..........
  4.                 Gdx.input.setInputProcessor(stage);
  5.                
  6.         }


  • Se necesitamos xestionar os eventos da forma tradicional (cunha interface InputProcessor ou GestureListener) teremos que engadir as dúas formas como vimos neste apartado.


Á hora de xestionar os eventos veremos que os Actor´s levan consigo a Interface que vai xestionar o seu propio evento de Click.

Dita interface vai facer uso do método hit.

  • Método hit: Dito método se chama de forma automática e controla cando un Actor é 'tocado' polo usuario premendo sobre a pantalla.

O código que ven por defecto neste método e para controlar unha forma rectangular. Se temos que controlar unha forma diferente (non rectangular), deberemos sobreescribilo e devolver o Actor en función de que se colisione ou non.

O método leva dous coordenadas que son as coordenadas no que o usuario preme a pantalla. Se o personaxe (actor) se toca, debemos facer un return do mesmo. En caso contrario debemos de devolver un null. Debemos comprobar se o actor en Touchable (se pode tocar) e se é visible.

Por exemplo:

  1.         // This hit() instead of checking against a bounding box, checks a bounding circle.
  2.         public Actor hit(float x, float y, boolean touchable){
  3.             // If this Actor is hidden or untouchable, it cant be hit
  4.             if(!this.isVisible() || this.getTouchable() == Touchable.disabled)
  5.                 return null;
  6.            
  7.             // Get centerpoint of bounding circle, also known as the center of the rect
  8.             float centerX = getWidth()/2;
  9.             float centerY = getHeight()/2;
  10.            
  11.             // Calculate radius of circle
  12.             float radius = (float) Math.sqrt(centerX * centerX +
  13.                     centerY * centerY);
  14.  
  15.             // And distance of point from the center of the circle
  16.             float distance = (float) Math.sqrt(((centerX - x) * (centerX - x))
  17.                     + ((centerY - y) * (centerY - y)));
  18.            
  19.             // If the distance is less than the circle radius, it's a hit
  20.             if(distance <= radius) return this;
  21.            
  22.             // Otherwise, it isnt
  23.             return null;
  24.         }
  25.     }

Nota: Exemplo de código obtido de http://www.gamefromscratch.com/post/2013/12/11/LibGDX-Tutorial-3C-Scene-management.aspx


Un Actor só terá en conta os eventos se é clickable e é visible.

Podemos cambiar o estado dun Actor chamando ós métodos:

  • setTouchable
  • setVisible

Por exemplo:

  1.         nave.setTouchable(Touchable.disabled);
  2.         nave.setVisible(true);

Sendo nave un obxecto pertencente á clase Actor.


Interface

Unha vez temos un Actor engadido ó Stage, é clickeable e está visible podemos xestionar os eventos que se producen sobre el facendo uso das interfaces:

Nese enlace tedes todos os métodos / eventos que podemos xestionar.

Exemplos de eventos serían:

  • Facer click sobre o actor.
  • Arrastrar o rato (drag).
  • Levantar o rato.

.....

Un exemplo:

  1. public class Personaxe extends Actor{
  2.  
  3.         ..........
  4.         Personaxe(){
  5.              ..........
  6.                 xestionarEventos();
  7.         }
  8.         private void xestionarEventos(){
  9.                 addListener(new InputListener(){
  10.                          public boolean touchDown(InputEvent event, float x, float y, int pointer, int buttons){
  11.                              return true;
  12.                          }
  13.                          public void touchUp(InputEvent event, float x, float y, int pointer, int buttons){
  14.                          }
  15.                          public void touchDragged (InputEvent event, float x, float y, int pointer) {
  16.                          }
  17.                 });
  18.                
  19.         }
  20. }


Exemplo de eventos que podemos capturar con dita interface temos:

  • Pam.
  • Zoom.
  • Evento de premer durante un tempo longo.

Un exemplo:

  1. public class Personaxe extends Actor{
  2.  
  3.         ..........
  4.         Personaxe(){
  5.              ..........
  6.                 xestionarEventos();
  7.         }
  8.         private void xestionarEventos(){
  9.  
  10.                 addListener(new ActorGestureListener(){
  11.                         public boolean longPress(Actor actor, float x, float y){
  12.                                 Gdx.app.log("FIRE!!!", "PREMEMOS DURANTE UN TEMPO LONGO");
  13.                                 return true;
  14.                         }
  15.                        
  16.                 });
  17.                
  18.         }
  19. }



Exemplo de código

Neste exemplo imos ver como a nave se move de esquerda a dereita na parte superior e aparecerá no centro un alien.

Ó premer sobre o alien, este irá cara arriba. Se toca a nave esta se fará máis pequena.

Preparación:

  • Descargade o seguinte arquivo e levalo ó cartafol assets da versión Android.

LIBGDX itin1 nave.png. LIBGDX itin1 alien.png.

  • Crear unha nova clase de nome Stage2D_Actor_2 e cambiar os diferentes proxectos para que carguen dita clase.


Código da clase Personaxe
Obxectivo: Modeliza a nave e o alien.

  1. import com.badlogic.gdx.Gdx;
  2. import com.badlogic.gdx.graphics.Texture;
  3. import com.badlogic.gdx.graphics.g2d.Batch;
  4. import com.badlogic.gdx.graphics.g2d.TextureRegion;
  5. import com.badlogic.gdx.math.Rectangle;
  6. import com.badlogic.gdx.math.Vector2;
  7. import com.badlogic.gdx.scenes.scene2d.Actor;
  8.  
  9. public class Personaxe extends Actor{
  10.        
  11.         private TextureRegion tr;
  12.         private Rectangle bounds;
  13.        
  14.         Personaxe(Vector2 pos, String grafico){
  15.                 Texture textura = new Texture(Gdx.files.internal(grafico));
  16.                 tr = new TextureRegion(textura);
  17.                
  18.                
  19.                 setBounds(pos.x,pos.y, 40,40);
  20.                
  21.                 bounds = new Rectangle();
  22.         }
  23.  
  24.          @Override
  25.      public void draw(Batch batch, float alpha){
  26.          batch.draw(tr, getX(), getY(), getWidth()/2, getHeight()/2, getWidth(), getHeight(),
  27.                          1, 1, getRotation());
  28.      }
  29.      
  30.      @Override
  31.      public void act(float delta){
  32.         super.act(delta);
  33.         bounds.set(getX(),getY(),getWidth(),getHeight());
  34.    
  35.      }
  36.  
  37.  
  38.      public Rectangle getBounds(){
  39.          return bounds;
  40.      }
  41.      
  42.                
  43. }

Desta clase non hai nada que explicar xa que é a usada nos exercicios anteriores. O único diferente é o constructor no que lle enviamos a posición nun Vector2 e o nome do gráfico a cargar.


C¢digo da clase AlienStage
Obxectivo: Representa o alien. É necesario crear unha clase xa que imos xestionar o evento de click sobre ela.

  1. import com.badlogic.gdx.math.Vector2;
  2. import com.badlogic.gdx.scenes.scene2d.Actor;
  3. import com.badlogic.gdx.scenes.scene2d.InputEvent;
  4. import com.badlogic.gdx.scenes.scene2d.InputListener;
  5. import com.badlogic.gdx.scenes.scene2d.actions.Actions;
  6. import com.badlogic.gdx.scenes.scene2d.actions.MoveToAction;
  7.  
  8. public class AlienStage extends Personaxe{
  9.        
  10.         private MoveToAction action;
  11.        
  12.         AlienStage(Vector2 pos, String grafico){
  13.                 super(pos,grafico);
  14.                
  15.                 xestionarEventos();
  16.         }
  17.  
  18.         private void xestionarEventos(){
  19.                 addListener(new InputListener(){
  20.                          public boolean touchDown(InputEvent event, float x, float y, int pointer, int buttons){
  21.                                  action = Actions.moveTo(getX(), AlienStage.this.getStage().getViewport().getViewportHeight(), 3);
  22.                                  addAction(action);
  23.                      return true;
  24.                     }
  25.                 });
  26.                
  27.         }
  28.        
  29.     @Override
  30.     public void act(float delta){
  31.         super.act(delta);
  32.        
  33.         if (getY()>=getStage().getViewport().getViewportHeight())
  34.                 setY(100);
  35.        
  36.         for (Actor actor : getStage().getActors()){
  37.                 if (actor.getName()=="nave") {
  38.                         Personaxe nave = (Personaxe)actor;
  39.                         if (nave.getBounds().overlaps(getBounds())){
  40.                                 nave.setSize(nave.getWidth()-5, nave.getHeight()-5);
  41.                                 removeAction(action);
  42.                                 setPosition(240, 100);
  43.                                 return;
  44.                         }
  45.                 }
  46.         }
  47.     }
  48.      
  49.                
  50. }
  • Liña 10: Imos gardar a acción do Alien de subir cando prememos sobre el. Isto vai ser necesario xa que cando choque coa nave debemos de eliminar dita acción.
  • Liñas 19-25: Xestionamos o click sobre o alien. Nese caso engadimos unha acción que consiste en mover o alien cara arriba durante 3 segundos.
  • Liñas 33-34: Se o alien chega á parte de arriba (viewportHeight) volve a colocarse na parte baixa.
  • Liña 36: Percorremos o stage obtendo cada un dos actores do mesmo.
  • Liña 37: Veremos despois que antes de engadir ó stage o actor, damos un nome para identificalo. Nesta liña comprobamos se o actor é a nave.
  • Liña 38: Convertemos o actor e un obxecto da clase Personaxe.
  • Liña 39: Comprobamos se chocan o Alien e a nave.
  • Liñas 40-43: En caso de chocar modificamos o tamaño da nave e movemos ó alien a súa posición inicial eliminando a acción de mover cara arriba.


Código da clase Stage2D_Actor_2
Obxectivo: Xestiona todo o stage.

  1. import com.badlogic.gdx.ApplicationAdapter;
  2. import com.badlogic.gdx.Gdx;
  3. import com.badlogic.gdx.graphics.GL20;
  4. import com.badlogic.gdx.math.Vector2;
  5. import com.badlogic.gdx.scenes.scene2d.Stage;
  6. import com.badlogic.gdx.scenes.scene2d.actions.Actions;
  7. import com.badlogic.gdx.utils.viewport.StretchViewport;
  8.  
  9. public class Stage2D_Actor_2 extends ApplicationAdapter {
  10.  
  11.         private Stage stage;
  12.        
  13.  
  14.         @Override
  15.         public void create () {
  16.  
  17.                 StretchViewport viewPort = new StretchViewport(480,800);
  18.                 stage = new Stage();
  19.                 stage.setViewport(viewPort);
  20.                
  21.                 Personaxe nave = new Personaxe(new Vector2(800,700),"LIBGDX_itin1_nave.png");
  22.                 nave.addAction(Actions.forever(Actions.sequence(Actions.moveTo(0, nave.getY(),5),Actions.moveTo(480-nave.getWidth(), nave.getY(),5))));
  23.                 nave.setName("nave");
  24.                
  25.                 AlienStage alien = new AlienStage(new Vector2(240,100),"LIBGDX_itin1_alien.png");
  26.                 alien.setName("alien");
  27.                                
  28.                 stage.addActor(nave);
  29.                 stage.addActor(alien);
  30.        
  31.                 Gdx.input.setInputProcessor(stage);
  32.                
  33.         }
  34.        
  35.  
  36.         @Override
  37.         public void render() {
  38.                 Gdx.gl.glClearColor(0, 0, 0, 1);
  39.                 Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
  40.                
  41.                 stage.act(Gdx.graphics.getDeltaTime());
  42.                 stage.draw();
  43.                
  44.  
  45.                
  46.         }
  47.         @Override
  48.         public void resize(int width, int height) {
  49.         // TODO Auto-generated method stub
  50.                 stage.getViewport().update(width, height, true);
  51.         }
  52.        
  53.         @Override
  54.         public void dispose() {
  55.  
  56.                 Gdx.input.setInputProcessor(null);
  57.  
  58.                 stage.dispose();
  59.         }
  60.  
  61.  
  62. }


O executar teremos como resultado isto:

LIBGDX UD3 Stage 2.jpg



-- Angel D. Fernández González -- (2015).