How to Create a Simple Android Game with AndEngine
This is a blog post by iOS Tutorial Team member Ali Hafizji, an iOS and Android developer working at Tavisca Solutions. In this tutorial, you’re going to get hands-on experience making a simple game on Android using AndEngine, a popular and easy to use game framework. There are many frameworks you can use to make […] By Ali Hafizji.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
How to Create a Simple Android Game with AndEngine
35 mins
Game Logic
Ready to bring your Tower of Hanoi puzzle to life? As mentioned before, as the foundation of the game logic, you’re going to create three stacks, each representing a tower. Start by adding the following import for the Stack class to TowerOfHanoiActivity.java:
import java.util.Stack;
Next, declare the stack variables below the other private variables:
private Stack mStack1, mStack2, mStack3;
You’ll initialize these variables in onCreateResources. Add the following lines of code after the end of section #3:
// 4 - Create the stacks
this.mStack1 = new Stack();
this.mStack2 = new Stack();
this.mStack3 = new Stack();
When the game starts, all three rings should be in the first stack. Put the following code in onCreateScene right before the return statement:
// 4 - Add all rings to stack one
this.mStack1.add(ring3);
this.mStack1.add(ring2);
this.mStack1.add(ring1);
// 5 - Initialize starting position for each ring
ring1.setmStack(mStack1);
ring2.setmStack(mStack1);
ring3.setmStack(mStack1);
ring1.setmTower(mTower1);
ring2.setmTower(mTower1);
ring3.setmTower(mTower1);
// 6 - Add touch handlers
scene.registerTouchArea(ring1);
scene.registerTouchArea(ring2);
scene.registerTouchArea(ring3);
scene.setTouchAreaBindingOnActionDownEnabled(true);
In the above code, you do the following:
- Added the rings to the first stack.
- Set the stack variable of each ring as the first stack and the tower variable as the first tower.
- To handle touch and movement of the rings, you registered each ring as a touchable area.
- Enabled touch binding.
Now, you need to override the onAreaTouch method of the Sprite class. This is where you’ll add logic to move the rings. But that code in turn will require a method which checks whether a ring collided with a tower. You’ll write that code later, but you need to add an empty method place holder for collision detection as follows (you can add this to the end of the class):
private void checkForCollisionsWithTowers(Ring ring) {
}
You also need to add the following import in order for the ring movement code to be able to identify the relevant classes:
import org.andengine.input.touch.TouchEvent;
Now, replace the first three lines of section #3 in onCreateScene (where you defined the rings) with the following:
Ring ring1 = new Ring(1, 139, 174, this.mRing1, getVertexBufferObjectManager()) {
@Override
public boolean onAreaTouched(TouchEvent pSceneTouchEvent, float pTouchAreaLocalX, float pTouchAreaLocalY) {
if (((Ring) this.getmStack().peek()).getmWeight() != this.getmWeight())
return false;
this.setPosition(pSceneTouchEvent.getX() - this.getWidth() / 2,
pSceneTouchEvent.getY() - this.getHeight() / 2);
if (pSceneTouchEvent.getAction() == TouchEvent.ACTION_UP) {
checkForCollisionsWithTowers(this);
}
return true;
}
};
Ring ring2 = new Ring(2, 118, 212, this.mRing2, getVertexBufferObjectManager()) {
@Override
public boolean onAreaTouched(TouchEvent pSceneTouchEvent, float pTouchAreaLocalX, float pTouchAreaLocalY) {
if (((Ring) this.getmStack().peek()).getmWeight() != this.getmWeight())
return false;
this.setPosition(pSceneTouchEvent.getX() - this.getWidth() / 2,
pSceneTouchEvent.getY() - this.getHeight() / 2);
if (pSceneTouchEvent.getAction() == TouchEvent.ACTION_UP) {
checkForCollisionsWithTowers(this);
}
return true;
}
};
Ring ring3 = new Ring(3, 97, 255, this.mRing3, getVertexBufferObjectManager()) {
@Override
public boolean onAreaTouched(TouchEvent pSceneTouchEvent, float pTouchAreaLocalX, float pTouchAreaLocalY) {
if (((Ring) this.getmStack().peek()).getmWeight() != this.getmWeight())
return false;
this.setPosition(pSceneTouchEvent.getX() - this.getWidth() / 2,
pSceneTouchEvent.getY() - this.getHeight() / 2);
if (pSceneTouchEvent.getAction() == TouchEvent.ACTION_UP) {
checkForCollisionsWithTowers(this);
}
return true;
}
};
Notice that onAreaTouched returns a boolean value. When it returns true, the touch is consumed, otherwise it is passed down to other layers until someone consumes it. So the first thing you do in this method is check if the weight of the current ring is not equal to the weight of the first ring in the stack. If it is, that means this ring is the first element of the stack and so you can proceed to move it, otherwise you let the touch go since you can’t move this ring.
You also check in onAreaTouched if the type of touch is an ACTION_UP event, triggered when the finger is lifted. If it is, you call checkForCollisionsWithTowers whose primary purpose is to check if the ring has collided with (or rather, is touching) a tower. As you may recall, you added a placeholder for checkForCollisionsWithTowers already. Let’s fill the function in now.
Replace the placeholder method for checkForCollisionsWithTowers with the following:
private void checkForCollisionsWithTowers(Ring ring) {
Stack stack = null;
Sprite tower = null;
if (ring.collidesWith(mTower1) && (mStack1.size() == 0 ||
ring.getmWeight() < ((Ring) mStack1.peek()).getmWeight())) {
stack = mStack1;
tower = mTower1;
} else if (ring.collidesWith(mTower2) && (mStack2.size() == 0 ||
ring.getmWeight() < ((Ring) mStack2.peek()).getmWeight())) {
stack = mStack2;
tower = mTower2;
} else if (ring.collidesWith(mTower3) && (mStack3.size() == 0 ||
ring.getmWeight() < ((Ring) mStack3.peek()).getmWeight())) {
stack = mStack3;
tower = mTower3;
} else {
stack = ring.getmStack();
tower = ring.getmTower();
}
ring.getmStack().remove(ring);
if (stack != null && tower !=null && stack.size() == 0) {
ring.setPosition(tower.getX() + tower.getWidth()/2 -
ring.getWidth()/2, tower.getY() + tower.getHeight() -
ring.getHeight());
} else if (stack != null && tower !=null && stack.size() > 0) {
ring.setPosition(tower.getX() + tower.getWidth()/2 -
ring.getWidth()/2, ((Ring) stack.peek()).getY() -
ring.getHeight());
}
stack.add(ring);
ring.setmStack(stack);
ring.setmTower(tower);
}
The above code checks whether the given ring is touching a tower, if it is, whether it can be moved to that tower, and if yes, places the ring appropriately.
Build and run, and you should have a completely functional Tower of Hanoi game! There are only three rings, but that means you should be able to beat the game in no time. :P
Where to Go From Here?
Here is the complete source code of the project.
There are a number of things left to be done, but these are easy enough to accomplish. So I’m going to leave them as an exercise for you :] Possible additions include:
- Detecting when all the rings have been moved to the third tower and showing a Game Over pop-up.
- Counting and displaying the total number of moves.
- Calculating and displaying the minimum number of moves required. (Hint: with three rings, the puzzle can be solved in seven moves.)
- Allowing the user to increase the difficulty by adding more rings. Legend has it that there is a temple where the priests are working on a version of this puzzle with 64 rings! I don’t suggest you create a version of this game with that many rings, unless you want to spend 580 billion years solving it!
Try your hand at these improvements and let me know how you fare in the forums!
Also let me know if you’d like to see more tutorials about AndEngine – I could write more about AndEngine’s extensions and how you can use each of them in a game. Until then, happy coding :]
This is a blog post by iOS Tutorial Team member Ali Hafizji, an iOS and Android developer working at Tavisca Solutions.