jueves, 24 de marzo de 2011

Introducción a AndEngine (Parte III)

Anteriormente en Droideando



Objetivo de hoy


Hoy tenemos varios objetivos:

  • Ponerle una pantalla de splash al juego
  • Crear el fondo realista de un campo de futbol


Pantalla de Splash


Todo juego que se precie tiene que empezar con un splash bien bonito. Vamos a ver como podemos hacer ello con AndEngine. Nos ofrece una clase BaseSplashActivity. Nos vamos en "Package Explorer" a src/com.pruebas.andengine y creamos una nueva clase.



Le ponemos en Name SplashExample, y vamos a SuperClass y le damos a buscar la clase BaseSplashActivity y aceptamos.




Nos genera una clase como esta.OJO: el método getFollowUpActivity por un error del formateador que uso para ésto muestra como comentarios html, ni caso... dejadlo como os lo genera Eclipse.


  1. package com.pruebas.andengine;
  2.  
  3. import org.anddev.andengine.engine.options.EngineOptions.ScreenOrientation;
  4. import org.anddev.andengine.opengl.texture.source.ITextureSource;
  5. import org.anddev.andengine.ui.activity.BaseSplashActivity;
  6.  
  7. import android.app.Activity;
  8.  
  9. public class SplashExample extends BaseSplashActivity {
  10.  
  11. @Override
  12. //Ojo, porque esto no se ve bien aqui, dejadlo como Eclipse lo genera
  13. protected Class<? extends Activity> getFollowUpActivity() {
  14. // TODO Auto-generated method stub
  15. return null;
  16. }
  17.  
  18. @Override
  19. protected ScreenOrientation getScreenOrientation() {
  20. // TODO Auto-generated method stub
  21. return null;
  22. }
  23.  
  24. @Override
  25. protected float getSplashDuration() {
  26. // TODO Auto-generated method stub
  27. return 0;
  28. }
  29.  
  30. @Override
  31. protected ITextureSource onGetSplashTextureSource() {
  32. // TODO Auto-generated method stub
  33. return null;
  34. }
  35.  
  36. }
Parsed in 0.074 seconds at 11.94 KB/s, using GeSHi 1.0.8.10
<


Ahora vamos a tocar algunas de los métodos de la clase para que muestre el splash que queremos. Si no tienes ninguna imagen de splash que quieras usar, puedes bajarte la que pongo a continuación. OJO: Recuerda guardarla como assets/gfx/splash.png




Ahora tocamos la clase para que muestre el splash desde la imagen. primero definimos unas constantes


  1. // ===========================================================
  2. // Constants
  3. // ===========================================================
  4.  
  5. private static final int SPLASH_DURATION = 3;
  6. private static final float SPLASH_SCALE_FROM = 1f;
Parsed in 0.074 seconds at 3.24 KB/s, using GeSHi 1.0.8.10

SPLASH_DURATION define el numero de segundos del splash, 3 está bien. La segunda constante es el origen desde el que se escala... por ejemplo, si pones 0.5f el splash aparecerá pequeñito y llegará a ocupar toda la pantalla.

En el primer procedimiento getFollowUpActivity(), lo que debemos devolver es la Actividad que se va a ejecutar después del splash. En este caso Main.


  1. @Override
  2. protected Class<? extends Activity> getFollowUpActivity() {
  3. return Main.class;
  4. }
Parsed in 0.080 seconds at 1.19 KB/s, using GeSHi 1.0.8.10

En el segundo método getScreenOrientation(), debemos devolver la orientación de la pantalla, en este caso es apaisada.


  1. protected ScreenOrientation getScreenOrientation() {
  2. return ScreenOrientation.LANDSCAPE;
  3. }
Parsed in 0.082 seconds at 1.15 KB/s, using GeSHi 1.0.8.10

Tercer método getSplashDuration(), devolvemos la constante


  1. @Override
  2. protected float getSplashDuration() {
  3. return SPLASH_DURATION;
  4. }
Parsed in 0.077 seconds at 1.01 KB/s, using GeSHi 1.0.8.10

Y por último onGetSplashTextureSource(), que devolvemos la textura que hemos guardado antes en el disco...



  1. protected ITextureSource onGetSplashTextureSource() {
  2. return new AssetTextureSource(this, "gfx/splash.png");
  3. }
  4.  
Parsed in 0.076 seconds at 1.51 KB/s, using GeSHi 1.0.8.10

Ahora implementamos un nuevo método por si queremos hacer el zoom y jugar con él.


  1. protected float getSplashScaleFrom() {
  2. return SPLASH_SCALE_FROM;
  3. }
Parsed in 0.077 seconds at 1.06 KB/s, using GeSHi 1.0.8.10

Bien, ya tenemos la clase del Splash, ahora hay que meterla en el AndroidManifest.xml y poerla por defecto. Para ello nos vamos a editar el AndroidManifest.xml como texto y añadimos la actividad y la ponemos para que se ejecute al empezar el programa.


  1. <activity android:name="SplashExample"
  2.                   android:label="@string/app_name">
  3. <intent-filter>
  4. <action android:name="android.intent.action.MAIN" />
  5. <category android:name="android.intent.category.LAUNCHER" />
  6. </intent-filter>
  7. </activity>
Parsed in 0.004 seconds at 87.19 KB/s, using GeSHi 1.0.8.10


Y eliminamos de la actividad Main los intent-filter para que la única que se ejecute al comenzar el juego sea la del splash. Le damos F11 para correr el proyecto y podmeos ver la pantalla de splash funcionando correctamente.


Creando el fondo del juego


Para crear el fondo del juego hay varias opciones. Primero probé con un RepeatingSpriteBackground, pero no se movía con el scroll de la pantalla, fuera. Mirando por los fuentes de AndEngine he visto una cosa llamada TMXLoader que carga un nivel de un xml y te pone todo en su sitio... me llamó la atención y manos a la obra


Afortunadamente tiene un editor de niveles gratuito y open source para todas las pataformas. Lo primero era crear el sprite con el fondo de cesped. Aqui lo teneis. Como siempre va a assets/gfx.



El sistema para crear niveles se basa en pngs que estén divididos como un tablero de ajedrez, para mi caso necesitaba las cuatro esquinas, arriba, abajo, izquierda, derecha y centro, 9 sprites.



Pongo el png con los bordes dibujados aqui para que entendais más o menos como lo he estructurado. 9 celdas de 120x120. Ahora me he bajado el editor de mapas. En Debian ha sido muy facil, un buen "sudo apt-get install tiled" y todo solucionado. En debian u otros linux la instalación será similar usando tu gestor de paquetes favorito. En windows puedes ir a su web y bajarlo. OJO: Al instalarlo comprobar en Editar->Preferencias donde pone "Almacenar la capa de patrones como" poned Base64 (con compresion gzip), si no AndEngine da errores y no carga el archivo tmx.


Tras un rato de diversión obtengo el archivo .tmx que es el mapa con una estructura xml. Ahora vamos a añadirlo al proyecto. Creamos una carpeta nueva en assets que se llame tmx para meter aqui nuestros mapas, y creamos un archivo llamado field.tmx. El mio tiene una pinta así.

  1. <map version="1.0" orientation="orthogonal" width="4" height="8" tilewidth="120" tileheight="120">
  2. <tileset firstgid="1" name="background" tilewidth="120" tileheight="120">
  3. <image source="gfx/background_tile.png"/>
  4. </tileset>
  5. <layer name="Capa de Patrones 1" width="4" height="8">
  6. <data encoding="base64" compression="gzip">
  7. H4sIAAAAAAAAA2NlYGBghGI2IGYBYk4oZqYBnx2ImaCYA4gB8HAreoAAAAA=
  8. </data>
  9. </layer>
  10. </map>
Parsed in 0.006 seconds at 69.25 KB/s, using GeSHi 1.0.8.10

Atentos al image-source, apunta a gfx/background_tile.png, si editais el mapa desde tiled luego igual teneis que tocar a donde apuntan las imagenes.

Antes de empezar a meter código, yo tengo el Main.java así:

  1. package com.pruebas.andengine;
  2.  
  3. import org.anddev.andengine.engine.Engine;
  4. import org.anddev.andengine.engine.camera.ZoomCamera;
  5. import org.anddev.andengine.engine.options.EngineOptions;
  6. import org.anddev.andengine.engine.options.EngineOptions.ScreenOrientation;
  7. import org.anddev.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
  8. import org.anddev.andengine.entity.scene.Scene;
  9. import org.anddev.andengine.entity.scene.Scene.IOnSceneTouchListener;
  10. import org.anddev.andengine.entity.scene.background.ColorBackground;
  11. import org.anddev.andengine.entity.sprite.Sprite;
  12. import org.anddev.andengine.entity.util.FPSLogger;
  13. import org.anddev.andengine.input.touch.TouchEvent;
  14. import org.anddev.andengine.input.touch.detector.ScrollDetector;
  15. import org.anddev.andengine.input.touch.detector.SurfaceScrollDetector;
  16. import org.anddev.andengine.input.touch.detector.ScrollDetector.IScrollDetectorListener;
  17. import org.anddev.andengine.opengl.texture.Texture;
  18. import org.anddev.andengine.opengl.texture.TextureOptions;
  19. import org.anddev.andengine.opengl.texture.region.TextureRegion;
  20. import org.anddev.andengine.opengl.texture.region.TextureRegionFactory;
  21. import org.anddev.andengine.ui.activity.BaseGameActivity;
  22.  
  23. import android.util.Log;
  24.  
  25. public class Main extends BaseGameActivity implements IScrollDetectorListener,
  26. IOnSceneTouchListener {
  27. // ===========================================================
  28. // Constants
  29. // ===========================================================
  30. static final int CAMERA_WIDTH = 480;
  31. static final int CAMERA_HEIGHT = 320;
  32.  
  33. private static final String TAG = "AndEngineTest";
  34.  
  35. // ===========================================================
  36. // Fields
  37. // ===========================================================
  38.  
  39. private ZoomCamera mCamera;
  40. private Texture mTexture;
  41. private TextureRegion mFaceTextureRegion;
  42. private SurfaceScrollDetector mScrollDetector;
  43.  
  44. // ===========================================================
  45. // Constructors
  46. // ===========================================================
  47.  
  48. // ===========================================================
  49. // Getter & Setter
  50. // ===========================================================
  51.  
  52. // ===========================================================
  53. // Methods for/from SuperClass/Interfaces
  54. // ===========================================================
  55.  
  56. @Override
  57. public void onLoadComplete() {
  58. // TODO Auto-generated method stub
  59.  
  60. }
  61.  
  62. @Override
  63. public Engine onLoadEngine() {
  64. this.mCamera = new ZoomCamera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
  65. final int alturaTotal = CAMERA_HEIGHT * 3;
  66. this.mCamera.setBounds(0, CAMERA_WIDTH, 0, alturaTotal);
  67. this.mCamera.setBoundsEnabled(true);
  68. return new Engine(new EngineOptions(true, ScreenOrientation.LANDSCAPE,
  69. new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT),
  70. this.mCamera));
  71. }
  72.  
  73. @Override
  74. public void onLoadResources() {
  75. this.mTexture = new Texture(64, 64,
  76. TextureOptions.BILINEAR_PREMULTIPLYALPHA);
  77. this.mFaceTextureRegion = TextureRegionFactory.createFromAsset(
  78. this.mTexture, this, "gfx/ui_ball_1.png", 0, 0);
  79.  
  80. this.mEngine.getTextureManager().loadTexture(this.mTexture);
  81.  
  82. }
  83.  
  84. @Override
  85. public Scene onLoadScene() {
  86. this.mEngine.registerUpdateHandler(new FPSLogger());
  87.  
  88. final Scene scene = new Scene(1);
  89. scene.setBackground(new ColorBackground(0, 0, 0.8784f));
  90. scene.setOnAreaTouchTraversalFrontToBack();
  91.  
  92. this.mScrollDetector = new SurfaceScrollDetector(this);
  93. this.mScrollDetector.setEnabled(true);
  94.  
  95. final int centerX = (CAMERA_WIDTH - this.mFaceTextureRegion.getWidth()) / 2;
  96. final int centerY = (CAMERA_HEIGHT - this.mFaceTextureRegion
  97. .getHeight()) / 2;
  98.  
  99. final Sprite ball = new Sprite(centerX, centerY,
  100. this.mFaceTextureRegion);
  101. scene.getLastChild().attachChild(ball);
  102.  
  103. scene.setOnSceneTouchListener(this);
  104. scene.setTouchAreaBindingEnabled(true);
  105.  
  106. return scene;
  107. }
  108.  
  109. @Override
  110. public void onScroll(ScrollDetector pScollDetector, TouchEvent pTouchEvent,
  111. float pDistanceX, float pDistanceY) {
  112. this.mCamera.offsetCenter(-pDistanceX, -pDistanceY);
  113. }
  114.  
  115. @Override
  116. public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent) {
  117. this.mScrollDetector.onTouchEvent(pSceneTouchEvent);
  118. return true;
  119. }
  120.  
  121. // ===========================================================
  122. // Methods
  123. // ===========================================================
  124.  
  125. // ===========================================================
  126. // Inner and Anonymous Classes
  127. // ===========================================================
  128. }
  129.  
Parsed in 0.106 seconds at 43.53 KB/s, using GeSHi 1.0.8.10

Vamos a crear una variable para el TMXTiledMap.

private TMXTiledMap mTMXTiledMap;

En el procedimiento onLoadScene() cuando ponemos el color de fondo con el comando

scene.setBackground(new ColorBackground(0, 0, 0.8784f));

Cambiamos ese código por éste otro

  1. final TMXLoader tmxLoader = new TMXLoader(this, this.mEngine
  2. .getTextureManager(),
  3. TextureOptions.BILINEAR_PREMULTIPLYALPHA,
  4. new ITMXTilePropertiesListener() {
  5.  
  6. @Override
  7. public void onTMXTileWithPropertiesCreated(
  8. final TMXTiledMap pTMXTiledMap,
  9. final TMXLayer pTMXLayer,
  10. final TMXTile pTMXTile,
  11. final TMXProperties<tmxtileproperty> pTMXTileProperties) {
  12.  
  13. }
  14. });
  15. this.mTMXTiledMap = tmxLoader.loadFromAsset(this, "tmx/field.tmx");
  16. } catch (final TMXLoadException tmxle) {
  17. Debug.e(tmxle);
  18. }
  19.  
  20. final TMXLayer tmxLayer = this.mTMXTiledMap.getTMXLayers().get(0);
  21. scene.getFirstChild().attachChild(tmxLayer);
Parsed in 0.078 seconds at 9.36 KB/s, using GeSHi 1.0.8.10

Con esto ya podemos darle a F11 y ver como queda la cosa... bien, no??. Bueno tiene un pequeño problema, por lo menos en el terminal que yo estoy probando, cuando hago scroll me salen unas lineas negras en la junta de las texturas. Investigando un poco por los foros de AndEngine veo la manera de solucionarlo. Vamos a la parte donde creamos la textura de fondo... y cambiamos TextureOptions.BILINEAR_PREMULTIPLYALPHA por TextureOptions.NEAREST. Luego vamos a la parte donde creamos la cámara en onLoadEngine() y ponemos esto para la creación de la cámara para que ajuste a enteros la posición de la cámara y se vea ese feo efecto en la teléfono.


  1. this.mCamera = new ZoomCamera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT) {
  2.  
  3. @Override
  4. public void onApplyMatrix(GL10 pGL) {
  5. GLHelper.setProjectionIdentityMatrix(pGL);
  6.  
  7. GLU.gluOrtho2D(pGL, (int) this.getMinX(), (int) this.getMaxX(),
  8. (int) this.getMaxY(), (int) this.getMinY());
  9. }
  10. };
Parsed in 0.091 seconds at 3.29 KB/s, using GeSHi 1.0.8.10

Ale, asunto solucinoado, ya tenemos esto funcionando correctamente. Así se me queda el Main.java.


  1. package com.pruebas.andengine;
  2.  
  3. import org.anddev.andengine.engine.Engine;
  4. import org.anddev.andengine.engine.camera.ZoomCamera;
  5. import org.anddev.andengine.engine.options.EngineOptions;
  6. import org.anddev.andengine.engine.options.EngineOptions.ScreenOrientation;
  7. import org.anddev.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
  8. import org.anddev.andengine.entity.layer.tiled.tmx.TMXLayer;
  9. import org.anddev.andengine.entity.layer.tiled.tmx.TMXLoader;
  10. import org.anddev.andengine.entity.layer.tiled.tmx.TMXProperties;
  11. import org.anddev.andengine.entity.layer.tiled.tmx.TMXTile;
  12. import org.anddev.andengine.entity.layer.tiled.tmx.TMXTileProperty;
  13. import org.anddev.andengine.entity.layer.tiled.tmx.TMXTiledMap;
  14. import org.anddev.andengine.entity.layer.tiled.tmx.TMXLoader.ITMXTilePropertiesListener;
  15. import org.anddev.andengine.entity.layer.tiled.tmx.util.exception.TMXLoadException;
  16. import org.anddev.andengine.entity.scene.Scene;
  17. import org.anddev.andengine.entity.scene.Scene.IOnSceneTouchListener;
  18. import org.anddev.andengine.entity.sprite.Sprite;
  19. import org.anddev.andengine.entity.util.FPSLogger;
  20. import org.anddev.andengine.input.touch.TouchEvent;
  21. import org.anddev.andengine.input.touch.detector.ScrollDetector;
  22. import org.anddev.andengine.input.touch.detector.SurfaceScrollDetector;
  23. import org.anddev.andengine.input.touch.detector.ScrollDetector.IScrollDetectorListener;
  24. import org.anddev.andengine.opengl.texture.Texture;
  25. import org.anddev.andengine.opengl.texture.TextureOptions;
  26. import org.anddev.andengine.opengl.texture.region.TextureRegion;
  27. import org.anddev.andengine.opengl.texture.region.TextureRegionFactory;
  28. import org.anddev.andengine.ui.activity.BaseGameActivity;
  29. import org.anddev.andengine.util.Debug;
  30.  
  31. public class Main extends BaseGameActivity implements IScrollDetectorListener,
  32. IOnSceneTouchListener {
  33. // ===========================================================
  34. // Constants
  35. // ===========================================================
  36. static final int CAMERA_WIDTH = 480;
  37. static final int CAMERA_HEIGHT = 320;
  38.  
  39. private static final String TAG = "AndEngineTest";
  40.  
  41. // ===========================================================
  42. // Fields
  43. // ===========================================================
  44.  
  45. private ZoomCamera mCamera;
  46. private Texture mTexture;
  47. private TextureRegion mFaceTextureRegion;
  48. private SurfaceScrollDetector mScrollDetector;
  49. private TMXTiledMap mTMXTiledMap;
  50.  
  51. // ===========================================================
  52. // Constructors
  53. // ===========================================================
  54.  
  55. // ===========================================================
  56. // Getter & Setter
  57. // ===========================================================
  58.  
  59. // ===========================================================
  60. // Methods for/from SuperClass/Interfaces
  61. // ===========================================================
  62.  
  63. @Override
  64. public void onLoadComplete() {
  65. // TODO Auto-generated method stub
  66.  
  67. }
  68.  
  69. @Override
  70. public Engine onLoadEngine() {
  71. this.mCamera = new ZoomCamera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
  72. final int alturaTotal = CAMERA_HEIGHT * 3;
  73. this.mCamera.setBounds(0, CAMERA_WIDTH, 0, alturaTotal);
  74. this.mCamera.setBoundsEnabled(true);
  75. return new Engine(new EngineOptions(true, ScreenOrientation.LANDSCAPE,
  76. new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT),
  77. this.mCamera));
  78. }
  79.  
  80. @Override
  81. public void onLoadResources() {
  82. this.mTexture = new Texture(64, 64,
  83. TextureOptions.BILINEAR_PREMULTIPLYALPHA);
  84. this.mFaceTextureRegion = TextureRegionFactory.createFromAsset(
  85. this.mTexture, this, "gfx/ui_ball_1.png", 0, 0);
  86.  
  87. this.mEngine.getTextureManager().loadTexture(this.mTexture);
  88.  
  89. }
  90.  
  91. @Override
  92. public Scene onLoadScene() {
  93. this.mEngine.registerUpdateHandler(new FPSLogger());
  94.  
  95. final Scene scene = new Scene(1);
  96.  
  97. try {
  98. final TMXLoader tmxLoader = new TMXLoader(this, this.mEngine
  99. .getTextureManager(), // TextureOptions.BILINEAR_PREMULTIPLYALPHA,
  100. TextureOptions.NEAREST, new ITMXTilePropertiesListener() {
  101.  
  102. @Override
  103. public void onTMXTileWithPropertiesCreated(
  104. final TMXTiledMap pTMXTiledMap,
  105. final TMXLayer pTMXLayer,
  106. final TMXTile pTMXTile,
  107. final TMXProperties<tmxtileproperty> pTMXTileProperties) {
  108.  
  109. }
  110.  
  111. });
  112. this.mTMXTiledMap = tmxLoader.loadFromAsset(this, "tmx/field.tmx");
  113. } catch (final TMXLoadException tmxle) {
  114. Debug.e(tmxle);
  115. }
  116.  
  117. final TMXLayer tmxLayer = this.mTMXTiledMap.getTMXLayers().get(0);
  118. scene.getFirstChild().attachChild(tmxLayer);
  119.  
  120. scene.setOnAreaTouchTraversalFrontToBack();
  121.  
  122. this.mScrollDetector = new SurfaceScrollDetector(this);
  123. this.mScrollDetector.setEnabled(true);
  124.  
  125. final int centerX = (CAMERA_WIDTH - this.mFaceTextureRegion.getWidth()) / 2;
  126. final int centerY = (CAMERA_HEIGHT - this.mFaceTextureRegion
  127. .getHeight()) / 2;
  128.  
  129. final Sprite ball = new Sprite(centerX, centerY,
  130. this.mFaceTextureRegion);
  131. scene.getLastChild().attachChild(ball);
  132.  
  133. scene.setOnSceneTouchListener(this);
  134. scene.setTouchAreaBindingEnabled(true);
  135.  
  136. return scene;
  137. }
  138.  
  139. @Override
  140. public void onScroll(ScrollDetector pScollDetector, TouchEvent pTouchEvent,
  141. float pDistanceX, float pDistanceY) {
  142. this.mCamera.offsetCenter(-pDistanceX, -pDistanceY);
  143. }
  144.  
  145. @Override
  146. public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent) {
  147. this.mScrollDetector.onTouchEvent(pSceneTouchEvent);
  148. return true;
  149. }
  150.  
  151. // ===========================================================
  152. // Methods
  153. // ===========================================================
  154.  
  155. // ===========================================================
  156. // Inner and Anonymous Classes
  157. // ===========================================================
  158. }
  159.  
Parsed in 0.120 seconds at 48.29 KB/s, using GeSHi 1.0.8.10

Bueno, por hoy está bien. Para el siguiente capítulo vamos a Implementar nuestro propio Detector, como el IScrollDetector pero para juegos estilo catapulta. Ya lo tengo hecho, pero una cosa es hacerlo y otra ponerlo aquí y explicarlo. Mañana más.

35 comentarios:

Gol D. Roger dijo...

Gracias! Muy currado el tutorial.
Entre otras cosas me ha llamado la atención aprender a utilizar el SuperClass Selection (no lo conocía xDD) y el software "tiled" se ve interesante otra cosa más para estudiar ^^,'

He encontrado algunos posibles errores en el código en los que en algunos tengo la solución y otros no.
La primera parte del tutorial funciona con algunos retoques y la segunda por ahora no..

Te lo comento por mail para no llenar esto.

saludos, sigue así!

Angel dijo...

Gracias por la correción. El problema está en el formateador de xml y de java, que se ha vuelto loco.

Voy a buscar otro para usar.

Un saludo.

Unknown dijo...

Impresionante!!

Llevo algún que otro día buscando y recolectando toda la doc. posible sobre este motor.

Y como sabes la mayoría de info está en inglés. tardo 5 veces más en entender ciertos conceptos jeje (llevo en esto muy poco).
Por supuesto los foros de Andengine son geniales pero tus tutoriales no tienen precio.
Sobretodo por la forma agradable y sencilla de explicarlos. Muchísimas gracias por contribuir a hacer que el estudio de Android y de este motor, sea mucho más llevadero.

Por mi parte el objetivo es hacer un LiveWallpaper aprovechando las bondades de Andengine y con el tiempo algo más complejo como un juego.
Muchísimas gracias de nuevo y, si me permites, te hago una preguntilla sobre los 2 primeros tutoriales de Andengine. (el 3º todavía no lo he estudiado)

- El el 1º tuto das un link directo al andengine.jar que pesa unos 1.5 MB. El mio que lo bajé del link que da Nicolas pesa 843KB.
Supongo que uno lleva el Manifest.xml, exportJarToAll.xml, etc. Y el otro está sin "añadidos" (que , por cierto, me funcionó de perlas en el emulador con tus 2 primeros tutoriales).
Podrías decirme que tipo de andengine.jar es el más aconsejable para un proyecto con este motor ó un link donde automáticamente esté el archivo actualizado?

Saludos y disculpa por la magnitud del post

Angel dijo...

Gracias por el comentario Ricard.

Pues la verdad no se exactamente que diferencia hay entre los dos jar... yo ahora que lo he mirado también estoy usando uno que ocupa 863.174 bytes. Cambiaré en enlace en el primer tutorial. Yo tampoco soy un experto en esto, con Java/Android llevo 3 meses jugueteando y con AndEngine llevo desde el primer tutorial, una semana creo.

Siento no saber solucionar tu duda... Si algo no te sale del tutorial porque hay una errata dímelo y lo soluciono, que me interesa que ésto se quede lo más fino posible. También si ves algo que hay una manera mejor de hacerlo, dimelo por favor, que en Java soy totalmente novato y probablemente habrá mejores maneras de hacerlas.

Un saludo :)

Unknown dijo...

Hola Angel,

Gracias por la rapidez!!
Respecto a lo que comentas, en cuanto a los errores o pulir código, no dudes en que lo haré con tal de poder aportar algo "a la causa", aunque de momento, reconozco que me llevas 3 pueblos de adelanto ;) y no te podré ayudar más que en la identificación de algunos errores.

Por lo demás decirte que las 2 primeras partes del tutorial son impecables y todo funciona genial. El único error (aunque creo que es mio) viene en el debug, donde la ClassLoader.class no puede "attachar" el android.jar y aunque la ruta C:/Program Files/Android/sdk/platforms/android-4/android.jar es correcta...no inicia la aplicación en modo debug.
Pero como he dicho creo que esto es cosa mía por lo que destinaré unas horas para solucionar el tema.

ReSaludos ;)

Unknown dijo...

Disculpa,

Lo tenía delante de las narices... Me he estado leyendo el tutorial de "Depurar proyectos en Android (Source not found)" y solucionado!!

Como siempre muchas gracias y buenas noches!!

Unknown dijo...

Hola Angel,

Al igual que Ephram, también me da error ciertas partes de código y aunque no se la solución que él ha aportado, en mi caso lo he resuelto sustituyendo la parte que hace referencia a:

new ITMXTilePropertiesListener() {
@Override
public void onTMXTileWithPropertiesCreated(
final TMXTiledMap pTMXTiledMap,
final TMXLayer pTMXLayer,
final TMXTile pTMXTile,
final TMXProperties pTMXTileProperties) {
}
}

Por:
@Override
public void onTMXTileWithPropertiesCreated(TMXTiledMap pTMXTiledMap, TMXLayer pTMXLayer, TMXTile pTMXTile, TMXProperties pTMXTileProperties) {
}
});
Y aunque no dudo en que deben existir otras soluciones mejores, a mi me funciona correctamente. Por supuesto estaré encantado de leer tus sugerencias al respecto.

Muchas gracias!!!
Saludos

Angel dijo...

La solución buena es esta:

new ITMXTilePropertiesListener();

Sin tanto follón, por desconocimiento mio de java y por basarme en codigo de los ejemplos la habia liado un poco.

Unknown dijo...

muchas gracias por publicar estos tutoriales... soy novato y estoy teniendo algunos problemas para correr la aplicacion en esta tercera parte.. el splashscreen me corre normal. pero al volver al main. me da un error y no encuentro cual es el problema.. copie y pegue el codigo tuyo directamente y aun asi, nada...
si pudieses ayudarme, te lo agradeceria.
por si lo olvidaba.. super estos tutoriales... keep up the good work !!!

Unknown dijo...

uppss... googleando sobre el problema me he tropezado con que tengo que importar el .so file pero no tengo idea de como hacer eso. ya que al descargar el andengine solo tengo andengine.jar y andenginephysicsbox2dextension.jar
se supone que tambien tenga que descargar los .so o es un procedimiento para incorporarlos a la libreria??

sorry si parece un poco tonto la verdad es que buscando sobre el tema, hay bastante problema pero no mucha informacion sobre como hacerlo..
gracias por adelantado

Unknown dijo...

Hola Angel,

Me imagino que, como muchos de nosotros, no vas sobrado de tiempo, por lo tanto ¡¡muchas gracias de nuevo por responder!!

En referencia a tu solución, a mi no me funciona. Increíblemente ya no me da error el codigo original. Bueno solo me da un aviso de:

/////---- TMXProperties is a raw type. References to generic type TMXProperties should be parameterized -----//// pero me permite lanzar la aplicación ene el emulador.

En cambio, la solución que aportas me da el error de:

/// --- Cannot instantiate the type TMXLoader.ITMXTilePropertiesListener ---///

Empiezo a creer que me faltan años luz de experiencia en java ya que hay cambios que no sé a que son debidos y errores que no llego a comprender.
De todas formas seguiré con este tutorial ya que con los cambios que hice de tu código original no me da aparentemente ningún problema.

Muchas gracias y ánimo con el proyecto!
Saludos

Unknown dijo...

Hola! yo he solucionado el codigo con :

:: Añadiendo a los imports:

import org.anddev.andengine.entity.layer.tiled.tmx.TMXLayer;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXLoader;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXLoader.ITMXTilePropertiesListener;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXProperties;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXTile;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXTileProperty;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXTiledMap;
import org.anddev.andengine.entity.layer.tiled.tmx.util.exception.TMXLoadException;

:: A nivell de codigo ::

final TMXLoader tmxLoader = new TMXLoader(this, this.mEngine.getTextureManager(), TextureOptions.BILINEAR_PREMULTIPLYALPHA, new ITMXTilePropertiesListener() {

public void onTMXTileWithPropertiesCreated(final TMXTiledMap pTMXTiledMap, final TMXLayer pTMXLayer, final TMXTile pTMXTile, final TMXProperties pTMXTileProperties) {

}
});

Unknown dijo...
Este comentario ha sido eliminado por el autor.
jordi dijo...
Este comentario ha sido eliminado por el autor.
Gustavo dijo...

Hola que tal? puse lo que dice Jordi, pero cuando pasa el splash me salta un error y se cierra la aplicacion. Puede q a alguien le haya pasado algo similar o tienen idea de que puede ser?? muchas gracias

Starry_Night dijo...

Gustavo, abre el tmx con un editor de texto y mira donde pone la url de la imagen. Asegurate que es gfx/nombreDeTuImagen.tmx

Saludos

Alonso dijo...

Hola, con la última librería que me he descargado de AndEngine (el enlace de la que has usado en la primera parte no funciona) me da un FC cuando termina de mostrar el Splash, y el caso es que la otra actividad mostrada sin splash si que funciona, al parecer falla al pasar de una actividad a otra, ¿a alguien más le ha pasado y sabe como solucionarlo?

Gracias.

Angel dijo...

Nicolas ha hecho un cambio en los fuentes de andengine y ahora las texturas han cambiado todas de nombre y los fuentes que hay en el proyecto no funcionan. Hay que hacer unos cambios de nombre....

Ahora mismo ando un poco liado con otros proyectos y no tengo tiempo de cambiar todos los fuentes de los tutoriales. Espero que cuando pase el verano me de tiempo a ponerlos al pistón otra vez y continuar las series.

Un saludo.

Angel dijo...

Estos son los cambios de variables. Cuando tenga un rato libre actualizo los tutoriales con ese cambio de fuentes.

TextureRegionFactory - > BitmapTextureAtlasTextureRegionFactory
ExternalStorageFileTextureSource -> ExternalStorageFileBitmapTextureAtlasSource
Texture -> BitmapTextureAtlas
BuildableTexture -> BuildableBitmapTextureAtlas

jchunly dijo...

hola chicos tengo un problema en esta parte

protected IBitmapTextureAtlasSource onGetSplashTextureAtlasSource() {
return new AssetTextureSource(this, "gfx/splash.png");
}

esto es lo tengo yo y no puedo ponerlo como en el tuto en la primera parte que me puede pasar.

un saludo y gracias.

John dijo...

Es porque tu verison de AndEngine es mas reciente y algunas variables y metodos cambiaron de nombre.

cambia:

AssetTextureSource por AssetBitmapTextureAtlasSource

y agrega el import

import org.anddev.andengine.opengl.texture.atlas.bitmap.source.AssetBitmapTextureAtlasSource;

Espero te funciones

Saludos

jcMedinaMtz dijo...

Hola amigo, gracias por tus tutoriales, son muy buenos y he aprendido mucho con ellos. Solo que tengo una duda:
Verás, agregue dos clases Splash (splash y splash2). Splash redirecciona a splash2, y splash2 me manda al main, lo hice asi para que me salgan dos imágenes antes del menú principal.
Bien, me di cuenta que cuando hace la transición entre splash y splash2, se vuelve la pantalla negra por un instante y de a misma forma pasa antes de irme al main.
Hay alguna manera de manejar algún tipo de transición personalizada para evitar que se vea ese parpadeo? o para no usar dos pantallas de splash, se puede montar en una misma las intersecciones?

Roger dijo...

Hola, estoy siguiendo hasta ahora, pero aun no me sale el splash, podrias pegar tu AndroidManifiest.xml hasta ese punto?, tampoco entiendo que se hace con el editor de niveles. pego el field.tmx pero me sale error

Ozuno dijo...

Hola
A mi me funciona el Splash pero cuando llama a la actividad principal se cae.
YO igual les dejo intent-filter en el Maniefiesto y pasa esto.
Pero si se los saco me dice que no encuentra la actividad.
Saludos

Ozuno dijo...

Ya lo solucione... pensé un poco: Como esto funciona por actividades, agregué otra actividad llamando a la clase principal y listo.
Muestra el Splash y después el juego.

Me respondí solo ;-)
Saludos

Roger dijo...
Este comentario ha sido eliminado por el autor.
jonny88 dijo...

tengo problemas en el splash si lo pongo, luego me sale un forzar cierre y nose como solucionarlo...
haber si podria ayudarme alguien gracias

Roger dijo...
Este comentario ha sido eliminado por el autor.
Roger dijo...
Este comentario ha sido eliminado por el autor.
Roger dijo...
Este comentario ha sido eliminado por el autor.
Unknown dijo...

Y como iba yo a saber que la versión tiene mucho que ver?. Amigos, también tuve que ver el problema del SplashScreen que luego de ejecutar, mostraba la imagen de inicio pero al querer saltar a la aplicación principal, ahi me lanzaba una excepción no controlada. Yo estuve compilando para la versión 1.2 del android. Luego cambié a la versión más reciente 7, y ahora si ya me funciona. Claro tienen que actualizar eso de ITexture, ya no existe con el ultimo jar de AndEngine. Aqui el AndroidManifest.xml para el que le haga falta

Unknown dijo...

Por cierto... tienen que declarar al Activity que van a llamar desde el splash screen, todo esto en el AndroidManifiest.xml
....
android:versionCode="1"
android:versionName="1.0" >













...

Unknown dijo...

ooops!, no puedo escribirles el código:

package="XXX.XXX"
android:versionCode="1"
android:versionName="1.0"

'uses-sdk android:minSdkVersion="7" /'

'application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" android:debuggable="true"'
'activity
android:name=".MainVista"
android:label="@string/app_name" '
'/activity'
'activity android:name=".SplashScreen" android:label="@string/app_name" android:icon="@drawable/ic_launcher"'
'intent-filter'
'action android:name="android.intent.action.MAIN"/'
'category android:name="android.intent.category.LAUNCHER"/'
'/intent-filter'
'/activity'
'/application'

'/manifest'

NOTA: Si no entiendes este código mejor presiona alt+f4 jejeje. Ayuda: reemplaza los ' por < o por > para cada etiqueta, aqui no se puede escribir código XML :(
Suerte.

elbrujojorge dijo...

Tengo el mismo problema de attach que Ozuno pero no me funcionó el crear otra actividad como él... alguna idea amigos?

elbrujojorge dijo...

Tenía mal declarado el nombre de una Activity en el Manifest... fallo tonto y dificil de ver xD

Publicar un comentario