Dino Pong is my first android game from concept to completion. It is based on the android game engine AndEngine. This post gives the main hightights in the making of this fairly simple but interesting game.
Do take a look at my earlier post “Creating a simple android game using AndEngine” to understand how the basic game can be setup.
You can clone the entire project at Git Hub Dino Pong game
A video clip of Dino Pong in action can be seen here – Dino Pong clip
For the Dino Pong game I wanted the following
- 3 animated sprites that bounced off walls and moved with different velocities and paddle
- A DigitalOnScreenController that controls the paddle
- Collision detection between the paddle and the sprites and between the sprites themselves
- Points awarded for hitting a sprite with a paddle and points deducted for misses at the point of contact
- A game board showing hits, misses and the total score
So I created 3 animated sprites. Take a look at my earlier post on how to create an animated dino. So in the onCreateResources the 3 animated sprites and the paddle are created as below
Animated Sprites and paddle
// Create a ball
this.mBitmapTextureAtlas = new BitmapTextureAtlas(this.getTextureManager(), 64, 32, TextureOptions.BILINEAR);
this.mFaceTextureRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(this.mBitmapTextureAtlas, this, “face_circle_tiled.png”, 0, 0, 2, 1);
this.mBitmapTextureAtlas.load();
// Create a bront
this.mBitmapTextureAtlas = new BitmapTextureAtlas(this.getTextureManager(), 160, 64, TextureOptions.BILINEAR);
this.mBrontTextureRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(this.mBitmapTextureAtlas, this, “bront2_tiled.png”, 0, 0, 5, 1); //
this.mBitmapTextureAtlas.load();
// Create a paddle
this.mBitmapTextureAtlas = new BitmapTextureAtlas(this.getTOnCextureManager(), 90, 30, TextureOptions.BILINEAR);
this.mPaddleTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mBitmapTextureAtlas, this, “paddle1.png”, 0, 0);
this.mBitmapTextureAtlas.load();
// Create a Box face
this.mBitmapTextureAtlas = new BitmapTextureAtlas(this.getTextureManager(), 64, 64, TextureOptions.BILINEAR);
this.mBoxFaceTextureRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(this.mBitmapTextureAtlas, this, “face_box_tiled.png”, 0, 0, 2, 1); // 64×32
this.mBitmapTextureAtlas.load();
In the onCreateScene the animated sprites and the paddle are added to the scene and attached to it as below
// Add ball to scene
finalfloat Y = (CAMERA_HEIGHT – this.mFaceTextureRegion.getHeight()) / 2;
ball = new Ball(X, Y, this.mFaceTextureRegion, this.getVertexBufferObjectManager());
scene.attachChild(ball);
// Add box to scene
finalfloat X1 = (CAMERA_WIDTH – this.mBoxFaceTextureRegion.getWidth()) / 2;
finalfloat Y1 = 270;
box = new Box(X1, Y1, this.mBoxFaceTextureRegion, this.getVertexBufferObjectManager());
scene.attachChild(box);
// Add paddle
finalfloat centerX = (CAMERA_WIDTH – this.mPaddleTextureRegion.getWidth()) / 2;
float centerY = 320;
paddle = new Sprite(centerX, centerY, this.mPaddleTextureRegion, this.getVertexBufferObjectManager());
final PhysicsHandler physicsHandler = new PhysicsHandler(paddle);
paddle.registerUpdateHandler(physicsHandler);
scene.attachChild(paddle);
// Create a shaking brontosaurus
finalfloat cX = (CAMERA_WIDTH – this.mBrontTextureRegion.getWidth())/2;
finalfloat cY = 50;
bront = new Bront(cX, cY, this.mBrontTextureRegion, this.getVertexBufferObjectManager());
bront.registerUpdateHandler(physicsHandler);
scene.attachChild(bront);
The paddle is registered with a physicsHandler. All the animated instances all register with the physicsHandler to be able to detect collisions.
DigitalOnScreenController for controlling paddle : For this game I have used a DigitalOnScreenController as opposed to the analog version. The digital controller seems to have a smoother movement and diagonal movements are disabled. The code for this taken from AndEngine examples.
// Add a digital on screen control
this.mDigitalOnScreenControl = new DigitalOnScreenControl(50, CAMERA_HEIGHT – this.mOnScreenControlBaseTextureRegion.getHeight() + 20, this.mCamera, this.mOnScreenControlBaseTextureRegion, this.mOnScreenControlKnobTextureRegion, 0.1f, this.getVertexBufferObjectManager(), new IOnScreenControlListener() {
@Override
publicvoid onControlChange(final BaseOnScreenControl pBaseOnScreenControl, finalfloat pValueX, finalfloat pValueY) {
physicsHandler.setVelocity(pValueX * 100, 0);
}
});
this.mDigitalOnScreenControl.getControlBase().setBlendFunction(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
this.mDigitalOnScreenControl.getControlBase().setAlpha(0.5f);
this.mDigitalOnScreenControl.getControlBase().setScaleCenter(0, 128);
this.mDigitalOnScreenControl.getControlBase().setScale(1.25f);
this.mDigitalOnScreenControl.getControlKnob().setScale(1.25f);
this.mDigitalOnScreenControl.refreshControlKnobPosition();
scene.setChildScene(this.mDigitalOnScreenControl);
One of the thing I did was to disable vertical movements of the controlled object the paddle. Hence the physicsHandler sets the y value to ‘0’ as shown above
publicvoid onControlChange(final BaseOnScreenControl pBaseOnScreenControl, finalfloat pValueX, finalfloat pValueY) {
physicsHandler.setVelocity(pValueX * 100, 0);
}
Handling collisions :
As I mentioned above all the animated sprites (brontosaurus, face_circle & face_box) register with physics handler when the object is instantiated
privatestaticclass Bront extends AnimatedSprite {
privatefinal PhysicsHandler mPhysicsHandler;
floatx,y;
public Bront(finalfloat pX, finalfloat pY, final TiledTextureRegion pTextureRegion, final VertexBufferObjectManager pVertexBufferObjectManager) {
super(pX, pY, pTextureRegion, pVertexBufferObjectManager);
this.animate(100);
this.mPhysicsHandler = new PhysicsHandler(this);
this.registerUpdateHandler(this.mPhysicsHandler);
// Change the angle to the horizontal
this.mPhysicsHandler.setVelocity(BRONT_VELOCITY, BRONT_VELOCITY);
}
If the paddle misses the sprite then when the sprite collides with the bottom wall a point is deducted
if(this.mY < 0) {
this.mPhysicsHandler.setVelocityY(BRONT_VELOCITY);
//bText.setText(“”);
} elseif(this.mY + this.getHeight() + 80 > CAMERA_HEIGHT) {
x = this.getX();
y = this.getY();
bText.setPosition(x-10,y + 20);
bText.setText(“-1”);
misses = misses – 1;
score = score -1;
missesText.setText(“Misses: “+ misses);
scoreText.setText(“Score: “ + score);
Also the sprite is restarted from the top at the same ‘x’ coordinate
// At bottom. Restart from the top
this.setPosition(x, 0);
this.mPhysicsHandler.setVelocityY(-BRONT_VELOCITY);
The collision with the paddle, face_circle & face_box are checked here
if(paddle.collidesWith(this) || this.collidesWith(paddle)){
x = this.getX();
y = this.getY();
bText.setPosition(x+10,y+10);
bText.setText(“+1”);
hits = hits + 1;
score = score + 1;
float vx = this.mPhysicsHandler.getVelocityX();
float vy = this.mPhysicsHandler.getVelocityY();
this.mPhysicsHandler.setVelocity(-vx,-vy);
}
if(ball.collidesWith(this)){
float vx = this.mPhysicsHandler.getVelocityX();
float vy = this.mPhysicsHandler.getVelocityY();
this.mPhysicsHandler.setVelocity(-vx,-vy);
}
Similarly the collision checks are done for the other 2 sprites.
When the paddle successfuly hits a sprite the points are awarded at the point of contact
if(paddle.collidesWith(this) || this.collidesWith(paddle)){
x = this.getX();
y = this.getY();
bText.setPosition(x-10,y + 20);
bText.setText(“-1”);
The score is updated simulataneously for each hit or miss
hitsText.setText(“Hits: “+ hits);
scoreText.setText(“Score: “ + score);
hits = hits + 1;
score = score + 1;
Additional tweaks
-
The size of the DigitalOnScreenController was shrunk by half as it seemed oversized for my Android phone
-
A box is drawn within which the sprites can bounce off allowing space for the score at the bottom
final Line line1 = new Line(0, 0, 320, 0, 5, this.getVertexBufferObjectManager());
final Line line2 = new Line(320, 0, 320, 400, 5, this.getVertexBufferObjectManager());
final Line line3 = new Line(320, 400, 0, 400, 5, this.getVertexBufferObjectManager());
final Line line4 = new Line(0, 400, 0, 0, 5, this.getVertexBufferObjectManager());
// Add bounded rectangle to scene
scene.attachChild(line1);
scene.attachChild(line2);
scene.attachChild(line3);
scene.attachChild(line4);
-
The velocities of the 3 sprites are made slightly different
-
The x & y components of the velocity of the face_circle and face_box differ to enable a slightly different angle of motion.
A video clip of Dino Pong in action can be seen here – Dino Pong clip
You can clone the entire project at Git Hub Dino Pong game
or the complete code can be downloaded at DinoPong.zip
Issues: One of the issues I see is that when the paddle hits the middle of any sprite then the sprite appears to get locked and does not bounce off. Sometimes 2 sprites also get into this ‘deadly embrace’ before getting themselves released. It appears that successive collisions happen before the velocity and position can be changed hence resulting in this lock up. Any ideas on fixing this are welcome.
Do let me know your thoughts on this game.
3 thoughts on “The making of Dino Pong android game”