Tutorial 4 - Andengine más a fondo

Buenas noches a todos. Hoy iremos más a fondo para entender a este fascinante motor de juegos.

Andengine en su implementación, se basa en un modelo llamado entity-component, es un modelo usado por muchos otros motores de juego y lo que hace es heredar todas sus clases de Entity. La clase entity tiene la implementación más básica desde la que parten todos los demas objetos: posición, rotación, color, agregar un objeto, quitarlo, entre otras. Esto quiere decir que un Sprite es una Entity, una escena es una entity, un texto es una entity.



Qué quiere decir esto? Pues, que podemos agregarle cualquier entidad a cualquier entidad. Todavia no? Ejemplo:

[code language="java"]
otroSprite.attachChild(entidad);
miSprite.attachChild(otroSprite);
escena.attachChild(miSprite);
[/code]

Ahora si? Pues eso es lo que hace que andengine sea tan bueno, la capacidad de poder usarlo como a uno se le antoje! Hoy puedo decidir dejar de usar escenas y usar entidades, o usar entidades como capas(sobre esto se hara un tutorial aparte), etc.

Incluso sobre este alcance, hay varios modelos que los usuarios de andengine han prensentado como modelos a seguir, por ejemplo está el modelo que solo usa entidades y nunca escenas, tambien está el modelo que prefiere escenas, hay otros que usan actividades pero es una locura.

Por ejemplo si queremos construir un personaje complejo, que tenga varias partes, podemos usar un AnimatedSprite y agregarle más AnimatedSprite's o Sprite's. Veamos un ejemplo:

Primera crearemos dos sprites(ya saben, cargamos las texturas para luego hacer los sprites) y luego haremos esto:

[code language="java"]
charSprite = new Sprite(200, 200, texturaChar, getVertexBufferObjectManager());
//si la vamos a unir a un Sprite, debemos tener en cuenta que nuestras coordenadas ahora son diferentes
//porque son relativas al sprite al que la vamos a agregar
accesorioSprite = new Sprite(charSprite.getWidth()*0.5f, charSprite.getHeight(), texturaAcc, getVertexBufferObjectManager());
charSprite.attachChild(accesorioSprite);

sceneEjemplo.attachChild(charSprite);
[/code]

Aquí el codigo completo de la sesión :

[code language="java"]
import java.io.IOException;

import org.andengine.audio.music.Music;
import org.andengine.audio.music.MusicFactory;
import org.andengine.audio.sound.Sound;
import org.andengine.audio.sound.SoundFactory;
import org.andengine.engine.camera.Camera;
import org.andengine.engine.options.EngineOptions;
import org.andengine.engine.options.ScreenOrientation;
import org.andengine.engine.options.WakeLockOptions;
import org.andengine.engine.options.resolutionpolicy.FillResolutionPolicy;
import org.andengine.entity.scene.IOnSceneTouchListener;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.sprite.AnimatedSprite;
import org.andengine.entity.sprite.Sprite;
import org.andengine.entity.text.Text;
import org.andengine.input.touch.TouchEvent;
import org.andengine.opengl.font.Font;
import org.andengine.opengl.font.FontFactory;
import org.andengine.opengl.texture.ITexture;
import org.andengine.opengl.texture.TextureOptions;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.andengine.opengl.texture.region.ITextureRegion;
import org.andengine.opengl.texture.region.ITiledTextureRegion;
import org.andengine.ui.activity.SimpleBaseGameActivity;

import android.graphics.Color;




public class MainActivity extends SimpleBaseGameActivity implements IOnSceneTouchListener {

private Camera mCamera;
private static int WIDTH = 800;
private static int HEIGHT= 480;

private BitmapTextureAtlas miAtlas;
private ITextureRegion texturaChar;
private ITextureRegion texturaAcc;
private Sprite charSprite;
private Sprite accesorioSprite;
private ITiledTextureRegion texturaAnimada;
private AnimatedSprite spriteAnimado;
private Font miFuente;
private Sound miSonido;
private Music miMusica;
private Text miTexto;
private int cuenta = 0;
private float factorDeMovimiento = 50;

@Override
public EngineOptions onCreateEngineOptions() {


// Definimos nuestra camara
mCamera = new Camera(0, 0, WIDTH, HEIGHT);
// Ahora declaramos las opciones del motor
EngineOptions engineOptions = new EngineOptions(true, ScreenOrientation.LANDSCAPE_FIXED, new FillResolutionPolicy(), mCamera);
//EngineOptions(es full screen?, Cual es la orientacion de la pantalla?, Como actuaremos ante distintas resoluciones?, y la camara)

//para activar el uso de sonido, debemos activar la opcion
engineOptions.getAudioOptions().setNeedsSound(true);
//para activar la musica
engineOptions.getAudioOptions().setNeedsMusic(true);

// impedimos que la pantalla se apague por inactividad
engineOptions.setWakeLockOptions(WakeLockOptions.SCREEN_ON);
// Return the engineOptions object, passing it to the engine
return engineOptions;



}

@Override
protected void onCreateResources() throws IOException {

//primero debemos indicar donde estan las imagenes
BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");
//luego crear el atlas, darle medidas y un tipo de textura.
miAtlas = new BitmapTextureAtlas(getTextureManager(), 800, 800, TextureOptions.DEFAULT);
//ubicamos nuestra imagen en el atlas
texturaChar = BitmapTextureAtlasTextureRegionFactory.createFromAsset(miAtlas, this, "char.png", 0, 0);
texturaAcc = BitmapTextureAtlasTextureRegionFactory.createFromAsset(miAtlas, this, "accesorio.png", 0, 96);

//Aqui ubicamos el sprite para que no se ubique sobre el anterior
//Osea teniendo en cuenta que el anterior estaba en 0,0 y ocupa hasta 75,95
//Lo ubicaremos despues 76 en x, 0 en y, e indicamos que tiene 10 columnas y 10 filas.
texturaAnimada = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(miAtlas, this, "animado.png", 76, 0, 10, 10);

//y la cargamos
miAtlas.load();

//Aqui hemos creado un atlas de 256 x 256 para cargar una imagen de 108 x 253
//en el punto 0,0 de miAtlas, osea nos sobra espacio



//Indicamos donde se ubican las fuentes
FontFactory.setAssetBasePath("fuentes/");
//aqui creamos la textura donde cargaremos la fuente
final ITexture fontTexture = new BitmapTextureAtlas(getTextureManager(), 256, 256, TextureOptions.BILINEAR);
//Aqui definimos cual es la fuente, tamaño, si usara antialias y su color
miFuente = FontFactory.createFromAsset(getFontManager(), fontTexture, getAssets(), "fuente.ttf", 40, true, Color.WHITE);
//La cargamos
miFuente.load();




try
{
//creo que la explicacion está demas
//lo que si indico es que tambien hay una clase musica
//pero se usa para canciones más largas
//y que se repiten constantemente
miSonido = SoundFactory.createSoundFromAsset(getEngine().getSoundManager(), this, "sonido/sonido.mp3");
//esto quiere decir que no se repite constantemente
miSonido.setLooping(false);
}
catch (IOException e)
{
e.printStackTrace();
}





try
{
miMusica = MusicFactory.createMusicFromAsset(mEngine.getMusicManager(), this,"musica/musica.mp3");
miMusica.setLooping(true);
}
catch (IOException e)
{
e.printStackTrace();
}





}

@Override
protected Scene onCreateScene() {

miMusica.setVolume(0.5f);
miMusica.play();

Scene sceneEjemplo = new Scene();

//para que el callback onSceneTouchEvent funcione
//debemos asignarlo a una escena, de esta forma:
sceneEjemplo.setOnSceneTouchListener(this);

miTexto = new Text(mCamera.getWidth()*0.2f, mCamera.getHeight()*0.8f, miFuente, "Click:1234567890", getVertexBufferObjectManager());
miTexto.setText("Click: " + cuenta);



charSprite = new Sprite(200, 200, texturaChar, getVertexBufferObjectManager());

//si la vamos a unir a un Sprite, debemos tener en cuenta que nuestras coordenadas ahora son diferentes
//porque son relativas al sprite al que la vamos a agregar
accesorioSprite = new Sprite(charSprite.getWidth()*0.5f, charSprite.getHeight(), texturaAcc, getVertexBufferObjectManager());
charSprite.attachChild(accesorioSprite);



sceneEjemplo.attachChild(charSprite);
sceneEjemplo.attachChild(miTexto);


return sceneEjemplo;
}

@Override
public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent) {

if(pSceneTouchEvent.isActionDown()){
cuenta++;
miTexto.setText("Click: "+ cuenta);

if(charSprite.getX() >= mCamera.getWidth())
factorDeMovimiento*=-1;


if(charSprite.getX() <= 0)
factorDeMovimiento*=-1;


charSprite.setX(charSprite.getX() + factorDeMovimiento);


}


return false;
}

}

[/code]

El resultado es este:

tutorial 4

Comentarios

  1. Este es el mismo ejemplo continuación del Tutorial 3? mi proyecto todavía se llama WaterTest, seria bueno ir siguiendo un ejemplo solamente de ser posible e ir agregándole funcionalidades mientras avanzamos.

    No se si tengo que crear otro proyecto para cada Post o es continuación del anterior??

    ResponderEliminar
  2. Es el mismo. Y si se agrega funcionalidad mientras avanzamos. Salvo el tutorial 4 que solo quitamos el sprite animado del sátiro y usamos un personaje compuesto por dos sprites simples.

    ResponderEliminar
  3. Hago una consulta, Resulta que nunca puedo usar throws IOException en esta linea
    protected void onCreateResources() throws IOException
    me sale este error de java:

    IOException is not compatible with throws clause in SimpleBaseGameActivity.onCreateResources() Java Problem

    Quitando el throws IOException del código todo funciona bien sin errores.
    tengo configurado usar el java 1.6 en el projecto.

    ResponderEliminar
  4. Podrias facilitarnos el accesorio? . Muy buen tutorial!!!. Descargue tu juego y ojala llegue a desarrollar algo similar :)

    ResponderEliminar
  5. Muy bueno el tutorial! Vengo siguiendo los ejemplos hasta aqu. Me costo instalar el andengine, porque tenía un problema que decía que faltaba andengine.apk. Luego me di cuenta que era porque tenia que importar el git en el workspace. En este ejemplo, cundo hiciste el copy an paste a la web se copiaron mal algunas cosas del código. Donde dice &quot hay que poner comillas dobles, y donde dice &gt va el signo <, lo mismo para mayor.
    Muchas Gracias.

    ResponderEliminar

Publicar un comentario

Entradas populares de este blog