Friday, April 27, 2012
Blog Status
Monday, December 5, 2011
AndEngine Quick Start Guide
Prerequisites
You must have Eclipse and Android SDK already installed.
First of all we need the Mercurial plug-in installed. Go in Eclipse to Help -> Install New Software, and install from http://cbes.javaforge.com/update.
Getting AndEngine Sources
To get AndEngine sources in eclipse, go to File -> Import in the Eclipse menu.
Then select "Close existing Mercurial Respository"
In Repository Location put https://code.google.com/p/andengine/ and click Next
Click Next Again. and Finish. My Eclipse looks like this:
Then we have some errors in the Eclipse proyect. To solve this you need to do two things.
Right click on AndEngine Proyect and go to properties.
In the left side choose Java Compiler and make sure that Enable project specific settings and 1.6 in the compilance level is clicked.
Right click on the AndEngine proyect and go to Android Tools -> Fix project properties.
New we have a clean AndEngine sources installed.
We must get now all the extensions for AndEngine. Repeat the same process with these urls
- https://code.google.com/p/andenginelivewallpaperextension
- https://code.google.com/p/andenginemodplayerextension
- https://code.google.com/p/andenginemultiplayerextension
- https://code.google.com/p/andenginemultitouchextension
- https://code.google.com/p/andenginephysicsbox2dextension
- https://code.google.com/p/andengineaugmentedrealityextension
- https://code.google.com/p/andenginesvgtextureregionextension
- https://code.google.com/p/andenginetexturepackerextension
Congratulations
We have now a clean installation of AndEngine totally updated. In the next weeks i will update all the series of the tutorials to the last version of AndEngine.
Saturday, August 6, 2011
Saturday, June 11, 2011
Off-Topic Article: How to stay up to date in andengine
Getting the sources of AndEngine
First of all we need to get the sources. We need to get the sources of andengine. For that you will need any Mercurial Client.
In my case (debian) "apt-get install mercurial", in ubuntu it may work well. If you use windows, try with the links in the mercurial page. Now we need to create a directory, open a terminal, go to that folder and write this:
I have an output like this:
requesting all changes
adding changesets
adding manifests
adding file changes
added 818 changesets with 3243 changes to 703 files (+4 heads)
updating to branch default
410 files updated, 0 files merged, 0 files removed, 0 files unresolved
Congratulations, our first step to have our own andengine.jar is completed
Importing sources in android
In the Eclipse menu, we go to File -> Import
We select "Existing Projects into Workspace" and press Next. Now in "Select root directory" we need to browse to the directory when we downloaded the sources of andEngine. In my case looks like that.
If you have done all the steps correctly, in Projects you must see AndEngine checked. Click Finish.
Now we have the project inside Eclipse, but it appears some erors.
Fixing some errors
Once imported the project in Eclipse, you need to create the Res folder. Right Click on AndEngine Root Project and select New -> Folder
Once created the res folder the problems have gone away.
Exporting the jar
Right Click on root AndEngine Project and select export.
We select Java -> Jar file and click Next.
In the next screen we need to do something important, we need to uncheck all the checkboxes in the right part of the screen, i marked in the photo in red. Then you need to put a path to the jar... and click Finish. All done.
Hope it helps you guys.
Friday, April 8, 2011
Current State of Development (April 2011)
Sorry about the quality of the video. I expect to put the code in subversion and make one, two or three articles to get to the actual state. Working with Box2d.
Wednesday, March 30, 2011
AndEngine from Scratch (V)
Previously on AndEngine from Scratch
Today Goals
- Finish the CatapultDetector
- Make the player react to the detector's events.
Let's go with the Detector
I have the Detector stable, here is the complete code:
package com.pruebas.andengine;
import org.anddev.andengine.input.touch.TouchEvent;
import org.anddev.andengine.input.touch.detector.BaseDetector;
import android.view.MotionEvent;
public class CatapultDetector extends BaseDetector {
// ===========================================================
// Constants
// ===========================================================
private static final float ANGLE_CONSTANT = 90;
private static final float DEFAULT_MAX_DISTANCE = 80;
// ===========================================================
// Fields
// ===========================================================
// Listener for the Detector
private final ICatapultDetectorListener mCatapultDetectorListener;
private float mMaxDistance;
// First Touch
private float mFirstX;
private float mFirstY;
// ===========================================================
// Constructors
// ===========================================================
public CatapultDetector(
final ICatapultDetectorListener pCatapultDetectorListener) {
this(DEFAULT_MAX_DISTANCE, pCatapultDetectorListener);
}
public CatapultDetector(final float pMaxDistance,
final ICatapultDetectorListener pCatapultDetectorListener) {
this.setMaxDistance(pMaxDistance);
this.mCatapultDetectorListener = pCatapultDetectorListener;
}
// ===========================================================
// Methods for/from SuperClass/Interfaces
// ===========================================================
@Override
protected boolean onManagedTouchEvent(TouchEvent pSceneTouchEvent) {
final float touchX = this.getX(pSceneTouchEvent);
final float touchY = this.getY(pSceneTouchEvent);
final int action = pSceneTouchEvent.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
this.mFirstX = touchX;
this.mFirstY = touchY;
return true;
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
// case MotionEvent.ACTION_CANCEL:
final float distanceX = Math.abs(touchX - this.mFirstX);
final float distanceY = Math.abs(touchY - this.mFirstY);
final float distance = Math.min((float) Math.hypot(
(double) distanceX, (double) distanceY), mMaxDistance);
final double angleX = touchX - this.mFirstX;
final double angleY = touchY - this.mFirstY;
final float angle = (float) Math.toDegrees(Math.atan2(angleY,
angleX))
+ ANGLE_CONSTANT;
if (action == MotionEvent.ACTION_MOVE) {
this.mCatapultDetectorListener.onCharge(this, pSceneTouchEvent,
distance, angle);
} else {
this.mCatapultDetectorListener.onShoot(this, pSceneTouchEvent,
distance, angle);
}
return true;
default:
return false;
}
}
// ===========================================================
// Getter & Setter
// ===========================================================
public void setMaxDistance(float mMaxDistance) {
this.mMaxDistance = mMaxDistance;
}
public float getMaxDistance() {
return mMaxDistance;
}
// ===========================================================
// Methods
// ===========================================================
protected float getX(final TouchEvent pTouchEvent) {
return pTouchEvent.getX();
}
protected float getY(final TouchEvent pTouchEvent) {
return pTouchEvent.getY();
}
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
public static interface ICatapultDetectorListener {
// ===========================================================
// Constants
// ===========================================================
// ===========================================================
// Methods
// ===========================================================
public void onCharge(final CatapultDetector pCatapultDetector,
final TouchEvent pTouchEvent, final float pDistance,
final float pAngle);
public void onShoot(final CatapultDetector pCatapultDetector,
final TouchEvent pTouchEvent, final float pDistance,
final float pAngle);
}
}
Let's take a look on the Listener, is the starting point of the listener.
public static interface ICatapultDetectorListener {
// ===========================================================
// Constants
// ===========================================================
// ===========================================================
// Methods
// ===========================================================
public void onCharge(final CatapultDetector pCatapultDetector,
final TouchEvent pTouchEvent, final float pDistance,
final float pAngle);
public void onShoot(final CatapultDetector pCatapultDetector,
final TouchEvent pTouchEvent, final float pDistance,
final float pAngle);
}
This listener has to respond two kind of events, when we are "charging" and when we shoot. The onCharge() method is for the first one and the onShoot() for the second one. The parameters to this methods are the same.
- pCatapultDetector: The detector itself.
- pTouchEvent: The current TouchScreen Event.
- pDistance: Distance from the starting point of the gesture to the current point.
- pAngle: The angle formed by the first touch point and the current.
// ===========================================================
// Constants
// ===========================================================
private static final float ANGLE_CONSTANT = 90;
private static final float DEFAULT_MAX_DISTANCE = 80;
// ===========================================================
// Fields
// ===========================================================
// Listener for the Detector
private final ICatapultDetectorListener mCatapultDetectorListener;
private float mMaxDistance;
// First Touch
private float mFirstX;
private float mFirstY;
We have the constants
- ANGLE_CONSTANT: In the early tests, i had to sum 90 to the angle for the player to rotate the correct angle.
- DEFAULT_MAX_DISTANCE: Default max distance of charge, if not indicated in the constructor, this is the max distance of charge, if you try to charge a number larger than the max distance, the detector will trigger the listener with the max distance.
Let's view the variables.
- mCatapultDetectorListener: Is a ICatapultDetectorListener that we have seen before. Is mandatary to have one Listener.
- mMaxDistance: In this variable we hold the max distance.
- mFirstX,mFirstY: First point of touch in X,Y coordinates.
Let's go to the class constructors
// ===========================================================
// Constructors
// ===========================================================
public CatapultDetector(
final ICatapultDetectorListener pCatapultDetectorListener) {
this(DEFAULT_MAX_DISTANCE, pCatapultDetectorListener);
}
public CatapultDetector(final float pMaxDistance,
final ICatapultDetectorListener pCatapultDetectorListener) {
this.setMaxDistance(pMaxDistance);
this.mCatapultDetectorListener = pCatapultDetectorListener;
}
We have two different constructors. The first one is invoked with only one parameter, the ICatapultDetectorListener that responds to the events. In the second one we can specify the value of Max Charge distance.
The real work in the detector is in the onManagedTouchEvent() method. It has only one parameter, the TouchEvent.
final float touchX = this.getX(pSceneTouchEvent);
final float touchY = this.getY(pSceneTouchEvent);
final int action = pSceneTouchEvent.getAction();
Here we use final variables to hold data usefull later in the method. In the first line we hold the X coordinate of the event, in the second the Y coordinate and in the third we have the action performed, in our case three posible values.
- ACTION_DOWN : The user touch the screen for first time.
- ACTION_MOVE : The user has the finger on the screen and move it.
- ACTION_UP : The take the finger away from the screen.
When the event is ACTION_DOWN the only thing we need to do is keep the coordinates where the user put the finger, that we will use them to calculate angles and distance.
To the ACTION_MOVE and ACTION_UP we use the same code for both.
final float distanceX = Math.abs(touchX - this.mFirstX);
final float distanceY = Math.abs(touchY - this.mFirstY);
final float distance = Math.min((float) Math.hypot(
(double) distanceX, (double) distanceY), mMaxDistance);
final double angleX = touchX - this.mFirstX;
final double angleY = touchY - this.mFirstY;
final float angle = (float) Math.toDegrees(Math.atan2(angleY,
angleX))
+ ANGLE_CONSTANT;
if (action == MotionEvent.ACTION_MOVE) {
this.mCatapultDetectorListener.onCharge(this, pSceneTouchEvent,
distance, angle);
} else {
this.mCatapultDetectorListener.onShoot(this, pSceneTouchEvent,
distance, angle);
}
return true;
First and second line, we grab the distance between the first and last touch coordinates in pixels. The third line calculates with hypot the real distance between the two points. In this third line we apply the Max distance of charge. Let's go to the angle.
The best way i found to figure th e angle between two point is the next lines method.We have in the angle variable the angle.
If the action is ACTION_MOVE we trigger an onCharge() event, if the action is ACTION_UP we trigger an onShoot() event.
With that we have finished the first version of our Detector. Sure there will be better and more efficiently ways to do this. If you have one better solution, please post it in the comments and i change the tutorial. I will send you a virtual beer ;)
Adapting the Player Class
First of all, the Player is a descendant of the AnimatedSprite class.
We have here the diferent frames of the animation. Let's go to work. Define a constant to hold the max frame of the charging state, if you look well, the las two frames are for the movement when the user releases the player.
private static final int PLAYER_CHARGE_ANIMATIONS = 5;
Let's add one method to the class.
public void setCharge(final float angle, final float distance)
{
final int step = Math.round(distance * PLAYER_CHARGE_ANIMATIONS / Main.MAX_CHARGE_DISTANCE);
this.stopAnimation(step);
this.setRotation(angle);
}
In the first line, we use a "rule of three" (Is this correct in english?) to calculate the actual frame according to distance the detector send to us. We use the MAX_CHARGE_DISTANCE constant (we will define that later). We use the stopAnimation() method to indicate the sprite not to animate and which frame we want to see in the screen. Then we rotate the Sprite the angle.
Let's go to the Main.java and put that constant. Mine look like this:
// ===========================================================
// Constants
// ===========================================================
private static final int CAMERA_WIDTH = 480;
private static final int CAMERA_HEIGHT = 320;
public static final float MAX_CHARGE_DISTANCE = 80;
private static final String TAG = "AndEngineTest";
In the onLoadScene() method we touch where the CatapultDetector is created and pass this constant to the constructor.
this.mScrollDetector = new SurfaceScrollDetector(this);
this.mScrollDetector.setEnabled(false);
this.mCatapultDetector = new CatapultDetector(MAX_CHARGE_DISTANCE,this);
this.mCatapultDetector.setEnabled(true);
Change the onCharge() method
@Override
public void onCharge(CatapultDetector pCatapultDetector,
TouchEvent pTouchEvent, float pDistance, float pAngle) {
this.mActivePlayer.setCharge(pAngle,pDistance);
}
Here we pass the player the level of charge. With these modifications the programs runs correctly. If you experienced any problem in this tutorial, please contact with me or post a comment and i will be pleased to solve it.
In the next chapter we will see how integrate the Box2d phisics engine and some improvements in the game.
Source Code
To get the source code: svn checkout http://ch-soccer.googlecode.com/svn/trunk/ tutorial-read-only -r 8
Index
Friday, March 25, 2011
AndEngine from Scratch (IV)
Previously on AndEngine from Scratch
Today goals
- Create the player sprite.
- Create a Detector to the catapult effect.
Create the player
To create the player i decided to use an AnimatedSprite, but we subclass the AnimatedSprite to be able to personalize it.
To crate the class, go to the folder with the sources in Eclipse. File New -> Class and the Name is Player and the SuperClass is AnimatedSprite. We add a debug TAG and for now is ok.
package com.pruebas.andengine;
import org.anddev.andengine.entity.sprite.AnimatedSprite;
import org.anddev.andengine.input.touch.detector.HoldDetector;
import org.anddev.andengine.input.touch.detector.HoldDetector.IHoldDetectorListener;
import org.anddev.andengine.opengl.texture.region.TiledTextureRegion;
import android.util.Log;
public class Player extends AnimatedSprite {
private static final String TAG = "Player";
public Player(float pX, float pY, TiledTextureRegion pTiledTextureRegion) {
super(pX, pY, pTiledTextureRegion);
}
}
Get back to the Main.java and let's add a variable to hold the active Player object. Let's change the mFaceTextureRegion to mBallTextureRegion to make it pretty and change the type to TiledTextureRegion. My variables looks like this:
// ===========================================================
// Fields
// ===========================================================
private ZoomCamera mCamera;
private Texture mTexture;
private TiledTextureRegion mBallTextureRegion;
private TiledTextureRegion mPlayerTextureRegion;
private SurfaceScrollDetector mScrollDetector;
private TMXTiledMap mTMXTiledMap;
private Player mActivePlayer;
Here is the player sprite, download to your assets/gfx folder as usual.
Here is some experimental ball sprite (i need a real ball to make photos), to the same site, assets/gfx
Now we must change the way to load the textures to load this new two textures. All the textures go to the mTexture Object. The mTexture object need a power of two in width and height in pixels. To hold the textures recently downloaded we need exactly 256X256 pixels. The texture in memory would look like this:
Let's change en onLoadResources() method to load all this new stuff. First of all, the size of the mTexture needs to be 256X256 and now to load the ball texture we use the createTiledFromAsset() function with the parameters:
- this.mTexture: The first is the mTexture object where all the textures are going
- this: Actual class.
- "gfx/ui_ball.png": Path to the image containing the tiled sprites.
- 0,0: The next two integer parameters is where are going yo put the image inside mTexture. In this case, in the top left corner (0,0). The player in the top middle (128,0).
- 2,4: Number of rows an columns in the tile. 2,4 in our case.
@Override
public void onLoadResources() {
this.mTexture = new Texture(256, 256,
TextureOptions.BILINEAR_PREMULTIPLYALPHA);
this.mBallTextureRegion = TextureRegionFactory.createTiledFromAsset(
this.mTexture, this, "gfx/ui_ball.png", 0, 0, 2, 4);
this.mPlayerTextureRegion = TextureRegionFactory.createTiledFromAsset(
this.mTexture, this, "gfx/ui_player.png", 128, 0, 2, 4);
this.mEngine.getTextureManager().loadTexture(this.mTexture);
}
Now, some code on the onLoadScene() method. First we delete the source creating the ball and deactivate the ScrollDetector. The procedure should look like this:
scene.setOnAreaTouchTraversalFrontToBack();
this.mScrollDetector = new SurfaceScrollDetector(this);
this.mScrollDetector.setEnabled(false); //Hemos puesto esto a false
/*
final int centerX = (CAMERA_WIDTH - this.mFaceTextureRegion.getWidth()) / 2;
final int centerY = (CAMERA_HEIGHT - this.mFaceTextureRegion
.getHeight()) / 2;
final Sprite ball = new Sprite(centerX, centerY,
this.mFaceTextureRegion);
scene.getLastChild().attachChild(ball);
*/
scene.setOnSceneTouchListener(this);
scene.setTouchAreaBindingEnabled(true);
return scene;
}
Let's create a method to create a player to test the animation.
// ===========================================================
// Methods
// ===========================================================
private void createPlayer() {
final Scene scene = this.mEngine.getScene();
final Player sprite = new Player(200, 100, this.mPlayerTextureRegion);
// scene.registerTouchArea(sprite);
scene.getLastChild().attachChild(sprite);
this.mActivePlayer = sprite;
}
To test, we are gonna put a player in the 200X100 position. Call this new function from onLoadComplete().
@Override
public void onLoadComplete() { // scene.set
createPlayer();
}
In this point, we can debug our program to see what's happen. We can see the background grass and the player. It doesn't respond to scroll because we deactivated it. Let's create the detector.
Creating a Detector
Looking around in the AndEngine sources, the ScrollDetector is a very easy way to create Detectors.
We create a new class in our project. Name: CatapultDetector and SuperClass BaseDetector
(org.anddev.andengine.input.touch.detector.BaseDetector)
package com.pruebas.andengine;
import org.anddev.andengine.input.touch.TouchEvent;
import org.anddev.andengine.input.touch.detector.BaseDetector;
public class CatapultDetector extends BaseDetector {
@Override
protected boolean onManagedTouchEvent(TouchEvent pSceneTouchEvent) {
// TODO Auto-generated method stub
return false;
}
}
We are going to try to make a Detector that works like the ScrollDetector, we need a listener interface.
public static interface ICatapultDetectorListener {
// ===========================================================
// Constants
// ===========================================================
// ===========================================================
// Methods
// ===========================================================
public void onCharge(final CatapultDetector pCatapultDetector,
final TouchEvent pTouchEvent, final float pDistance,
final float pAngle);
public void onShoot(final CatapultDetector pCatapultDetector,
final TouchEvent pTouchEvent, final float pDistance,
final float pAngle);
}
This is a basic listener to test the working of the Detector. The listener object recieves the angle and distance of the soot. We define this class inside the CatapultDetector class like the other detector in AndEngine.
Let's put some variables to the detector.
// ===========================================================
// Constants
// ===========================================================
private static final float TRIGGER_SCROLL_MINIMUM_DISTANCE_DEFAULT = 10;
private static final float ANGLE_CONSTANT = 10;
private static final int DEFAULT_STEPS = 6;
private float DEFAULT_MAX_DISTANCE = 100;
// ===========================================================
// Fields
// ===========================================================
//Minimum distance to execute
private float mTriggerScrollMinimumDistance;
//Listener for the Detector
private final ICatapultDetectorListener mCatapultDetectorListener;
private boolean mTriggered;
//First Touch
private float mFirstX;
private float mFirstY;
//Last Touch
private float mLastX;
private float mLastY;
private int mSteps;
private float mMaxDistance;
We create some methods to use later and getter and setter to mTriggerScrollMinimumDistance
// ===========================================================
// Getter & Setter
// ===========================================================
public void setTriggerScrollMinimumDistance(
float mTriggerScrollMinimumDistance) {
this.mTriggerScrollMinimumDistance = mTriggerScrollMinimumDistance;
}
public float getTriggerScrollMinimumDistance() {
return mTriggerScrollMinimumDistance;
}
// ===========================================================
// Methods
// ===========================================================
protected float getX(final TouchEvent pTouchEvent) {
return pTouchEvent.getX();
}
protected float getY(final TouchEvent pTouchEvent) {
return pTouchEvent.getY();
}
Code a little in the class constructors.
// ===========================================================
// Constructors
// ===========================================================
public CatapultDetector(
final ICatapultDetectorListener pCatapultDetectorListener) {
this(TRIGGER_SCROLL_MINIMUM_DISTANCE_DEFAULT, pCatapultDetectorListener);
}
public CatapultDetector(final float pTriggerScrollMinimumDistance,
final ICatapultDetectorListener pCatapultDetectorListener) {
this.setTriggerScrollMinimumDistance(pTriggerScrollMinimumDistance);
this.mCatapultDetectorListener = pCatapultDetectorListener;
}
And now the main method of the class, where all happens.
// ===========================================================
// Methods for/from SuperClass/Interfaces
// ===========================================================
@Override
protected boolean onManagedTouchEvent(TouchEvent pSceneTouchEvent) {
final float touchX = this.getX(pSceneTouchEvent);
final float touchY = this.getY(pSceneTouchEvent);
switch (pSceneTouchEvent.getAction()) {
case MotionEvent.ACTION_DOWN:
this.mFirstX = touchX;
this.mFirstY = touchY;
this.mLastX = touchX;
this.mLastY = touchY;
this.mTriggered = false;
return true;
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
final float distanceX = touchX - this.mLastX;
final float distanceY = touchY - this.mLastY;
if (pSceneTouchEvent.getAction() == MotionEvent.ACTION_MOVE) {
final float triggerScrollMinimumDistance = this.mTriggerScrollMinimumDistance;
if (this.mTriggered
|| Math.abs(distanceX) > triggerScrollMinimumDistance
|| Math.abs(distanceY) > triggerScrollMinimumDistance) {
final float distance = (float)Math.hypot((double)distanceX,(double)distanceY);
final double angleX = touchX - this.mFirstX;
final double angleY = touchY - this.mFirstY;
final float angle = (float)Math.toDegrees(Math.atan2(angleY, angleX))+ANGLE_CONSTANT;
this.mCatapultDetectorListener.onCharge(this, pSceneTouchEvent, distance, angle);
this.mLastX = touchX;
this.mLastY = touchY;
this.mTriggered = true;
}
else
{
}
}
return true;
default:
return false;
}
}
In The next article we are going to explain more carefully the Detector, but looking the source you can see how it works. Let's back to the Main.java. Create a private variable to hold the Detector Object.
// ===========================================================
// Fields
// ===========================================================
private ZoomCamera mCamera;
private Texture mTexture;
private TiledTextureRegion mBallTextureRegion;
private TiledTextureRegion mPlayerTextureRegion;
private SurfaceScrollDetector mScrollDetector;
private TMXTiledMap mTMXTiledMap;
private Player mActivePlayer;
private CatapultDetector mCatapultDetector; //Nueva variable Creada
Now tell the Main class to implement the new ICatapultDetectorListener interface.
public class Main extends BaseGameActivity implements IScrollDetectorListener,
IOnSceneTouchListener, ICatapultDetectorListener
Now we must implement the missing methods of the interface.
@Override
public void onCharge(CatapultDetector pCatapultDetector,
TouchEvent pTouchEvent, float pDistance, float pAngle) {
Log.d(TAG, "Cargando... {Distancia:" + pDistance + ", angulo: "
+ pAngle + "}");
this.mActivePlayer.setRotation(pAngle);
}
@Override
public void onShoot(CatapultDetector pCatapultDetector,
TouchEvent pTouchEvent, float pDistance, float pAngle) {
Log.d(TAG, "Disparo... {Distancia:" + pDistance + ", angulo: " + pAngle
+ "}");
}
In the onCharge() method, we rotate the player sprite according to the calculated angle. In the onShoot() method, only Debug message. The next step is create in the onLoadScene() method the Detector and assign to the Main Object.
this.mScrollDetector = new SurfaceScrollDetector(this);
this.mScrollDetector.setEnabled(false);
//Creamos el detector de catapulta
this.mCatapultDetector = new CatapultDetector(this);
this.mCatapultDetector.setEnabled(true);
And in the onSceneTouchEvent() method we pass the event to the CatapultDetector.
@Override
public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent) {
if (this.mActivePlayer != null) {
this.mCatapultDetector.onTouchEvent(pSceneTouchEvent);
}
return true;
}
We now can debug again the project and see what's going on. F11... we can see the splash, the background, the player... all fine. Let's tap with the finger on the Screen and do some move around. The payer rotates but not in the desired angle. It's a start. Now my files are like this:
package com.pruebas.andengine;
import org.anddev.andengine.engine.Engine;
import org.anddev.andengine.engine.camera.ZoomCamera;
import org.anddev.andengine.engine.options.EngineOptions;
import org.anddev.andengine.engine.options.EngineOptions.ScreenOrientation;
import org.anddev.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
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.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.TMXLoader.ITMXTilePropertiesListener;
import org.anddev.andengine.entity.layer.tiled.tmx.util.exception.TMXLoadException;
import org.anddev.andengine.entity.scene.Scene;
import org.anddev.andengine.entity.scene.Scene.IOnSceneTouchListener;
import org.anddev.andengine.entity.sprite.AnimatedSprite;
import org.anddev.andengine.entity.sprite.Sprite;
import org.anddev.andengine.entity.util.FPSLogger;
import org.anddev.andengine.input.touch.TouchEvent;
import org.anddev.andengine.input.touch.detector.ScrollDetector;
import org.anddev.andengine.input.touch.detector.SurfaceScrollDetector;
import org.anddev.andengine.input.touch.detector.ScrollDetector.IScrollDetectorListener;
import org.anddev.andengine.opengl.texture.Texture;
import org.anddev.andengine.opengl.texture.TextureOptions;
import org.anddev.andengine.opengl.texture.region.TextureRegion;
import org.anddev.andengine.opengl.texture.region.TextureRegionFactory;
import org.anddev.andengine.opengl.texture.region.TiledTextureRegion;
import org.anddev.andengine.ui.activity.BaseGameActivity;
import org.anddev.andengine.util.Debug;
import android.util.Log;
import com.pruebas.andengine.CatapultDetector.ICatapultDetectorListener;
public class Main extends BaseGameActivity implements IScrollDetectorListener,
IOnSceneTouchListener, ICatapultDetectorListener {
// ===========================================================
// Constants
// ===========================================================
static final int CAMERA_WIDTH = 480;
static final int CAMERA_HEIGHT = 320;
private static final String TAG = "AndEngineTest";
// ===========================================================
// Fields
// ===========================================================
private ZoomCamera mCamera;
private Texture mTexture;
private TiledTextureRegion mBallTextureRegion;
private TiledTextureRegion mPlayerTextureRegion;
private SurfaceScrollDetector mScrollDetector;
private TMXTiledMap mTMXTiledMap;
private Player mActivePlayer;
private CatapultDetector mCatapultDetector; //Nueva variable Creada
// ===========================================================
// Constructors
// ===========================================================
// ===========================================================
// Getter & Setter
// ===========================================================
// ===========================================================
// Methods for/from SuperClass/Interfaces
// ===========================================================
@Override
public void onLoadComplete() {
createPlayer();
}
@Override
public Engine onLoadEngine() {
this.mCamera = new ZoomCamera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
final int alturaTotal = CAMERA_HEIGHT * 3;
this.mCamera.setBounds(0, CAMERA_WIDTH, 0, alturaTotal);
this.mCamera.setBoundsEnabled(true);
return new Engine(new EngineOptions(true, ScreenOrientation.LANDSCAPE,
new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT),
this.mCamera));
}
@Override
public void onLoadResources() {
this.mTexture = new Texture(256, 256,
TextureOptions.BILINEAR_PREMULTIPLYALPHA);
this.mBallTextureRegion = TextureRegionFactory.createTiledFromAsset(
this.mTexture, this, "gfx/ui_ball.png", 0, 0, 2, 4);
this.mPlayerTextureRegion = TextureRegionFactory.createTiledFromAsset(
this.mTexture, this, "gfx/ui_player.png", 128, 0, 2, 4);
this.mEngine.getTextureManager().loadTexture(this.mTexture);
}
@Override
public Scene onLoadScene() {
this.mEngine.registerUpdateHandler(new FPSLogger());
final Scene scene = new Scene(1);
try {
final TMXLoader tmxLoader = new TMXLoader(this, this.mEngine
.getTextureManager(), // TextureOptions.BILINEAR_PREMULTIPLYALPHA,
TextureOptions.NEAREST, new ITMXTilePropertiesListener() {
@Override
public void onTMXTileWithPropertiesCreated(
final TMXTiledMap pTMXTiledMap,
final TMXLayer pTMXLayer,
final TMXTile pTMXTile,
final TMXProperties<TMXTileProperty> pTMXTileProperties) {
}
});
this.mTMXTiledMap = tmxLoader.loadFromAsset(this, "tmx/field.tmx");
} catch (final TMXLoadException tmxle) {
Debug.e(tmxle);
}
final TMXLayer tmxLayer = this.mTMXTiledMap.getTMXLayers().get(0);
scene.getFirstChild().attachChild(tmxLayer);
scene.setOnAreaTouchTraversalFrontToBack();
this.mScrollDetector = new SurfaceScrollDetector(this);
this.mScrollDetector.setEnabled(false);
this.mCatapultDetector = new CatapultDetector(this);
this.mCatapultDetector.setEnabled(true);
scene.setOnSceneTouchListener(this);
scene.setTouchAreaBindingEnabled(true);
return scene;
}
@Override
public void onCharge(CatapultDetector pCatapultDetector,
TouchEvent pTouchEvent, float pDistance, float pAngle) {
Log.d(TAG, "Cargando... {Distancia:" + pDistance + ", angulo: "
+ pAngle + "}");
this.mActivePlayer.setRotation(pAngle);
}
@Override
public void onShoot(CatapultDetector pCatapultDetector,
TouchEvent pTouchEvent, float pDistance, float pAngle) {
Log.d(TAG, "Disparo... {Distancia:" + pDistance + ", angulo: " + pAngle
+ "}");
}
@Override
public void onScroll(ScrollDetector pScollDetector, TouchEvent pTouchEvent,
float pDistanceX, float pDistanceY) {
this.mCamera.offsetCenter(-pDistanceX, -pDistanceY);
}
@Override
public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent) {
if (this.mActivePlayer != null) {
this.mCatapultDetector.onTouchEvent(pSceneTouchEvent);
}
return true;
}
// ===========================================================
// Methods
// ===========================================================
private void createPlayer() {
final Scene scene = this.mEngine.getScene();
final Player sprite = new Player(200, 100, this.mPlayerTextureRegion);
scene.getLastChild().attachChild(sprite);
this.mActivePlayer = sprite;
}
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
}
package com.pruebas.andengine;
import org.anddev.andengine.input.touch.TouchEvent;
import org.anddev.andengine.input.touch.detector.BaseDetector;
import android.view.MotionEvent;
public class CatapultDetector extends BaseDetector {
// ===========================================================
// Constants
// ===========================================================
private static final float TRIGGER_SCROLL_MINIMUM_DISTANCE_DEFAULT = 10;
private static final float ANGLE_CONSTANT = 10;
private static final int DEFAULT_STEPS = 6;
private float DEFAULT_MAX_DISTANCE = 100;
// ===========================================================
// Fields
// ===========================================================
//Minimum distance to execute
private float mTriggerScrollMinimumDistance;
//Listener for the Detector
private final ICatapultDetectorListener mCatapultDetectorListener;
private boolean mTriggered;
//First Touch
private float mFirstX;
private float mFirstY;
//Last Touch
private float mLastX;
private float mLastY;
private int mSteps;
private float mMaxDistance;
// ===========================================================
// Constructors
// ===========================================================
public CatapultDetector(
final ICatapultDetectorListener pCatapultDetectorListener) {
this(TRIGGER_SCROLL_MINIMUM_DISTANCE_DEFAULT, pCatapultDetectorListener);
}
public CatapultDetector(final float pTriggerScrollMinimumDistance,
final ICatapultDetectorListener pCatapultDetectorListener) {
this.setTriggerScrollMinimumDistance(pTriggerScrollMinimumDistance);
this.mCatapultDetectorListener = pCatapultDetectorListener;
}
// ===========================================================
// Methods for/from SuperClass/Interfaces
// ===========================================================
@Override
protected boolean onManagedTouchEvent(TouchEvent pSceneTouchEvent) {
final float touchX = this.getX(pSceneTouchEvent);
final float touchY = this.getY(pSceneTouchEvent);
switch (pSceneTouchEvent.getAction()) {
case MotionEvent.ACTION_DOWN:
this.mFirstX = touchX;
this.mFirstY = touchY;
this.mLastX = touchX;
this.mLastY = touchY;
this.mTriggered = false;
return true;
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
final float distanceX = touchX - this.mLastX;
final float distanceY = touchY - this.mLastY;
if (pSceneTouchEvent.getAction() == MotionEvent.ACTION_MOVE) {
final float triggerScrollMinimumDistance = this.mTriggerScrollMinimumDistance;
if (this.mTriggered
|| Math.abs(distanceX) > triggerScrollMinimumDistance
|| Math.abs(distanceY) > triggerScrollMinimumDistance) {
final float distance = (float)Math.hypot((double)distanceX,(double)distanceY);
final double angleX = touchX - this.mFirstX;
final double angleY = touchY - this.mFirstY;
final float angle = (float)Math.toDegrees(Math.atan2(angleY, angleX));
this.mCatapultDetectorListener.onCharge(this, pSceneTouchEvent, distance, angle);
this.mLastX = touchX;
this.mLastY = touchY;
this.mTriggered = true;
}
else
{
}
}
return true;
default:
return false;
}
}
// ===========================================================
// Getter & Setter
// ===========================================================
public void setTriggerScrollMinimumDistance(
float mTriggerScrollMinimumDistance) {
this.mTriggerScrollMinimumDistance = mTriggerScrollMinimumDistance;
}
public float getTriggerScrollMinimumDistance() {
return mTriggerScrollMinimumDistance;
}
// ===========================================================
// Methods
// ===========================================================
protected float getX(final TouchEvent pTouchEvent) {
return pTouchEvent.getX();
}
protected float getY(final TouchEvent pTouchEvent) {
return pTouchEvent.getY();
}
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
public static interface ICatapultDetectorListener {
// ===========================================================
// Constants
// ===========================================================
// ===========================================================
// Methods
// ===========================================================
public void onCharge(final CatapultDetector pCatapultDetector,
final TouchEvent pTouchEvent, final float pDistance,
final float pAngle);
public void onShoot(final CatapultDetector pCatapultDetector,
final TouchEvent pTouchEvent, final float pDistance,
final float pAngle);
}
}
Good work today. I'm working on this Detector. The next chapter in the same subject.
Source Code
To get the source code: svn checkout http://ch-soccer.googlecode.com/svn/trunk/ tutorial-read-only -r 7