lunes, 28 de marzo de 2016

Cosas Geek y Mas...

Hola buenas.

Les quería compartir una pagina hermana destinada a noticias, curiosidades, ciencias, móviles, programación, tecnologías y mas xD 
Pueden visitarla aquí: http://www.geeks503.com/
Un Saludo.

martes, 22 de marzo de 2016

Tutorial 6: Animaciones 2D

Hola buenas.
En esta ocasión veremos como animar sprites para nuestros personales, Es perfecto para crear ese dinamismo. En esta ocacion ocuparemos unos sprite descargados de: http://opengameart.org/content/jack-o-lantern-free-sprite 
Antes que todo vamos a preparar las imagenes, ya que son muy grandes. Con Gimp redimensionaremos las imagenes a 100x132 pixeles. Solo utilizaremos tres estados, el estar parado, caminando y corriendo.
Para lograr esto:

Manos a la obra.
Generamos el proyecto:

E importamos en eclipse:

En la carpeta assets de nuestro sub proyecto de android agregamos las carpetas "idle", "walk" y "run", donde estarán nuestras imágenes ya listas. Estas imágenes las van a encontrar en el código fuentes, que pondré al final.

Codigo:
Clase Tuto4;
package sv.chuckles.tuto4;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;

public class Tuto4 extends ApplicationAdapter {
SpriteBatch batch;
float stateTime;
Animation aniIdle, aniWalk, aniRun;
@Override
public void create () {
batch = new SpriteBatch();
//carga de imaganes del descanso
TextureRegion[] keyFramesIdle = {
new TextureRegion(new Texture("idle/idle_1.png")),
new TextureRegion(new Texture("idle/idle_2.png")),
new TextureRegion(new Texture("idle/idle_3.png")),
new TextureRegion(new Texture("idle/idle_4.png")),
new TextureRegion(new Texture("idle/idle_5.png")),
new TextureRegion(new Texture("idle/idle_6.png")),
new TextureRegion(new Texture("idle/idle_7.png")),
new TextureRegion(new Texture("idle/idle_8.png")),
new TextureRegion(new Texture("idle/idle_9.png")),
new TextureRegion(new Texture("idle/idle_10.png"))
}; 
aniIdle = new Animation(0.075f, keyFramesIdle);
//carga de imaganes caminando
TextureRegion[] keyFramesWalk = {
new TextureRegion(new Texture("walk/walk_1.png")),
new TextureRegion(new Texture("walk/walk_2.png")),
new TextureRegion(new Texture("walk/walk_3.png")),
new TextureRegion(new Texture("walk/walk_4.png")),
new TextureRegion(new Texture("walk/walk_5.png")),
new TextureRegion(new Texture("walk/walk_6.png")),
new TextureRegion(new Texture("walk/walk_7.png")),
new TextureRegion(new Texture("walk/walk_8.png")),
new TextureRegion(new Texture("walk/walk_9.png")),
new TextureRegion(new Texture("walk/walk_10.png"))
}; 
aniWalk = new Animation(0.075f, keyFramesWalk);
//carga de imagenes corriendo
TextureRegion[] keyFramesRun = {
new TextureRegion(new Texture("run/run_1.png")),
new TextureRegion(new Texture("run/run_2.png")),
new TextureRegion(new Texture("run/run_3.png")),
new TextureRegion(new Texture("run/run_4.png")),
new TextureRegion(new Texture("run/run_5.png")),
new TextureRegion(new Texture("run/run_6.png")),
new TextureRegion(new Texture("run/run_7.png")),
new TextureRegion(new Texture("run/run_8.png"))
}; 
aniRun = new Animation(0.07f, keyFramesRun);

stateTime = 0;
}

@Override
public void render () {
Gdx.gl.glClearColor(0.5f, 0.5f, 0.5f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stateTime += Gdx.graphics.getDeltaTime();
batch.begin();
batch.draw(aniIdle.getKeyFrame(stateTime, true), 0, 0);
batch.draw(aniWalk.getKeyFrame(stateTime, true), 0, 170);
batch.draw(aniRun.getKeyFrame(stateTime, true), 0, 340);
batch.end();
}
@Override
public void dispose() {
batch.dispose();
}
}

Al ejecutarlo, veremos:

Explicación:
En la declaración de variables, veremos:
  1. float stateTime: Este flotante sera utilizado para acumular el tiempo que transcurre desde el ultimo frame en segundos. para que las animaciones sean pintadas de forma sincronizadas y correctas.
  2. Animation aniIdle, aniWalk, aniRun: Estas variables son las encargadas de almacenar todas nuestras imágenes y que ordenan las animaciones. La variable aniIdle es para el personaje en animación parado, aniWalk para la animación caminando y aniRun para la animación corriendo.
Método create:
  1. Lineas 20 a 31: Creamos un arreglo TextureRegion, donde cargaremos nuestras imágenes cuando el personaje esta parado, las imagines son del 1 al 10 de la carpeta "idle".
  2. Linea 32 - aniIdle = new Animation(0.075f, keyFramesIdle): Instanciamos la clase y le enviamos de parámetro tiempo en segundos que se ejecuta una frame después del otro. Para este caso 0.075 Seg. Y el ultimo parámetro es el arreglo de los imágenes.
  3. Lineas 35 a 47: Igual que el literal anterior. Con la variante que es para la animación de caminar.
  4. Lineas 50 a 60: Lo mismo solo que con la variante de las imágenes de correr.
Metodo render:
  1. stateTime += Gdx.graphics.getDeltaTime(): Es el acumulador ya descrito en la sección 1 de la Explicación.
  2. batch.draw(aniIdle.getKeyFrame(stateTime, true), 0, 0): Pintamos el frame actual, calculado por el stateTime en la posición (0,0), también se indica con el parámetro "true" que es un ciclo infinito, osea se repiten siempre las animaciones.
  3. batch.draw(aniWalk.getKeyFrame(stateTime, true), 0, 170): Igual que el literal anterior, solo que se pinta la animación de caminar en la posición (0,170).
  4. batch.draw(aniRun.getKeyFrame(stateTime, true), 0, 340): Igual que el literal anterior, solo que se pinta la animación de correr en la posición (0,340).
Ejecutamos esto, y veremos nuestras animaciones en acción xD
Ahora bien, que se necesita para pintar animaciones que estén de derecha a izquierda?
Pues hay dos formas, la primera es crear otra animación con las imágenes invertidas en X, pero esto conlleva que cargamos imágenes que ya existen y lo cual no es recomendable hacerlo por rendimiento. Así que la solución mas optima es utilizar nuestro objeto "batch", he indicar que pinte al revés nuestra animación.
Asi: 

batch.draw(aniRun.getKeyFrame(stateTime, true), 600 //posicion en X
,340 //posicion en Y
,-aniRun.getKeyFrame(stateTime).getRegionWidth() //ancho de la imagen
,aniRun.getKeyFrame(stateTime).getRegionHeight() //alto de la imagen
);
Aquí veremos una sobre carga del método "draw", lo importante es que recibe de parámetro extras las dimensiones de las animaciones, entonces ponemos negativo el ancho xD

Ejecutamos:

También lo podemos probar en el emulador o dispositivo:

Código fuente: https://github.com/Solidux/tuto-libgdxelsalvador.blogspot.com/tree/master/tuto4

Espero que todo haya quedado claro xD
Un Saludos

Sigueme en Twiter: https://twitter.com/libgdxESA

Si te gusta mi trabajo y quisieras ver mas y mas rápido, puedes donar $1.00 vía donación paypal:


jueves, 17 de marzo de 2016

Tutorial 5: Detecciones de Colisiones o Choques

Hola Gente.
En esta ocasiona veremos como detectar los choques entre elementos rectangulares y circulares.
Existe también los polígonos, pero por simplicidad veremos estos dos solamente.
Ustedes debes de elegir que tipo utilizar según sean tus necesidades, normalmente se utilizan mas las figuras rectangulares.
Para las detecciones rectangulares utilizaremos la clase "com.badlogic.gdx.math.Rectangle" y para las  circulares utilizaremos la clase "com.badlogic.gdx.math.Circle".

Estrategia:
Crearemos 3 sprites del logo de LibGdx, con las dimensiones 128x128, estos estarán situados en la pantalla en forma de triangulo. Al sprite mas alto sera estático y tendrá asociado un rectángulo igual a sus dimensiones y asociado un circulo que tendrá mas o menos las dimensiones de la imagen circular del logo. Cuando me refiero al termino "asociado", quiero decir que el rectángulo o circulo se van a mover en las mismas posiciones del sprite. Con respecto a los otras sprites, uno sera asociado con un rectángulo y el otro a un circulo; con la finalidad que puedan chocar con el mas alto.

Otra estrategia sera colocar un tinte diferente para diferenciar cada sprite, también moveremos el sprite de la izquierda con las teclas ASWD y el de la derecha con las teclas cursoras.

Comencemos: Lo primero es crear nuestro proyecto:

Importamos nuestro proyecto en eclipse, como ya lo hemos hecho. Un dato importante es que no incluiremos el sub proyecto para android, puesto moveremos nuestros sprite con el teclado.
Clase Tuto3:
package sv.chuckles.tuto3;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.math.Circle;
import com.badlogic.gdx.math.Rectangle;

public class Tuto3 extends ApplicationAdapter {
SpriteBatch batch;
Sprite sprite1,sprite2,sprite3;
Rectangle rec1,rec2;
Circle cir1,cir3;
ShapeRenderer renderer = null;
@Override
public void create () {
batch = new SpriteBatch();
sprite1 = new Sprite(new Texture("badlogic.jpg"));
sprite2 = new Sprite(new Texture("badlogic.jpg"));
sprite3 = new Sprite(new Texture("badlogic.jpg"));
sprite1.setPosition(Gdx.graphics.getWidth()/2-sprite1.getWidth()/2, Gdx.graphics.getHeight()-sprite1.getHeight()-50);
rec1 = new Rectangle(sprite1.getX(), sprite1.getY(), sprite1.getWidth(), sprite1.getHeight());
cir1 = new Circle(sprite1.getX()+sprite1.getWidth()/2, sprite1.getY()+sprite1.getWidth()/2, 50f);
sprite2.setColor(Color.BLUE);
rec2 = new Rectangle(0, 0, sprite2.getWidth(), sprite2.getHeight());
sprite3.setPosition(Gdx.graphics.getWidth()-sprite3.getWidth(),0);
sprite3.setColor(Color.MAGENTA);
cir3 = new Circle(0, 0, 50f);
//Instancia para dibujar la figuras matematicas
//comentarias esta linea si no se quiere ver los rectangulos y circulos dibujados
renderer = new ShapeRenderer();
}

@Override
public void render () {
Gdx.gl.glClearColor(0.5f, 0.5f, 0.5f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
detectarMovimiento(sprite2,false);
detectarMovimiento(sprite3,true);
detectarColisiones();

//pintado de las imagenes en la pantalla
batch.begin();
sprite1.draw(batch);
sprite2.draw(batch);
sprite3.draw(batch);
batch.end();
if(renderer != null){
renderer.begin(ShapeType.Line);
renderer.setColor(Color.GOLD);
renderer.rect(rec1.getX(), rec1.getY(), rec1.getWidth(), rec1.getHeight());
renderer.circle(cir1.x, cir1.y, cir1.radius);
renderer.setColor(Color.WHITE);
renderer.circle(cir3.x, cir3.y, cir3.radius);
renderer.rect(rec2.getX(), rec2.getY(), rec2.getWidth(), rec2.getHeight());
renderer.end();
}
}
private void detectarColisiones() {
//detectar si hay colision entre los rectangulos
if(rec1.overlaps(rec2)){
sprite2.setColor(Color.YELLOW);
}else{
sprite2.setColor(Color.BLUE);
}
if(cir1.overlaps(cir3)){
sprite3.setColor(Color.YELLOW);
}else{
sprite3.setColor(Color.MAGENTA);
}
}

private void detectarMovimiento(Sprite sprite,boolean isKeyCursorPress){
float x = sprite.getX();
float y = sprite.getY();
if(isKeyCursorPress){
if(Gdx.input.isKeyPressed(Keys.LEFT))
x -= 5;
else if(Gdx.input.isKeyPressed(Keys.RIGHT))
x += 5;
if(Gdx.input.isKeyPressed(Keys.UP))
y += 5;
else if(Gdx.input.isKeyPressed(Keys.DOWN))
y -= 5;
}else{
if(Gdx.input.isKeyPressed(Keys.A))
x -= 5;
else if(Gdx.input.isKeyPressed(Keys.D))
x += 5;
if(Gdx.input.isKeyPressed(Keys.W))
y += 5;
else if(Gdx.input.isKeyPressed(Keys.S))
y -= 5;
}
if(x < 0) x=0;
if(y < 0) y=0;
if(x>Gdx.graphics.getWidth()) x=Gdx.graphics.getWidth();
if(y>Gdx.graphics.getHeight()) y=Gdx.graphics.getHeight();
sprite.setPosition(x, y);
//tambien tenemos que mover el rectangulo o el circulo
if(isKeyCursorPress)//si es verdad, movemos el circulo
cir3.setPosition(x+sprite.getWidth()/2, y+sprite.getHeight()/2);
else
rec2.setPosition(x, y);
}
@Override
public void dispose() {
if(renderer != null)
renderer.dispose();
batch.dispose();
}
}

Explicacion:

Declaraciones de objetos: No hay nada del otro mundo. Solo existe este objeto "ShapeRenderer renderer" que es de suma importancia, ya que en el es posible dibujar gráficos primitivos como lineas, rectángulos, círculos, etc. Entonces para ¿qué nos servirá esto?, pues los objetos rectángulos y círculos son lógicos, no son representaciones gráficas y nos auxiliaremos de esta clase.

Método create:
El sprite1 era destinado al estático, que tendrá asociado el rectangular rec1 y el circulo cir1, aquí instanciamos el objeto rec1, que el constructor recibe de parámetros la posición del rectángulo y las dimensiones del ancho y alto, para nuestro caso tendríamos que poner los mismas coordenadas de sprite1: rec1 = new Rectangle(sprite1.getX(), sprite1.getY(), sprite1.getWidth(), sprite1.getHeight());
Para el caso del circulo: cir1 = new Circle(sprite1.getX()+sprite1.getWidth()/2, sprite1.getY()+sprite1.getWidth()/2, 50f); donde se coloca la posicion del centro y su radio.
Creo que aquí todo esta fácil de entender, a esta altura del partido ya debemos de estar muy familiarizados con el código.

Método render:
Aquí esta toda la lógica, encontraremos el método: "detectarMovimiento", el cual detecta que tecla fue tocada y mueva la imagen y su rectángulo o circulo asociado.
Donde nos centraremos es en el método "detectarColisiones", este metodo observamos como se pregunta que el rec1 esta sobre el rec2, si esto es cierto el tinte cambia del sprite2:

Tambien se pregunta que el cir1 esta sobre el cir2, si es cierto también cambia de tinte amarillo:

Podemos ver como funciona las colisiones, mas sencillo imposible xD
Si no quieren ver los rectángulos o círculos dibujado pues comentaríamos la linea 43
Este "ShapeRenderer" es nuestro DEBUG gráfico.


Para el siguiente tutorial, veremos como hacer animaciones
Un Saludos
Sigueme en Twiter: https://twitter.com/libgdxESA

Si te gusta mi trabajo y quisieras ver mas y mas rápido, puedes donar $1.00 vía donación paypal:


martes, 8 de marzo de 2016

Tutorial 4: Ciclo de Vida en LibGdx.

Hola buenas.
En el presente tutorial veremos como se comporta el ciclo de vida en nuestros juegos basados en LibGdx y alguna funcionalidades de la maravillosa clase estática Gdx.

Ciclo básico de cualquier videojuego:
Start: Inicia el juego.
Events: Busca eventos, ya sean lectura de input(teclado,controles,toches,etc), de cálculos de movimientos(desplazamientos de posición), es todo lo que se puede encapsular.
Update: Es la actualización de todos los cálculos, estados del juego.
Draw: Es cuando el juego pinto todos los elementos graficos del juego.
Exit?: Bandera que pregunta si el juego termina o no. Si es "NO", vuelve al proceso de Events y continua al ciclo; Si es "SI", pasa a finalizar el ciclo.
Close: Cierre del juego.

Después de esta pequeña introducción, veremos como funciona en libgdx, cuando creamos nuestros proyectos, la clase principal extiende de ApplicationAdapter, la cual proporciona los siguientes métodos:
@Override
public void create () {
}

@Override
public void resize(int width, int height) {
}
@Override
public void render () {
}

@Override
public void pause() {
}

@Override
public void resume() {
}

@Override
public void dispose() {

}
Podemos observar que este ciclo de vida es extendido del ciclo de vida de los programas en Android.
El ciclo de vida se ejecuta así:
  1. create: método para instanciar nuestros objetos. 
  2. resize: actualiza nuestras resolución de pantalla.
  3. render: este método se ejecuta recurrentemente, y se encarga de hacer todo la lógica de nuestro juego, por ejemplo leer algún input, procesarlo, actualizar alguna posición de sprite, verificar colisiones, etc.
  4. pause: esta acción es llamada por libGdx cuando entra en segundo plano. LibGdx pone en pausa todos los elementos gráficos.
  5. resume: esta acción es llamada cuando la aplicación entra en primer plano.
  6. dispose: esta acción es llamada antes de cerrar la aplicación y es donde hay que liberar todos los recursos utilizados en nuestros juegos.
Construiremos un nuevo proyecto llamado tuto2:

Importamos desde eclipse:
Si hemos sido observadores, veremos que no incluí el proyecto de android, esto lo hice para facilitarme la importación del proyecto. Ustedes pueden incluir el sub proyecto.

En este tutorial veremos, como utilizar la amada clase estática Gdx, esta clase posee cualidades de manipulación de audio, archivos, gráficos, lecturas de input(teclado, mouse, acceletrometro, giroscopio, vibración, toques de pantalla) y configuraciones de nuestra aplicación.
Claro veremos las básicas, y en posteriores entregas las restantes.
Clase Tuto2:
public class Tuto2 extends ApplicationAdapter {

SpriteBatch batch;
Texture img;
Sound sonido;
Music musica;
@Override
public void create () {
batch = new SpriteBatch();
img = new Texture("badlogic.jpg");
Gdx.app.log("Tuto2", "Inicia el programa.");
sonido = Gdx.audio.newSound(Gdx.files.internal("explosion.wav"));
musica = Gdx.audio.newMusic(Gdx.files.internal("fight.wav"));
musica.setLooping(true);
musica.setVolume(0.2f);
musica.play();
}

@Override
public void render () {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
if(Gdx.input.justTouched()){
sonido.play();
Gdx.app.log("Tuto2", "Touch(X,Y):("+Gdx.input.getX()+","+Gdx.input.getY()+")");
}
batch.begin();
batch.draw(img,//logo libgdx
Gdx.graphics.getWidth()/2-img.getWidth()/2,//posicion en X Centrada 
Gdx.graphics.getHeight()/2-img.getHeight()/2//posicion en Y Centrada
);
batch.end();
}
@Override
public void resize(int width, int height) {
Gdx.app.log("Tuto2", "Resolucion: "+Gdx.graphics.getWidth()+"x"+Gdx.graphics.getHeight());
}

@Override
public void pause() {
Gdx.app.log("Tuto2", "Entro en pausa.");
musica.pause();
}

@Override
public void resume() {
Gdx.app.log("Tuto2", "Entro en resumen.");
musica.play();
}

@Override
public void dispose() {
Gdx.app.log("Tuto2", "Entro en dispose.");
img.dispose();
batch.dispose();
musica.dispose();
sonido.dispose();
}
}

Explicación:
En las propiedades de la clase, declaramos Sound sonido, que cargaremos un sonido de explosión, declaramos también Music musica, que cargaremos una música de fondo.
Método create:
  1. Gdx.app.log("Tuto2", "Inicia el programa."): Se utiliza para colocar nuestros mensajes en consola/logcat, para ir trazando nuestros eventos en el juego. Primer parámetro es una etiqueta para identificar el mensaje, segundo parámetro es el menajes mismo.
  2. sonido = Gdx.audio.newSound(Gdx.files.internal("explosion.wav")): Esta instrucción es bien interesante, se observa como se crea un nuevo sonido con solo agregar: Gdx.audio.newSound, pero esta instrucción recibe un parámetro FileHandle, para esto utlizamos el Gdx.files.internal que gestiona todos los archivos que estén ubicados en nuestra carpeta "assets". Entonces esta linea de código esta yendo a buscar el archivo "explosion.wav" a la carpeta "assets" de nuestro proyecto y obtiene su referencia, la cual es pasada a newSound, que instancia nuestro sonido.
  3. musica = Gdx.audio.newMusic(Gdx.files.internal("fight.wav")): Es igual que la instancia del sonido, solo que es aplicado a una musica. El newSound solo funciona con sonidos de corta duracion, para lo demos esta newMusic. Solo pueden ser cargados los archivos WAV, MP3 Y OGG.
  4. musica.setLooping(true): indicamos que la música se vuelva a repetir una vez haya terminado. 
  5. musica.setVolume(0.2f): Ponemos el volumen a 20%.
  6. musica.play(): Le indicamos que comience a tocar la música.
Método render:
  1. if(Gdx.input.justTouched()): Otra vez nuestra amada clase xD, utilizando justTouched nos devuevl true si hemos presionado la pantalla o un click.
  2. sonido.play(): toca el sonido.
  3. Gdx.app.log("Tuto2", "Touch(X,Y):("+Gdx.input.getX()+","+Gdx.input.getY()+")"): Otro momento interesante, utilizamos la lectura de input, getX y getY obtenimos la posicion del puntero o cuando hemos presionado sobre la pantalla.
  4. Gdx.graphics.getWidth()/2-img.getWidth()/2, y Gdx.graphics.getHeight()/2-img.getHeight()/2: en metodo draw ya visto antes, le pasamos la ubicación donde pintara nuestra imagen. Para ello utilizo Gdx.graphics.getWidth() que nos devuelve el ancho de nuestra pantalla y Gdx.graphics.getHeight() que nos devuelve el alto de nuestra pantalla, entonces con un sencillo calculo, ponemos nuestra imagen centrada.
Método resize:
  1. Gdx.app.log("Tuto2", "Resolucion: +Gdx.graphics.getWidth()+"x"+Gdx.graphics.getHeight()): Solo pintamos en consola la nueva resolución cuando cambiamos el tamaño de nuestra pantalla.
Método pause:
  1. Gdx.app.log("Tuto2", "Entro en pausa."): informamos cuando entra en pausa nuestra aplicacion, ya sea quitando el foco o minimizando.
  2. musica.pause(): como entra en pausa la aplicación y la música sigue tocando, le indicamos que se ponga en pausa también. Puedes hacer la prueba comentariando esta linea y ejecutando.
Método resume:
  1. Gdx.app.log("Tuto2", "Entro en resumen."): informamos que entro en resumen.
  2. musica.play(): activamos la música otra vez.
Método dispose:
  1. Gdx.app.log("Tuto2", "Entro en dispose."): informamos que esta en dispose
  2. img.dispose(): liberamos la memoria de la textura.
  3. batch.dispose(): liberamos la memoria del SpriteBatch.
  4. musica.dispose(): liberamos la memoria del objeto Music.
  5. sonido.dispose(): liberamos la memoria del objeto Sound.
Ya podemos ejecutar y observar el comportamiento. Pinchando sobre la ventana y observando la consola.
Si agregaste el sub proyecto de android, debes de colocar los assets del repositorio en tu proyecto de andoid.

Considero que a estas alturas ya tiene mas claro como funciona libGdx
Quizá en el transcurso de la semana hago otro tutorial ya con mas sabor xD
Pienso que ya podemos ver como funcionan las colisiones.
Un Saludos
Sigueme en Twiter: https://twitter.com/libgdxESA

Si te gusta mi trabajo y quisieras ver mas y mas rápido, puedes donar $1.00 vía donación paypal:



martes, 1 de marzo de 2016

Tutorial 3: Corriendo en Android.

Buenas a todos.
En el pasado tutorial aplicamos cierto dinamismo a nuestra plantilla que libGDX nos proporciona. En esta ocasiona veremos como ajustar nuestro ejemplo a un dispositivo real, ya que la emulación no es capaz de imitar el acelerómetro.
El codigo:

package sv.chuckles.tuto1;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;

public class Tuto1 extends ApplicationAdapter {
SpriteBatch batch;
Texture img;
Sprite sprite;

@Override
public void create () {
batch = new SpriteBatch();
img = new Texture("badlogic.jpg");
sprite = new Sprite(img);
sprite.setPosition(200, 100);
sprite.setScale(0.75f);
sprite.setRotation(45);
}

@Override
public void render () {
float rotar = 5;
Gdx.gl.glClearColor(0.5f, 0.5f, 0.5f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
rotar += sprite.getRotation();
if(rotar > 360) rotar = 5;
sprite.setRotation(rotar);

float dirX = Gdx.input.getAccelerometerY();
float dirY = Gdx.input.getAccelerometerX();
float x = sprite.getX();
float y = sprite.getY();

if(dirX == 0){
if(Gdx.input.isKeyPressed(Keys.LEFT))
x -= 5;
else if(Gdx.input.isKeyPressed(Keys.RIGHT))
x += 5;
}else{
if(dirX < 0)
x -= 5;
else
x += 5;
}
if(dirY == 0){
if(Gdx.input.isKeyPressed(Keys.UP))
y += 5;
else if(Gdx.input.isKeyPressed(Keys.DOWN))
y -= 5;
}else{
if(dirY < 0)
y += 5;
else
y -= 5;
}
if(x < 0) x=0;
if(y < 0) y=0;
if(x>Gdx.graphics.getWidth()) x=Gdx.graphics.getWidth();
if(y>Gdx.graphics.getHeight()) y=Gdx.graphics.getHeight();
sprite.setPosition(x, y);
sprite.draw(batch);
batch.end();
}
}

Podemos ejecutarlo en nuestro dispositivo, y movemos el mobil, y veremos como la imagen se mueve de un  lado para otro y girando al mismo tiempo.

Explicacion:
Las lineas float dirX = Gdx.input.getAccelerometerY(); y float dirY = Gdx.input.getAccelerometerX();, es la manera que ligGDX obtiene los valores del acelerómetro, lo importante es que si no detecta o no esta disponible el  acelerometro, libGDX nos devolvera cero.
En la variable x e y, guardamos esos valores del sprite.
Preguntamos si dirX es cero, si es cero significa que no hay acceleracion y verificamos si se ha presionado una tecla cursora.Si es que el valor de dirX es diferente de cero, preguntamos si es negativo, si es negativo restamos 5 pixeles a la posición. Esta misma lógica funciona para X e Y.
Es bien intuitivo saber como funciona.
Vale aclarar las validaciones finales. donde validamos que la posición X no sea negativa ni mayor al ancho de la pantalla. Esto mismo funciona para Y.

Ya Con esto finalizamos los primeros pasos, aquí tiene que practicar.

Esta la siguiente semana, que veremos un tutorial mas tecnico, sin tanta teoria.
Saludos
Sigueme en Twiter: https://twitter.com/libgdxESA

Si te gusta mi trabajo y quisieras ver mas y mas rápido, puedes donar $1.00 vía donación paypal: