viernes, 25 de marzo de 2011

Introducción a AndEngine (Parte IV)

Anteriormente en Droideando



Objetivos de hoy

  • Crear el sprite del jugador
  • Crear un Detector de AndEngine para el efecto de catapulta en el jugador



Creamos el jugador


Para crear el jugador he decidido usar un AnimatedSprite, pero como seguro que le tengo que meter alguna cosa, heredo la clase y la uso.


Para crear la clase, vamos a la carpeta de nuestros fuentes en Eclipse. File New -> Class y le ponemos Name Player y SuperClass AnimatedSprite. Le añadimos un TAG para el debug y por ahora listo.Se nos queda algo así.


  1. package com.pruebas.andengine;
  2.  
  3. import org.anddev.andengine.entity.sprite.AnimatedSprite;
  4. import org.anddev.andengine.input.touch.detector.HoldDetector;
  5. import org.anddev.andengine.input.touch.detector.HoldDetector.IHoldDetectorListener;
  6. import org.anddev.andengine.opengl.texture.region.TiledTextureRegion;
  7.  
  8. import android.util.Log;
  9.  
  10. public class Player extends AnimatedSprite  {
  11.  
  12. private static final String TAG = "Player"; 
  13.  
  14. public Player(float pX, float pY, TiledTextureRegion pTiledTextureRegion) {
  15. super(pX, pY, pTiledTextureRegion);  
  16. }
  17.  
  18.  
  19. }
  20.  
Parsed in 0.077 seconds at 7.25 KB/s, using GeSHi 1.0.8.10

Ahora volvemos al Main.java y añadimos una variable para guardar el jugador activo y cambamos la variable mFaceTextureRegion por mBallTextureRegion para que el nombre coincida con lo que lleva dentro, y le cambiamos también el tipo a TiledTextureRegion. Se queda así.


  1. // ===========================================================
  2. // Fields
  3. // ===========================================================
  4.  
  5. private ZoomCamera mCamera;
  6. private Texture mTexture;
  7. private TiledTextureRegion mBallTextureRegion;
  8. private TiledTextureRegion mPlayerTextureRegion;
  9. private SurfaceScrollDetector mScrollDetector;
  10. private TMXTiledMap mTMXTiledMap;
  11. private Player mActivePlayer;
Parsed in 0.106 seconds at 3.86 KB/s, using GeSHi 1.0.8.10

Aqui pongo el sprite del jugador para que lo bajeis a vuestro proyecto, en la carpeta assets/gfx como de costumbre



Pongo también el sprite de la pelota (provisional, necesito un balón de verdad para echarle fotos), al mismo sitio assets/gfx.



Ahora vamos a cambiar la carga de texturas para cargar estas dos nuevas textuas. La carga de texturas se hace en el objeto mTexture. El objeto mTexture debe ser por exigencias de AndEngine tanto en altura como longitud potencias de 2 en píxeles. Para las texturas que tenemos ahora mismo, lo mínimo sin despercidicar ni un pixel en memoria es 256X256 píxeles. La textura en memoria se quedaría algo como ésto:




Ahora vamos a cambiar en onLoadResources para cargar todo esto que hemos metido nuevo. Primero el tamaño de la textura pasa a ser 256X256 para poder albergar las texturas que hemos metido nuevas. A la hora de crear la textura de la pelota, usamos la funcion createTiledFromAsset(), que usa los siguientes parámetros:

  • this.mTexture: El primero parámetro es el objeto textura donde lo vamos a guardar. En el objeto mTexture de la clase.
  • this: La clase actual. Pocos comentarios al respecto.
  • "gfx/ui_ball.png": La ruta a la imagen.
  • 0,0: los dos siguientes parámetros es donde vamos a colocar éste objeto dentro de mTexture, en este caso vamos a colocar la pelota en la parte de la izquierda y el jugador en la derecha, o sea, para la pelota le ponemos 0,0 y para el jugador 128,0.
  • 2,4: Número de Filas y Columnas, en el caso tanto de la pelota como del jugador son 2,4.
Se queda una cosa así:


  1. @Override
  2. public void onLoadResources() {
  3. this.mTexture = new Texture(256, 256,
  4. TextureOptions.BILINEAR_PREMULTIPLYALPHA);
  5. this.mBallTextureRegion = TextureRegionFactory.createTiledFromAsset(
  6. this.mTexture, this, "gfx/ui_ball.png", 0, 0, 2, 4);
  7. this.mPlayerTextureRegion = TextureRegionFactory.createTiledFromAsset(
  8. this.mTexture, this, "gfx/ui_player.png", 128, 0, 2, 4);
  9.  
  10. this.mEngine.getTextureManager().loadTexture(this.mTexture);
  11.  
  12. }
Parsed in 0.074 seconds at 6.24 KB/s, using GeSHi 1.0.8.10

Ahora vamos a tocar el método onLoadScene(). Primero eliminamos el código que creaba la bola y desactivamos el Detector de Scroll. El final del procedimiento se me queda así.


  1. scene.setOnAreaTouchTraversalFrontToBack();
  2.  
  3. this.mScrollDetector = new SurfaceScrollDetector(this);
  4. this.mScrollDetector.setEnabled(false); //Hemos puesto esto a false
  5.  
  6. /*
  7.   final int centerX = (CAMERA_WIDTH - this.mFaceTextureRegion.getWidth()) / 2;
  8.   final int centerY = (CAMERA_HEIGHT - this.mFaceTextureRegion
  9.     .getHeight()) / 2;
  10.  
  11.   final Sprite ball = new Sprite(centerX, centerY,
  12.     this.mFaceTextureRegion);
  13.   scene.getLastChild().attachChild(ball);
  14.      */
  15. scene.setOnSceneTouchListener(this);
  16. scene.setTouchAreaBindingEnabled(true);
  17.  
  18. return scene;
  19. }
Parsed in 0.077 seconds at 7.57 KB/s, using GeSHi 1.0.8.10

Ahora metemos el jugador en pantalla y ya podemos probar como se ve y eso. Para ello creamos un método createPlayer().


  1. // ===========================================================
  2. // Methods
  3. // ===========================================================
  4.  
  5. private void createPlayer() {
  6. final Scene scene = this.mEngine.getScene();
  7.  
  8. final Player sprite = new Player(200, 100, this.mPlayerTextureRegion);
  9. // scene.registerTouchArea(sprite);
  10.  
  11. scene.getLastChild().attachChild(sprite);
  12. this.mActivePlayer = sprite;
  13. }
Parsed in 0.069 seconds at 5.99 KB/s, using GeSHi 1.0.8.10

Aqui lo que hacemos es para probar ponemos un jugador en la posicion 200,100. Ahora llamamos a este método desde onLoadComplete().


  1. @Override
  2. public void onLoadComplete() { // scene.set 
  3. createPlayer();
  4. }
Parsed in 0.072 seconds at 1.08 KB/s, using GeSHi 1.0.8.10

En este punto ya podemos ejecutar el programa para ver como va la cosa. Se ve el cesped y el jugador, pero no responde al Scroll porque lo hemos desactivado. Por ahora todo va bien. Vamos a crear el Detector.


Creando un Detector


Mirando un poco los fuentes del ScrollDetector, que funciona de fábula y siendo el juego tipo catapultas bastante popular, porqué no hacer un Detector de catapultas?? Manos a la obra.


Creamos una nueva clase en nuestro proyecto. Nombre: CatapultDetector y SuperClass BaseDetector (org.anddev.andengine.input.touch.detector.BaseDetector)


  1. package com.pruebas.andengine;
  2.  
  3. import org.anddev.andengine.input.touch.TouchEvent;
  4. import org.anddev.andengine.input.touch.detector.BaseDetector;
  5.  
  6. public class CatapultDetector extends BaseDetector {
  7.  
  8. @Override
  9. protected boolean onManagedTouchEvent(TouchEvent pSceneTouchEvent) {
  10. // TODO Auto-generated method stub
  11. return false;
  12. }
  13.  
  14. }
  15.  
Parsed in 0.091 seconds at 3.82 KB/s, using GeSHi 1.0.8.10

Un detector es un objeto para usarlo como hicimos con el ScrollDetector en el anterior tutorial. Necesitamos una interface listener. Vamos a ello.


  1. public static interface ICatapultDetectorListener {
  2. // ===========================================================
  3. // Constants
  4. // ===========================================================
  5.  
  6. // ===========================================================
  7. // Methods
  8. // ===========================================================
  9.  
  10. public void onCharge(final CatapultDetector pCatapultDetector,
  11. final TouchEvent pTouchEvent, final float pDistance,
  12. final float pAngle);
  13.  
  14. public void onShoot(final CatapultDetector pCatapultDetector,
  15. final TouchEvent pTouchEvent, final float pDistance,
  16. final float pAngle);
  17. }
  18.  
Parsed in 0.102 seconds at 6.30 KB/s, using GeSHi 1.0.8.10


Este es un listener básico para probar el funcionamiento. Al objeto que esté escuchando le pasamos un ángulo y una distancia. Esta clase la definimos dentro de la CatapultDetector al final como en los demás Detectors que he visto en los fuentes de AndEngine.


Vamos a meterle algunas variables al Detector que algunas las vamos a usar ya mismo y otras las usaremos después. No preocuparse por los warnings, ya nos encargaremos de eso más tarde


  1. // ===========================================================
  2. // Constants
  3. // ===========================================================
  4. private static final float TRIGGER_SCROLL_MINIMUM_DISTANCE_DEFAULT = 10;
  5. private static final float ANGLE_CONSTANT = 10;
  6. private static final int DEFAULT_STEPS = 6;
  7. private float DEFAULT_MAX_DISTANCE = 100;
  8. // ===========================================================
  9. // Fields
  10. // ===========================================================
  11.  
  12. //Minimum distance to execute 
  13. private float mTriggerScrollMinimumDistance;
  14.  
  15. //Listener for the Detector
  16. private final ICatapultDetectorListener mCatapultDetectorListener;
  17.  
  18. private boolean mTriggered;
  19.  
  20. //First Touch
  21. private float mFirstX;
  22. private float mFirstY;
  23.  
  24. //Last Touch
  25. private float mLastX;
  26. private float mLastY;
  27.  
  28. private int mSteps;
  29. private float mMaxDistance;
Parsed in 0.088 seconds at 10.05 KB/s, using GeSHi 1.0.8.10

Creamos unos métodos que usaremos después y los Getter y Setter para mTriggerScrollMinimumDistance.


  1. // ===========================================================
  2. // Getter & Setter
  3. // ===========================================================
  4.  
  5. public void setTriggerScrollMinimumDistance(
  6. float mTriggerScrollMinimumDistance) {
  7. this.mTriggerScrollMinimumDistance = mTriggerScrollMinimumDistance;
  8. }
  9.  
  10. public float getTriggerScrollMinimumDistance() {
  11. return mTriggerScrollMinimumDistance;
  12. }
  13.  
  14. // ===========================================================
  15. // Methods
  16. // ===========================================================
  17.  
  18. protected float getX(final TouchEvent pTouchEvent) {
  19. return pTouchEvent.getX();
  20. }
  21.  
  22. protected float getY(final TouchEvent pTouchEvent) {
  23. return pTouchEvent.getY();
  24. }
Parsed in 0.098 seconds at 7.41 KB/s, using GeSHi 1.0.8.10

Tocamos un poco los constructores de la clase


  1. // ===========================================================
  2. // Constructors
  3. // ===========================================================
  4.  
  5. public CatapultDetector(
  6. final ICatapultDetectorListener pCatapultDetectorListener) {
  7. this(TRIGGER_SCROLL_MINIMUM_DISTANCE_DEFAULT, pCatapultDetectorListener);
  8. }
  9.  
  10. public CatapultDetector(final float pTriggerScrollMinimumDistance,
  11. final ICatapultDetectorListener pCatapultDetectorListener) {
  12. this.setTriggerScrollMinimumDistance(pTriggerScrollMinimumDistance);
  13. this.mCatapultDetectorListener = pCatapultDetectorListener;
  14. }
Parsed in 0.077 seconds at 7.53 KB/s, using GeSHi 1.0.8.10

Y ahora tocamos el método donde se va a llevar todo a cabo, para nuestra primera prueba nos vale algo sencillo como ésto


  1. // ===========================================================
  2. // Methods for/from SuperClass/Interfaces
  3. // ===========================================================
  4.  
  5. @Override
  6. protected boolean onManagedTouchEvent(TouchEvent pSceneTouchEvent) {
  7. final float touchX = this.getX(pSceneTouchEvent);
  8. final float touchY = this.getY(pSceneTouchEvent);
  9.  
  10. switch (pSceneTouchEvent.getAction()) {
  11. case MotionEvent.ACTION_DOWN:
  12. this.mFirstX = touchX;
  13. this.mFirstY = touchY;
  14. this.mLastX = touchX;
  15. this.mLastY = touchY;
  16. this.mTriggered = false;
  17. return true;
  18. case MotionEvent.ACTION_MOVE:
  19. case MotionEvent.ACTION_UP:
  20. case MotionEvent.ACTION_CANCEL:
  21. final float distanceX = touchX - this.mLastX;
  22. final float distanceY = touchY - this.mLastY;
  23. if (pSceneTouchEvent.getAction() == MotionEvent.ACTION_MOVE) {
  24. final float triggerScrollMinimumDistance = this.mTriggerScrollMinimumDistance;
  25. if (this.mTriggered
  26. || Math.abs(distanceX) > triggerScrollMinimumDistance
  27. || Math.abs(distanceY) > triggerScrollMinimumDistance) {
  28. final float distance = (float)Math.hypot((double)distanceX,(double)distanceY);     
  29. final double angleX = touchX - this.mFirstX;
  30. final double angleY = touchY - this.mFirstY;
  31. final float angle = (float)Math.toDegrees(Math.atan2(angleY, angleX))+ANGLE_CONSTANT;
  32. this.mCatapultDetectorListener.onCharge(this, pSceneTouchEvent, distance, angle);
  33. this.mLastX = touchX;
  34. this.mLastY = touchY;
  35. this.mTriggered = true;
  36. }
  37. else
  38. {
  39.  
  40.  
  41. }
  42. }
  43. return true;
  44. default:
  45. return false;
  46. }
  47. }
  48.  
Parsed in 0.097 seconds at 16.70 KB/s, using GeSHi 1.0.8.10

Ya entraré mas a detalle en otro artículo de como funciona el Detector, pero mirando los fuentes puedes hacerte una idea bastante clara. Con esto ya tenemos el Detector en el punto para probarlo. Volvamos al Main.java. Creamos una variable privada para albergar el detector.


  1. // ===========================================================
  2. // Fields
  3. // ===========================================================
  4.  
  5. private ZoomCamera mCamera;
  6. private Texture mTexture;
  7. private TiledTextureRegion mBallTextureRegion;
  8. private TiledTextureRegion mPlayerTextureRegion;
  9. private SurfaceScrollDetector mScrollDetector; 
  10. private TMXTiledMap mTMXTiledMap;
  11. private Player mActivePlayer;
  12. private CatapultDetector mCatapultDetector; //Nueva variable Creada
Parsed in 0.078 seconds at 6.09 KB/s, using GeSHi 1.0.8.10

Ahora necesitamos le decimos a nuestra Clase Main, que implemente la interface ICatapultDetectorListener.


  1. public class Main extends BaseGameActivity implements IScrollDetectorListener,
  2. IOnSceneTouchListener, ICatapultDetectorListener
Parsed in 0.082 seconds at 1.54 KB/s, using GeSHi 1.0.8.10

Ahora implementamos los métodos de ICatapultDetectorListener.


  1. @Override
  2. public void onCharge(CatapultDetector pCatapultDetector,
  3. TouchEvent pTouchEvent, float pDistance, float pAngle) {
  4. Log.d(TAG, "Cargando... {Distancia:" + pDistance + ", angulo: "
  5. + pAngle + "}");
  6. this.mActivePlayer.setRotation(pAngle);
  7.  
  8. }
  9.  
  10. @Override
  11. public void onShoot(CatapultDetector pCatapultDetector,
  12. TouchEvent pTouchEvent, float pDistance, float pAngle) {
  13. Log.d(TAG, "Disparo... {Distancia:" + pDistance + ", angulo: " + pAngle
  14. + "}");
  15. }
Parsed in 0.084 seconds at 5.75 KB/s, using GeSHi 1.0.8.10

En el método onCharge() rotamos el jugador el ángulo que correspode, en el onShoot() un debug solamente, aunque realmente en el estado del detector no se va a disparar este evento aún. Lo siguiente es crear en el onLoadScene() el Scroll y asignarlo.


  1. this.mScrollDetector = new SurfaceScrollDetector(this);
  2. this.mScrollDetector.setEnabled(false); 
  3.  
  4. //Creamos el detector de catapulta
  5. this.mCatapultDetector = new CatapultDetector(this);
  6. this.mCatapultDetector.setEnabled(true);
Parsed in 0.093 seconds at 2.55 KB/s, using GeSHi 1.0.8.10

Y en el onSceneTouchEvent le pasamos el evento al CatapultDetector.



  1. @Override
  2. public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent) {
  3. if (this.mActivePlayer != null) {
  4. this.mCatapultDetector.onTouchEvent(pSceneTouchEvent);
  5. }
  6. return true;
  7. }
Parsed in 0.079 seconds at 2.59 KB/s, using GeSHi 1.0.8.10


Ya tenemos el proyecto en otro momento para poder ejecutar y ver que está pasando por debajo de todo ésto. F11 y arranca splash... aparece el campo con el jugador, hacemos click en cualquier sitio, y al mover el dedo por la pantalla vemos como el jugador gira, aunque no lo hace en el ángulo correcto, pero es un principio. Ahora mismo mis archivos están asi:



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.AnimatedSprite;
  19. import org.anddev.andengine.entity.sprite.Sprite;
  20. import org.anddev.andengine.entity.util.FPSLogger;
  21. import org.anddev.andengine.input.touch.TouchEvent;
  22. import org.anddev.andengine.input.touch.detector.ScrollDetector;
  23. import org.anddev.andengine.input.touch.detector.SurfaceScrollDetector;
  24. import org.anddev.andengine.input.touch.detector.ScrollDetector.IScrollDetectorListener;
  25. import org.anddev.andengine.opengl.texture.Texture;
  26. import org.anddev.andengine.opengl.texture.TextureOptions;
  27. import org.anddev.andengine.opengl.texture.region.TextureRegion;
  28. import org.anddev.andengine.opengl.texture.region.TextureRegionFactory;
  29. import org.anddev.andengine.opengl.texture.region.TiledTextureRegion;
  30. import org.anddev.andengine.ui.activity.BaseGameActivity;
  31. import org.anddev.andengine.util.Debug;
  32.  
  33. import android.util.Log;
  34.  
  35. import com.pruebas.andengine.CatapultDetector.ICatapultDetectorListener;
  36.  
  37. public class Main extends BaseGameActivity implements IScrollDetectorListener,
  38. IOnSceneTouchListener, ICatapultDetectorListener {
  39. // ===========================================================
  40. // Constants
  41. // ===========================================================
  42. static final int CAMERA_WIDTH = 480;
  43. static final int CAMERA_HEIGHT = 320;
  44.  
  45. private static final String TAG = "AndEngineTest";
  46.  
  47. // ===========================================================
  48. // Fields
  49. // ===========================================================
  50.  
  51. private ZoomCamera mCamera;
  52. private Texture mTexture;
  53. private TiledTextureRegion mBallTextureRegion;
  54. private TiledTextureRegion mPlayerTextureRegion;
  55. private SurfaceScrollDetector mScrollDetector; 
  56. private TMXTiledMap mTMXTiledMap;
  57. private Player mActivePlayer;
  58. private CatapultDetector mCatapultDetector; //Nueva variable Creada
  59.  
  60. // ===========================================================
  61. // Constructors
  62. // ===========================================================
  63.  
  64. // ===========================================================
  65. // Getter & Setter
  66. // ===========================================================
  67.  
  68. // ===========================================================
  69. // Methods for/from SuperClass/Interfaces
  70. // ===========================================================
  71.  
  72. @Override
  73. public void onLoadComplete() {  
  74. createPlayer();
  75. }
  76.  
  77. @Override
  78. public Engine onLoadEngine() {
  79. this.mCamera = new ZoomCamera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
  80. final int alturaTotal = CAMERA_HEIGHT * 3;
  81. this.mCamera.setBounds(0, CAMERA_WIDTH, 0, alturaTotal);
  82. this.mCamera.setBoundsEnabled(true);
  83. return new Engine(new EngineOptions(true, ScreenOrientation.LANDSCAPE,
  84. new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT),
  85. this.mCamera));
  86. }
  87.  
  88. @Override
  89. public void onLoadResources() {
  90. this.mTexture = new Texture(256, 256,
  91. TextureOptions.BILINEAR_PREMULTIPLYALPHA);
  92. this.mBallTextureRegion = TextureRegionFactory.createTiledFromAsset(
  93. this.mTexture, this, "gfx/ui_ball.png", 0, 0, 2, 4);
  94. this.mPlayerTextureRegion = TextureRegionFactory.createTiledFromAsset(
  95. this.mTexture, this, "gfx/ui_player.png", 128, 0, 2, 4);
  96.  
  97. this.mEngine.getTextureManager().loadTexture(this.mTexture);
  98.  
  99. }
  100.  
  101. @Override
  102. public Scene onLoadScene() {
  103. this.mEngine.registerUpdateHandler(new FPSLogger());
  104.  
  105. final Scene scene = new Scene(1);
  106.  
  107. try {
  108. final TMXLoader tmxLoader = new TMXLoader(this, this.mEngine
  109. .getTextureManager(), // TextureOptions.BILINEAR_PREMULTIPLYALPHA,
  110. TextureOptions.NEAREST, new ITMXTilePropertiesListener() {
  111.  
  112. @Override
  113. public void onTMXTileWithPropertiesCreated(
  114. final TMXTiledMap pTMXTiledMap,
  115. final TMXLayer pTMXLayer,
  116. final TMXTile pTMXTile,
  117. final TMXProperties<TMXTileProperty> pTMXTileProperties) {
  118.  
  119. }
  120.  
  121. });
  122. this.mTMXTiledMap = tmxLoader.loadFromAsset(this, "tmx/field.tmx");
  123. } catch (final TMXLoadException tmxle) {
  124. Debug.e(tmxle);
  125. }
  126.  
  127. final TMXLayer tmxLayer = this.mTMXTiledMap.getTMXLayers().get(0);
  128. scene.getFirstChild().attachChild(tmxLayer);
  129.  
  130. scene.setOnAreaTouchTraversalFrontToBack();
  131.  
  132. this.mScrollDetector = new SurfaceScrollDetector(this);
  133. this.mScrollDetector.setEnabled(false); 
  134.  
  135. this.mCatapultDetector = new CatapultDetector(this);
  136. this.mCatapultDetector.setEnabled(true);
  137.  
  138. scene.setOnSceneTouchListener(this);
  139. scene.setTouchAreaBindingEnabled(true);
  140.  
  141. return scene;
  142. }
  143.  
  144.  
  145. @Override
  146. public void onCharge(CatapultDetector pCatapultDetector,
  147. TouchEvent pTouchEvent, float pDistance, float pAngle) {
  148. Log.d(TAG, "Cargando... {Distancia:" + pDistance + ", angulo: "
  149. + pAngle + "}");
  150. this.mActivePlayer.setRotation(pAngle);
  151.  
  152. }
  153.  
  154. @Override
  155. public void onShoot(CatapultDetector pCatapultDetector,
  156. TouchEvent pTouchEvent, float pDistance, float pAngle) {
  157. Log.d(TAG, "Disparo... {Distancia:" + pDistance + ", angulo: " + pAngle
  158. + "}");
  159. } 
  160.  
  161.  
  162. @Override
  163. public void onScroll(ScrollDetector pScollDetector, TouchEvent pTouchEvent,
  164. float pDistanceX, float pDistanceY) {
  165. this.mCamera.offsetCenter(-pDistanceX, -pDistanceY);
  166. }
  167.  
  168. @Override
  169. public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent) {
  170. if (this.mActivePlayer != null) {
  171. this.mCatapultDetector.onTouchEvent(pSceneTouchEvent);
  172. }
  173. return true;
  174. }
  175.  
  176. // ===========================================================
  177. // Methods
  178. // ===========================================================
  179.  
  180. private void createPlayer() {
  181. final Scene scene = this.mEngine.getScene();
  182.  
  183. final Player sprite = new Player(200, 100, this.mPlayerTextureRegion);
  184. scene.getLastChild().attachChild(sprite);
  185.  
  186. this.mActivePlayer = sprite;
  187. } 
  188.  
  189.  
  190. // ===========================================================
  191. // Inner and Anonymous Classes
  192. // ===========================================================
  193. }
  194.  
Parsed in 0.129 seconds at 53.47 KB/s, using GeSHi 1.0.8.10


CatapultDetector.java
  1. package com.pruebas.andengine;
  2.  
  3. import org.anddev.andengine.input.touch.TouchEvent;
  4. import org.anddev.andengine.input.touch.detector.BaseDetector;
  5.  
  6. import android.view.MotionEvent;
  7.  
  8. public class CatapultDetector extends BaseDetector {
  9. // ===========================================================
  10. // Constants
  11. // ===========================================================
  12. private static final float TRIGGER_SCROLL_MINIMUM_DISTANCE_DEFAULT = 10;
  13. private static final float ANGLE_CONSTANT = 10;
  14. private static final int DEFAULT_STEPS = 6;
  15. private float DEFAULT_MAX_DISTANCE = 100;
  16. // ===========================================================
  17. // Fields
  18. // ===========================================================
  19.  
  20. //Minimum distance to execute 
  21. private float mTriggerScrollMinimumDistance;
  22.  
  23. //Listener for the Detector
  24. private final ICatapultDetectorListener mCatapultDetectorListener;
  25.  
  26. private boolean mTriggered;
  27.  
  28. //First Touch
  29. private float mFirstX;
  30. private float mFirstY;
  31.  
  32. //Last Touch
  33. private float mLastX;
  34. private float mLastY;
  35.  
  36. private int mSteps;
  37. private float mMaxDistance;
  38.  
  39. // ===========================================================
  40. // Constructors
  41. // ===========================================================
  42.  
  43. public CatapultDetector(
  44. final ICatapultDetectorListener pCatapultDetectorListener) {
  45. this(TRIGGER_SCROLL_MINIMUM_DISTANCE_DEFAULT, pCatapultDetectorListener);
  46. }
  47.  
  48. public CatapultDetector(final float pTriggerScrollMinimumDistance,
  49. final ICatapultDetectorListener pCatapultDetectorListener) {
  50. this.setTriggerScrollMinimumDistance(pTriggerScrollMinimumDistance);
  51. this.mCatapultDetectorListener = pCatapultDetectorListener;
  52. }
  53.  
  54.  
  55.  
  56. // ===========================================================
  57. // Methods for/from SuperClass/Interfaces
  58. // =========================================================== 
  59.  
  60. @Override
  61. protected boolean onManagedTouchEvent(TouchEvent pSceneTouchEvent) {
  62. final float touchX = this.getX(pSceneTouchEvent);
  63. final float touchY = this.getY(pSceneTouchEvent);
  64.  
  65. switch (pSceneTouchEvent.getAction()) {
  66. case MotionEvent.ACTION_DOWN:
  67. this.mFirstX = touchX;
  68. this.mFirstY = touchY;
  69. this.mLastX = touchX;
  70. this.mLastY = touchY;
  71. this.mTriggered = false;
  72. return true;
  73. case MotionEvent.ACTION_MOVE:
  74. case MotionEvent.ACTION_UP:
  75. case MotionEvent.ACTION_CANCEL:
  76. final float distanceX = touchX - this.mLastX;
  77. final float distanceY = touchY - this.mLastY;
  78. if (pSceneTouchEvent.getAction() == MotionEvent.ACTION_MOVE) {
  79. final float triggerScrollMinimumDistance = this.mTriggerScrollMinimumDistance;
  80. if (this.mTriggered
  81. || Math.abs(distanceX) > triggerScrollMinimumDistance
  82. || Math.abs(distanceY) > triggerScrollMinimumDistance) {
  83. final float distance = (float)Math.hypot((double)distanceX,(double)distanceY);     
  84. final double angleX = touchX - this.mFirstX;
  85. final double angleY = touchY - this.mFirstY;
  86. final float angle = (float)Math.toDegrees(Math.atan2(angleY, angleX));
  87. this.mCatapultDetectorListener.onCharge(this, pSceneTouchEvent, distance, angle);
  88. this.mLastX = touchX;
  89. this.mLastY = touchY;
  90. this.mTriggered = true;
  91. }
  92. else
  93. {
  94.  
  95.  
  96. }
  97. }
  98. return true;
  99. default:
  100. return false;
  101. }
  102. }
  103.  
  104. // ===========================================================
  105. // Getter & Setter
  106. // ===========================================================
  107.  
  108. public void setTriggerScrollMinimumDistance(
  109. float mTriggerScrollMinimumDistance) {
  110. this.mTriggerScrollMinimumDistance = mTriggerScrollMinimumDistance;
  111. }
  112.  
  113. public float getTriggerScrollMinimumDistance() {
  114. return mTriggerScrollMinimumDistance;
  115. }
  116.  
  117. // ===========================================================
  118. // Methods
  119. // ===========================================================
  120.  
  121. protected float getX(final TouchEvent pTouchEvent) {
  122. return pTouchEvent.getX();
  123. }
  124.  
  125. protected float getY(final TouchEvent pTouchEvent) {
  126. return pTouchEvent.getY();
  127. } 
  128.  
  129.  
  130. // ===========================================================
  131. // Inner and Anonymous Classes
  132. // =========================================================== 
  133.  
  134. public static interface ICatapultDetectorListener {
  135. // ===========================================================
  136. // Constants
  137. // ===========================================================
  138.  
  139. // ===========================================================
  140. // Methods
  141. // ===========================================================
  142.  
  143. public void onCharge(final CatapultDetector pCatapultDetector,
  144. final TouchEvent pTouchEvent, final float pDistance,
  145. final float pAngle);
  146.  
  147. public void onShoot(final CatapultDetector pCatapultDetector,
  148. final TouchEvent pTouchEvent, final float pDistance,
  149. final float pAngle);
  150. }
  151.  
  152. }
  153.  
Parsed in 0.126 seconds at 38.60 KB/s, using GeSHi 1.0.8.10

Bueno, por hoy está bien, voy a seguir trabajando en el Detector y cuando lo tenga terminado lo pongo en el foro de AndEngine y subo otro artículo siguiendo por la misma línea.

7 comentarios:

MeKaWeNDie dijo...

Sigue así crack !!!

A ver si puedo ir sacando tiempo y puedo mirarlo un poco más a fondo todo.

Muchas gracias por tu trabajo!

Angel dijo...

Gracias por el comentario.

Voy a pasar unas semanas en las que no voy a poder dedicarle tiempo a esto, pero ya tengo metido el motor de físicas box2d para el proyecto, y funciona de lujo. Para el siguiente artículo lo pongo.

@MMMM87 dijo...

Estoy tratando hacer funcionar las librerias y el motor de fisicas pero no lo he conseguido. Es necesario tenerlas separadas?! o pueden estar en un solo archivo jar(la libreria y las extensiones)??

Osiris dijo...

Nesecito más! plis!!

gst dijo...

Buscando info sobre andengine y desarrollo de juegos 2D he encontrado tu blog. Es muy interesante lo que aquí explicas.

Te expongo mi problema a ver si tu te has encontrado con lo mismo:
Yo estoy intentando desarrollar un juego de mesa en android. El tema es que para el tablero intento ver ejemplos de trabajo con polígonos (regulares, triángulos, cuadrados y también círculos) y aunque encuentro ejemplos en andengine no consigo que compilen porque no veo esas clases en la extensión.
Agradecería ayudas...;-)

Paco dijo...

Hola Angel
Como vas con este tutorial,... he realizado todos los capitulos y me he quedado con la miel en los labios,... hay mas tutoriales?

Cristian Garcia Escobar dijo...

hola como vas excelentes tutoriales, vas a continuar con ellos?

Publicar un comentario