The making of Dino Pong android game

DSC00016Dino 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

  1. 3 animated sprites that bounced off walls and moved with different velocities and paddle
  2. A DigitalOnScreenController that controls the paddle
  3. Collision detection between the paddle and the sprites and between the sprites themselves
  4. Points awarded for hitting a sprite with a paddle and points deducted for misses at the point of contact
  5. 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_HEIGHTthis.mFaceTextureRegion.getHeight()) / 2;

ball = new Ball(X, Y, this.mFaceTextureRegion, this.getVertexBufferObjectManager());

scene.attachChild(ball);

// Add box to scene

finalfloat X1 = (CAMERA_WIDTHthis.mBoxFaceTextureRegion.getWidth()) / 2;

finalfloat Y1 = 270;

box = new Box(X1, Y1, this.mBoxFaceTextureRegion, this.getVertexBufferObjectManager());

scene.attachChild(box);

// Add paddle

finalfloat centerX = (CAMERA_WIDTHthis.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_WIDTHthis.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_HEIGHTthis.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

  1. The size of the DigitalOnScreenController was shrunk by half as it seemed oversized for my Android phone

  2. 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);

  1. The velocities of the 3 sprites are made slightly different

  2. 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.

Find me on Google+

Creating a simple android game using AndEngine

IMG_8928AndEngine is the really cool android game engine developed by Nicolas Gramlich. This post gives the steps needed to create a simple android game using AndEngine. Please look at my previous post “Getting started with AndEngine” for details of downloading and configuring the AndEngine in your Eclipse environment.

Fortunately AndEngine comes with a lot of examples which are a good starting point for creating of a game. After you installed AndEngine on your phone do give the examples a try and understand their behavior. You should then be able to suitably mix & match different components for the game you need.

In my case as a start I wanted to develop a simple Pong game with a paddle and an animated sprite for the ball. So I checked out the following examples

  1. Drawing a Sprite – SpriteExample.java
  2. Removing a Sprite – SpriteRemoveExample.java
  3. Drawing Animated Sprites – AnimatedSpriteExample.java
  4. A Moving ball example – MovingBallExample.java
  5. Analog On Screen Control – AnalogOnScreenControlExample.java
  6. Collision Detection – CollisionDetectionExample.java

Once I was fairly familiar with the above examples I started by creating an Android Project from Eclipse. I next copied the entire contents of AnalogOnScreenControlExample .java to the /src folder in a file named Pong.java. I changed the package details and also the class name from AnalogOnScreenControlExample to Pong.

Once this is done you have to do the following steps which is very important

  1. Click Project->Properties->Java Compiler and chose “Enable project specific setting” and select 1.6
  2. Click Project->Properties->Android and select Android 4.2
  3. Click Project-> Properties->Android  and under Library click the Add button and select AndEngine as a library.

Managing a paddle with the AnalogOnScreenController

Since I wanted to move a Pong paddle instead of the sprite in the above example I downloaded a jpg file for the paddle and copied it to

/assets/gfx

You must also copy the onscreen_control_base.png and onscreen_control_knob.png to /assets/gfx folder.

Build and run you program by connecting your phone through a USB cable. You should see the on screen control and the paddle. For my game I did not need the rotary control so I removed it and only kept the control for handling the velocity of my paddle.

Once you have your basic code working you can add the other parts. For my game I needed the following

  1. Animated Sprite
  2. A moving animated sprite
  3. Collision detection of the sprite with the paddle

Animated Sprite: To create an animated sprite you have to create a tiled picture with slight variations of the image. I downloaded a jpg of a brontosaurus and used GIMP to tile the picture with 5 tiles. For this in GIMP choose Filters->Map-> and choose %. Unlink the Width & Height and set the Width to 500% and height to 100%. This will create 5 vertical adjacent tiles. Then I applied transform->shear to each individual tile so that in effect it will look like an animated dino.

One this png is created you will have to copy it to assets/gfx folders and use in onCreateResources()

this.mBitmapTextureAtlas = new BitmapTextureAtlas(this.getTextureManager(), 64, 160, TextureOptions.BILINEAR);

this.mBrontTextureRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(this.mBitmapTextureAtlas, this, “bront1_tiled.png”, 0, 0, 1, 5); //

this.mBitmapTextureAtlas.load();

This typically is animated as follows

bront = new AnimatedSprite(pX, pY, this.mBrontTextureRegion, this.getVertexBufferObjectManager());

bront.animate(200);

Creating a moving animated Sprite : For this I picked up the code from the MovingBallExample.java as follows and replaced the ball sprite with my bront sprite

final Bront bront = new Bront(cX, cY, this.mBrontTextureRegion, this.getVertexBufferObjectManager());

bront.registerUpdateHandler(physicsHandler);

scene.attachChild(bront);

….

privatestaticclass Bront extends AnimatedSprite {

public Bront(finalfloat pX, finalfloat pY, final TiledTextureRegion pTextureRegion, final VertexBufferObjectManager pVertexBufferObjectManager) {

super(pX, pY, pTextureRegion, pVertexBufferObjectManager);

this.animate(100);

Create a moving sprite For this I picked up the appropriate code from the MovingBallExample.java and massaged it a bit to handle my animated bront sprite

privatestaticclass Bront extends AnimatedSprite {

privatefinal PhysicsHandler mPhysicsHandler;

public Bront(finalfloat pX, finalfloat pY, final TiledTextureRegion pTextureRegion, final VertexBufferObjectManager pVertexBufferObjectManager) {

….

this.mPhysicsHandler = new PhysicsHandler(this);

this.registerUpdateHandler(this.mPhysicsHandler);

this.mPhysicsHandler.setVelocity(DEMO_VELOCITY, DEMO_VELOCITY);

}

@Override

protectedvoid onManagedUpdate(finalfloat pSecondsElapsed) {

if(this.mX < 0) {

this.mPhysicsHandler.setVelocityX(DEMO_VELOCITY);

} elseif(this.mX + this.getWidth() > CAMERA_WIDTH) {

this.mPhysicsHandler.setVelocityX(-DEMO_VELOCITY);

}

if(this.mY < 0) {

this.mPhysicsHandler.setVelocityY(DEMO_VELOCITY);

} elseif(this.mY + this.getHeight() > CAMERA_HEIGHT) {

this.mPhysicsHandler.setVelocityY(-DEMO_VELOCITY);

}

Handling collisions: To handle the collisions the code in CollisionDetectionExample.java comes handy. So the paddle which is controlled by the onScreenAnalogControl will detect collisions with the animated sprite as below

and reverses the velocity component on collision detection

@Override

protectedvoid onManagedUpdate(finalfloat pSecondsElapsed) {

….

if(paddle.collidesWith(this)){

float vx = this.mPhysicsHandler.getVelocityX();

float vy = this.mPhysicsHandler.getVelocityY();

this.mPhysicsHandler.setVelocity(-vx,-vy);

}

super.onManagedUpdate(pSecondsElapsed);

So thats about all. We have a basic pong game ready! The game definitely needs more enhancements which I propose to do in the coming days. Watch this space!

Checkout the video clip of the  Pong game in action.

You can download the code from Pong.zip


Find me on Google+

Getting started with AndEngine

And Engine is the Open Source Android 2D OpenGL Game Engine created by Nicolas Gramlich. This post gives the steps for getting started with this cool game engine if you are keen on developing killer games for the world.

If you are already developing in Android then you probably have Eclipse. The entire source code for AndEngine has been moved to the Github. So the first thing you need to do is to get the Eclipse Git plugin. To do this open Eclipse and select Help-> Install New Software and type in http://download.eclipse.org/egit/updates in the Work with text field and hit enter. You should see the following

egit

Since I was on Linux I chose only EGit. If you are on Windows you will also have to probably install the Win32 plugin. Once this installed close Eclipse and open it again. Now you will have to clone all the AndEngine’s code from Github. The site is AndEngine Site.

Now all the AndEngine source has to be cloned along with the set o AndEngine Examples from this site.

To do this select File->Import->Git->Projects From Git and click Next.

Select URI from the next screen and select Next.

In the Source Git Repository screen enter the URI for each of the AndEngine files and extensions as shown below

ae-2

Click Next. Choose all the default settings for all the next few screens. This will create a copy of the contents of the folders for each of the AndEngine code. Repeat the step for the AndEngine and all of its extensions

The list is as below

  1. AndEngine
  2. AndEngineAugmentedRealityExtension
  3. AndEngineLiveWallPaperExtension
  4. AndEngineMODPlayerExtension
  5. AndEngineMultiplayerExtension
  6. AndEnginePhysicsBox2DExtension
  7. AndEngineRobotiumExtension
  8. AndEngineScriptingExtension
  9. AndEngineScriptingExtensionGenerator
  10. AndEngineSVGTextureRegionExtension
  11. AndEngineTexturePackerExtension
  12. AndEngineTMXTiledMapExtension

Once you have cloned all of the above you will need to build each of them individually. Make sure you perform the following

  1. Select Project->Properties->Java Compiler. Check the ‘Enable project specific settings’ and choose compiler compliance level as 1.6
  2. Select Project->Properties->Android and choose Android 4.2 API level 17
  3. Select Project->Properties->Android, click Add button under Library and add AndEngine and other libaries AndEnginePhysicsBox2DExtension etc.

And then build the project. It should build cleanly. I did get some errors as mentioned below. A lot of time I clicked ‘Fix project’ or ‘organize imports’ and the issues went away. Anyway here are the main issues I faced

In AndEngineRobotiumExtension for the AndEngineSolo.java I had to fix the imports. The imports were erroneously showing up as org.anddev….. I had to replace it with the following

Replace

import org.anddev.andengine.engine.Engine;

import org.anddev.andengine.engine.camera.Camera;

import org.anddev.andengine.entity.IEntity;

import org.anddev.andengine.entity.IEntity.IEntityMatcher;

import org.anddev.andengine.input.touch.TouchEvent;

import org.anddev.andengine.input.touch.controller.ITouchController;

import org.anddev.andengine.ui.activity.BaseGameActivity;

import org.anddev.andengine.util.constants.Constants;

with

import org.andengine.ui.activity.*;

import org.andengine.engine.Engine;

import org.andengine.engine.camera.Camera;

import org.andengine.entity.IEntity;

import org.andengine.entity.*;

import org.andengine.input.touch.TouchEvent;

import org.andengine.input.touch.controller.ITouchController;

import org.andengine.ui.activity.BaseGameActivity;

import org.andengine.util.Constants;

After this clone AndEngineExamples and build as before. You will run into the following errors once you have fixed the imports. (If you are looking at this post a couple of months afterwards it is likely that these issues have been fixed and you do not need to worry about them)

Next there were couple of errors in the

TextBreakExample.java, line 106

BoundCameraExample.java, line 220 

SplitScreenExample.java, line 179

The fix for this is given in this link

http://www.andengine.org/forums/tutorials/andenine-examples-showing-error-t9883.html

I also had to fix an error where I had to replace IEntity.getChild() with IEntity.getChildByIndex() don’t recollect where it was

Finally I had to replace the following line with the line below. This is more of a hack

Replaced the line in TexturePackerExample.java

//final TexturePack spritesheetTexturePack = new TexturePackLoader(this.getTextureManager(), “gfx/spritesheets/”).loadFromAsset (this.getAssets().toString(), “texturepackerexample.xml”);

with this

final TexturePack spritesheetTexturePack = new TexturePackLoader(this.getAssets(),this.getTextureManager()).loadFromAsset (this.getAssets().toString(), “texturepackerexample.xml”);

At this point the build should be clean. To run the examples you will have to connect your android phone to the laptop using a USB cable. The AndEngine Examples do not work on the AVD.

I have to admit the AndEngine examples are really cool. Some clips are shown below

Filtering Collisions example

Using a Revolutejoint example

<a href=”https://plus.google.com/103077316191161424665/?rel=author”>Find me on Google+</a>

Train Spotting android app – Nuts and bolts

trainsplashTrainspotting Android app. This is my second android app from concept, design and finally to implementation. You can download this app from Google Play at Train Spotting.

In this post I discuss the details of the app threadbare. The app has all the usual goodies of android and uses the following features of Android

  • Tab Layout
  • List Layout with checkbox
  • Options Menu with add, delete and deleteAll options
  • Passing parameters between activities
  • Handling the checkbox
  • Using the assets folder
  • Alert dialog
  • Widgets like spinners, buttons, text fields etc

Actiity Flow

The picture below shows the flow between the different activities

ts-activity

Tab Layout

The app has 3 main tabs

  1. Favorites b) Locate Train c) Train At d) About.

Creating tabs is fairly straightforward

Create 3 tab xml files in the res/layout folder. The res/layout folder will also contain 3 xml files containing the icons that have to displayed when a tab is selected and when it not selected.

For the above 3 tabs the layout files are

  1. Favoritesa. Layout file – display.xml which is a list viewb. Icon file – favorites.xml
  2. Locatea. Layout file – locate_train.xml with spinners and buttonsb. Icon file – locate.xml3) About

a. Layout file – about.xml – Webview

b. Icon file – help.xml

For e.g.

display.xml has the following

<ListView xmlns:android=”http://schemas.android.com/apk/res/android&#8221;
android:id=”@android:id/list”
android:layout_width=”wrap_content”
android:layout_height=”match_parent” >

</ListView>

favorites.xml

?xml version=“1.0” encoding=“utf-8”?>

<selector xmlns:android=http://schemas.android.com/apk/res/android&#8221;>

<!– When selected, use grey –>

<item android:drawable=“@drawable/star”

android:state_selected=“true” />

<!– When not selected, use white–>

<item android:drawable=“@drawable/star_1” />

</selector>

To create the above tab layout the following needs to added to the MainActivity to create the 3 tabs

// Create 3 tabs. Favorites, Locate, About

TabHost tabHost = getTabHost();

// Favorite trains tab

TabSpec favspec = tabHost.newTabSpec(“Favorites”);

// setting Title and Icon for the Tab

favspec.setIndicator(“Favorites”, getResources().getDrawable(R.drawable.star));

Intent favoritesIntent = new Intent(this, displayTrains.class);

favspec.setContent(favoritesIntent);

// Locate Train tab

TabSpec locatespec = tabHost.newTabSpec(“Locate”);

locatespec.setIndicator(“Locate”, getResources().getDrawable(R.drawable.binoculars));

Intent locateIntent = new Intent(this, locateTrain.class);

locatespec.setContent(locateIntent);

// About Tab

TabSpec aboutspec = tabHost.newTabSpec(“About”);

aboutspec.setIndicator(“About”, getResources().getDrawable(R.drawable.help));

Intent aboutIntent = new Intent(this, about.class);

aboutspec.setContent(aboutIntent);

// Add TabSpec to TabHost

tabHost.addTab(favspec);

tabHost.addTab(locatespec);

tabHost.addTab(aboutspec);

 Screenshot with the tabsts_screen1

The app starts at the Main Activity and then immediately switches to the Favorites tab. This tab displays the current list of trains that the user has stored in the SQLiteDatabase.

Options Menu

The Favorites tab includes an Option Menu when the Options button on the device is pressed.

There are 3 options presented to the user

  1. Add b) Delete c) deleteAll

To create an Options Menu add the options to the res/menu folder as options_menu.xml

The contents of res/menu/options_menu.xml is as follows

<?xml version=“1.0” encoding=“utf-8”?>

<menu xmlns:android=http://schemas.android.com/apk/res/android&#8221;>

<item android:id=“@id/add”

android:icon=“@drawable/add”

android:title=“@string/add” />

<item android:id=“@id/delete”

android:icon=“@drawable/delete”

android:title=“@string/delete” />

<item android:id=“@id/deleteAll”

android:title=“@string/deleteAll”

android:icon=“@drawable/deleteall”/>

</menu>

This can be inflated in the Activity (displayTrains.java) as follows

publicboolean onCreateOptionsMenu(Menu menu) {

MenuInflater inflater = getMenuInflater();

inflater.inflate(R.menu.options_menu, menu);

returntrue;

}

When a user selects an option the on the OptionItemSelectedMenu is invoked. There are currently 3 actions that can be selected from the OptionsMenu

a) Add b) Delete c) DeleteAll

Add option : When this option is selected the addTrain activity is started to take user input for the train no and train name

publicboolean onOptionsItemSelected(MenuItem item) {

Intent intent;

int count;

SqlOpenHelper helper = new SqlOpenHelper(this);

ArrayList<String> r = new ArrayList<String>();

final Context context = this;

switch (item.getItemId()) {

case R.id.add:

// Switch to the addTrain Activity

intent = new Intent(context, addTrain.class);

startActivity(intent);

returntrue;

The delete and the deleteAll option are also invoked in a similar fashion from the Option Menu

case R.id.delete:

…..

returntrue;

case R.id.deleteAll:

….

}

returntrue;

default:

returnsuper.onOptionsItemSelected(item);

}

}

 Screen shot with the options menu

ts_screen21

Passing parameters between activities

Sending parameters from one activity to another (locateTrain.java)

In the LocateTrain activity when the user selects the ‘train no’ and the ‘day” for which to locate the train the WebView has to be invoked with the selected values for the train no and day. This is done as as follows. In the calling activity locateTrain

Intent intent = new Intent(context, trainAt.class);

//Setup to pass parameters to new activity

// Pass the train & the day to the trainAt Activity

Bundle b = new Bundle();

b.putString(“train”, train_tokens[0]);

b.putString(“day”, dayValue);

intent.putExtras(b);

startActivity(intent);

The values are put in the bundle ‘b’ and the the parameters are passed with the call

intent.putExtras(b). The intent is finally started with the trainAt activity.

The trainAt activity receives the passed parameters are received as follows

Receiving parameters (trainAt.java)

// Receive the passed parameters

Bundle b = getIntent().getExtras();

int trainNo = Integer.parseInt(b.getString(“train”).toString());

String value = b.getString(“day”).toString();

// Invoke the web with passed parameters

String url = “http://www.spoturtrain.com/status.php?tno=&#8221; + trainNo + “&date=” +value;

WebView myWebView = (WebView) findViewById(R.id.webview);

myWebView.loadUrl(url);

Handling delete of selected items

To handle deletion of selected trains from the listview the delete() method is called. The code and the explanation is given below

SqlOpenHelper helper = new SqlOpenHelper(this);

ArrayList<String> r = new ArrayList<String>();

ListView lv = getListView();

SparseBooleanArray a = new SparseBooleanArray();

the lv.getCheckedItemPositions() returns a sparse array which has the checked items set to true.

// Create a sparse array of checked positions

a = lv.getCheckedItemPositions();

The list is iterated and the rows which are checked are determines as below

// Determine the positions which are checked

for(int pos=0;pos<lv.getCount(); pos++){

//Log.d(“val”,”pos:”+ pos + ” ” + a.get(pos));

if(a.get(pos)){

// If item is checked add it to the items ArrayList

items.add(pos);

}

}

//Convert the integer ArrayList to an Integer Array

Integer[] itemArray = new Integer[ items.size() ];

items.toArray( itemArray );

//Delete all selected items from SQLiteDatabase by passing in the itemArray

A train array is created with the selected rows and passed to deleteTrains()

helper.deleteTrains(itemArray);

// Clear the ArrayList

items.clear();

After deleting the selected rows the ListView is again re-populated with the new list.

//Re-populate the list

r = populateResults();

listAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_multiple_choice,r);

this.setListAdapter(listAdapter);

listAdapter.notifyDataSetChanged();

lv = getListView();

lv.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);

Handling Cancel

As before the sparse array of checked items is obtained and each of them are set to false to uncheck them as below

// Get the checked positions in a Sparse Array

a = lv.getCheckedItemPositions();

for(int i=0;i<lv.getCount(); i++){

//Log.d(“val”,”i:”+ i + ” ” + a.get(i));

// Uncheck the checked positions

if(a.get(i)){

lv.setItemChecked(i, false);

}

}

// Clear the sparse Array. Clear the ArrayList

a.clear();

items.clear();

Using the assets folder

The About tab displays a Help file which is stored as a html in the

/assets folder.

To display the Web page, webview is used

publicclass about extends Activity {

publicvoid onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.about);

// Add the trainspot.html in assets/

WebView webView = (WebView) findViewById(R.id.trainspot);

webView.loadUrl(“file:///android_asset/trainspot.html”);

}

}

Creating an alert dialog

An alert dialog is fairly straightforward

AlertDialog.Builder builder = new AlertDialog.Builder(context);

Set the title of the dialog and the message to be displayed as below

// Set title

builder.setTitle(“Confirm delete”);

a = lv.getCheckedItemPositions();

// Set the dialog message

builder.setMessage(“Do you want to delete these ” + a.size() + ” items?”);

Add either ‘Yes’/’No’ or ‘OK’/’Cancel’ buttons and handle the actions accordingly

// Add the Yes & No buttons

builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {

publicvoid onClick(DialogInterface dialog, int id) {

// User clicked Yes button

// Delete selected items

delete();

}

});

builder.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {

publicvoid onClick(DialogInterface dialog, int id) {

// User No the dialog

// Uncheck the checked items

uncheck();

dialog.cancel();

}

});

// Create the AlertDialog

AlertDialog dialog = builder.create();

// show it

dialog.show();

This post gives all the finer details of this interesting app. Do install it and give it a try.

A sample output is shown below

ts_screen41

You can clone the project from Github at Trainspotting or

The complete code of this app can be downloaded at trainspotting.zip

Happy train spotting!

You may also like
1. Unity (full) android app – With bells and whistles
2. The making of Dino Pong android game

Find me on Google+

Unity(full) android App: With bells and whistles

In this post I discuss a fairly complete Android App – Unity which is a simple unit converter. The android app has all the good stuff from Android including activities, intents, spinners, launch icons and a splash screen to boot as below. Download it from Google Play : Unity – Unit Converter . To know more about the app read on …

compasses

I have enhanced my earlier basic Unity app to start with a Splash Screen before moving onto an initial screen with buttons for various unit conversion like mass,length,volume etc

This is shown below

unity-1

When any of these buttons are clicked it goes to the appropriate conversion screen. This is done by starting the appropriate activity. An activity is invoked by the intent which starts the activity.

Hence the MainActivity.java has an intent and activity for each of the buttons mass,length,volume in the addListenerOnButton as follows

publicvoid addListenerOnButton() {

//Mass activity

massButton = (Button) findViewById(R.id.button1);

massButton.setTextAppearance(context,R.style.ButtonFontStyle);

massButton.setOnClickListener(new OnClickListener() {

publicvoid onClick(View arg0) {

Intent intent = new Intent(context, massActivity.class);

startActivity(intent);

}

});

//Length activity

lengthButton = (Button) findViewById(R.id.button2);

lengthButton.setTextAppearance(context,R.style.ButtonFontStyle);

lengthButton.setOnClickListener(new OnClickListener() {

publicvoid onClick(View arg0) {

Intent intent = new Intent(context, lengthActivity.class);

startActivity(intent);

}

});

When the “Mass button” is clicked it activates a new intent based on the massActivity.java class.

The massActivity.java file performs the following main functions

  1. Changes the layout to the one defined in mass.xml under res/layout.mass.xml
  2. Instantiates a massAdapter as an ArrayAdapter
  3. Passes the massAdapter to both the spinners in the View
  4. A convert method is invoked when the Convert button is clicked. This method does the actual calculation
  5. Finally a ‘Home’ button is used to go back to the MainActivity class

publicclass massActivity extends Activity {

String[] massUnits = {“gram”,“kilogram”,“ounce”,“pound”,“ton”};

//double massConversion[][] = new double[5][5];

doublemassConversion[][] = newdouble [][]{

{1.0,0.001,3.527e-2,2.205e-3,1.102e-6},

{1000.0,1.0,35.27,2.205,1.102e-3},

{28.35,28.38e-2,1,6.25e-2,3.125e-5},

{453.6,0.4536,16.0,1.0,.0005},

{9.072e-5,907.2,3.2e4,2000.0,1}

};

protectedvoid onCreate(Bundle savedInstanceState) {

ArrayAdapter<String> massAdapter = new ArrayAdapter<String> (this,

android.R.layout.simple_spinner_item,massUnits);

sp1 = (Spinner) findViewById(R.id.spinner1);

sp1.setAdapter(massAdapter);

sp1.setOnItemSelectedListener(new OnItemSelectedListener() {

publicvoid onItemSelected(AdapterView<?> argo0, View arg1,

int arg2, long arg3) {

intitem = sp1.getSelectedItemPosition();

}

publicvoid onNothingSelected(AdapterView<?> arg0) {

}

});

sp2 = (Spinner) findViewById(R.id.spinner2);

sp2.setAdapter(massAdapter);

sp2.setOnItemSelectedListener(new OnItemSelectedListener() {

publicvoid onItemSelected(AdapterView<?> argo0, View arg1,

int arg2, long arg3) {

intitem = sp2.getSelectedItemPosition();

/

}

});

}

publicvoid convert(View view) {

double inputValue = Double.parseDouble(text1.getText().toString());

int item1 = sp1.getSelectedItemPosition();

int item2 = sp2.getSelectedItemPosition();

double value = massConversion[item1][item2];

double convertedValue = inputValue * value;

txtConvertedValue.setText(String.valueOf(convertedValue));;

}

The Home button takes back to the Main screen

publicvoid home(View view) {

final Context context = this;

Intent intent = new Intent(context,

MainActivity.class);

startActivity(intent);

}

The mass.xml screen has 1 Textfield for input, a TextView for output, 2 spinners for handling the fromUnit & toUnit and a Convert & a Home button. The mass.xml is shown below

<TableLayout xmlns:android=http://schemas.android.com/apk/res/android&#8221;

android:layout_width=“fill_parent”

android:layout_height=“fill_parent” >

<TableRow

android:id=“@+id/tableRow1”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content” >

<TextView

android:id=“@+id/textView1”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:layout_column=“0”

android:layout_span=“4”

android:text=“@string/massConversion”

android:textAppearance=“?android:attr/textAppearanceMedium” />

</TableRow>

<TableRow

<TextView

android:id=“@+id/textView2”

/>

<EditText

android:id=“@+id/editText1”

android:inputType=“numberDecimal” />

</TableRow>

<TableRow

<TextView

android:id=“@+id/textView3”

android:text=“@string/convertedValue” >

<TextView

android:id=“@+id/txtConvertedValue”>

</TableRow>

<TableRow

android:id=“@+id/tableRow5”

<Spinner

android:id=“@+id/spinner1”>

</TableRow>

<TableRow

android:id=“@+id/tableRow6”

<Spinner

android:id=“@+id/spinner2”>

</TableRow>

<TableRow

android:id=“@+id/tableRow11>

<Button

android:onClick=“convert”

android:text=“@string/Convert” />

<Button

android:onClick=“home”

android:text=“@string/home” />

</TableRow>

</TableLayout>

unity-5

Note: Ensure that you add this new activity massActivity to AndroidManifest.xml

As shown

<application

<activity

android:name=”com.example.test.massActivity”

android:label=”@string/app_name” >

</activity>

</application>

</manifest>

Similar code can be replicated for the other buttons and other conversion units.

Once this is done your application is ready. It is now time to create a suitable “icon” for your android app. I found GIMP utility extremely useful in creating icons. GIMP cam be downloaded from http://www.gimp.org. This requires some learning ramp-up. So I took the easy route and downloaded ready made icon from OpenClipArt.org which has a huge collection of icons.

The specified dimensions for the icons based on the resolution of the android device is given in http://developer.android.com/guide/practices/ui_guidelines/icon_design_launcher.html

and should be

  • Low density screens (ldpi): 36x36px, 120dpi
  • Medium density screens (mdpi): 48x48px, 160dpi
  • High density screens (hdpi): 72x72px, 240dpi
  • Extra high density screens (xdpi): 96x96px, 320dpi

Copy all the icons to the directory below and rename the png files to ic_launcher.png

  • Low density icon : res/drawable-ldpi
  • Medium density icon : res/drawable-mdpi
  • High density icon : res/drawable-hdpi
  • Extra high density icon : res/drawable-xdpi

WhenyoubuildandruntheapponyouremulatoryoushouldseeyouriconinsteadofthestandardAndroidicon.

It is worth mentioning a problem that I faced initially and had me stumped. I would make some changes and get the error “R cannot be resolved to a variable”.

AftertryingtounsuccessfullycleanandrebuildtheprojectseveraltimesItriedtodiginmore.MysearchwithGoogleprovedfutilewithsomepostscomplainingthatEclipsewasclobberingfiles.TheissueusuallyhappenswhentheR.javafilecannotbegeneratedwhenyoubuildtheproject.Thisusuallyhappenswhenthereissomeissueinyour /resdirectory.Checkifthereareanyredmarksinyourlayout,strings.xmlorAndroidManifest.xmletcfile, fixthem, rebuild and theproblemshouldgoaway.

Finally I added an initial splash screen. For this I took the code from O’Reilly’s cook book “Splash screens in Android”. A splash *.jpg or *.png has to be added to the res/drawable folders

Remember to change the AndroidManifest.xml to have the app open up with the splash screen and then switch the MainActivity.java.

A snippet is shown below

<activity

android:name=“com.tvganesh.unity.SplashScreen”

android:noHistory=“true”

android:label=“@string/app_name” >

<intent-filter>

<action android:name=“android.intent.action.MAIN” />

<category android:name=“android.intent.category.LAUNCHER” />

</intent-filter>

</activity>

<activity

android:name=“com.tvganesh.unity.MainActivity”

android:label=“@string/app_name” >

</activity>

<activity

android:name=“com.tvganesh.unity.massActivity”

android:label=“@string/app_name” >

</activity>

….

With this app is also set to rock ‘n roll. I also managed to submit the app to Google Play. To publish in Google Play you need to do the following

  1. Create a signed app package. For this right click the package, select Android Tools->Export Signed Application Package and follow the prompts. Upload the *.apk file in Google Play
  2. You will also need 2 screenshots of the app & a 512×512 icon.

And you should be through.

The Unity project can be cloned from Git Hub at Unity project or

The entire Unity – Unit converter app can be downloaded at Unity-Unit Converter

Find me on Google+

Unity – My first android app

Unity – A simple unit converter is my first android app. The app in itself is no great piece of software wizardry but I managed to play around some of the basic android concepts. Currently in its current version there are just 4 main types of units – length, mass,temperature and volume each with just 2 unit types. I am planning to implement a full-fledged android version with all types of units and unit conversions shortly. Watch this space for more.

For this simple version I have a textfield to take user input of the value to be converted. I also have 2 spinners with the list of units. The first spinner (fromUnit) has its content loaded in runtime from an ArrayAdapter. The contents of the 2nd spinner is based on the selection of the 1st spinner. So if the 1st spinner chooses a length unit the 2nd spinner will also be loaded with the length units and so on. There is also a Calculate button with a “convert” method for onClick to convert from the fromUnit to the toUnit.

The resource/activity_main.xml

<RelativeLayout xmlns:android=http://schemas.android.com/apk/res/android&#8221;
xmlns:tools=http://schemas.android.com/tools&#8221;
android:layout_width=“match_parent”
android:layout_height=“match_parent”
tools:context=“.MainActivity” >
<Button
android:id=“@+id/button1”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”
android:layout_below=“@+id/spinner2”android:layout_centerHorizontal=“true”
android:layout_marginTop=“62dp”
android:onClick=“convert”
android:text=“Calculate” />
<EditText
android:id=“@+id/editText1”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”
android:layout_alignParentTop=“true”
android:layout_centerHorizontal=“true”
android:layout_marginTop=“24dp”
android:ems=“10”
android:inputType=“numberDecimal” >

<requestFocus />
</EditText>
<Spinner
android:id=“@+id/spinner1”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”
android:layout_alignParentLeft=“true”
android:layout_below=“@+id/editText1”
android:layout_marginTop=“24dp” />
<Spinner
android:id=“@+id/spinner2”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”
android:layout_alignParentLeft=“true”
android:layout_below=“@+id/spinner1”
android:layout_marginTop=“44dp” />
</RelativeLayout>
The fromUnit is based on the units array below
String[] units = {“kilogram”,“mile”,
“kilometer”,“pound”,“gallon”,“liter”,“centigrade”,“fahrenheit”,
};
In the onCreate() method I create an ArrayAdapter and set the spinner with this adapter as follows
final ArrayAdapter<String> adapter = new ArrayAdapter<String> (this,
android.R.layout.simple_spinner_item,units);
sp = (Spinner) findViewById(R.id.spinner1);
sp.setAdapter(adapter);
I also set the 2nd spinner (toUnit) based on the selected unit in spinner 1. Hence I conditionally set the 2nd spinner as follows
sp1 = (Spinner) findViewById(R.id.spinner2);
sp.setOnItemSelectedListener(new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> argo0, View arg1,
int arg2, long arg3) {
int item = sp.getSelectedItemPosition();
fromUnit = units[item];
if( (fromUnit.equals(“kilometer”)) || (fromUnit.equals(“mile”))) {
sp1.setAdapter(lengthAdapter);
unitType=1;
}
else if ((fromUnit.equals(“kilogram”)) || (fromUnit.equals(“pound”))){
sp1.setAdapter(massAdapter);
unitType=2;
}
else if ((fromUnit.equals(“centigrade”)) || (fromUnit.equals(“fahrenheit”))) {
sp1.setAdapter(tempAdapter);
unitType=3;
}
else if((fromUnit.equals(“liter”)) ||(fromUnit.equals(“gallon”))){
sp1.setAdapter(volumeAdapter);
unitType=4;
}
else {
sp1.setAdapter(adapter);
unitType =5;
}
Toast.makeText(getBaseContext(),“You have selected: “ +
fromUnit, Toast.LENGTH_SHORT).show();
}
public void onNothingSelected(AdapterView<?> arg0) {
}
});
sp1.setOnItemSelectedListener(new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> argo0, View arg1,
int arg2, long arg3) {
int item = sp1.getSelectedItemPosition();
if(unitType == 1) {
toUnit= lengthUnits[item];
}
else if(unitType == 2){
toUnit = massUnits[item];
}
else if(unitType == 3){
toUnit = tempUnits[item];
}
else if (unitType == 4) {
toUnit = volumeUnits[item];
}
else {
toUnit = units[item];
}
Toast.makeText(getBaseContext(),“SP2:You have
selected: “ +
toUnit, Toast.LENGTH_SHORT).show();
}
public void onNothingSelected(AdapterView<?> arg0) {
}
});
Finally based on the fromUnit and the toUnit the appropriate method is called in the onClick method of the Calculate button.
if((fromUnit.equals(“kilometer”)) && (toUnit.equals(“mile”))){
text.setText(String.valueOf(convertkilometer2mile(inputValue)));
}

else if((fromUnit.equals(“mile”)) && (toUnit.equals(“kilometer”))) {
text.setText(String.valueOf(convertmile2kilometer(inputValue)));
}
and so on…
While this is an elementary app I intend to develop a more thorough version shortly with some of the good features of android.
The complete code can be downloaded from the link Unity.zip

Also see
1. Train Spotting android app – Nuts & bolts
2. The making of Dino Pong android game

Find me on Google+