Wednesday, December 26, 2012

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

Monday, December 24, 2012

Getting started with AndEngine


AndEngine 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
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
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

Friday, December 21, 2012

Train Spotting android app - Nuts & 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
android:id="@android:id/list"
android:layout_width="wrap_content"
android:layout_height="match_parent" >
favorites.xml
?xml version="1.0" encoding="utf-8"?>
"http://schemas.android.com/apk/res/android"
>
"@drawable/star"
android:state_selected="true" />
"@drawable/star_1"
 />
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
"1.0"
 encoding="utf-8"?>


"http://schemas.android.com/apk/res/android"
>
"@id/add"
android:icon="@drawable/add"
android:title="@string/add" />
"@id/delete"
android:icon="@drawable/delete"
android:title="@string/delete" />
"@id/deleteAll"
android:title="@string/deleteAll"
android:icon="@drawable/deleteall"/>
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 r = new ArrayList();
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=" + 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 r = new ArrayList();
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
//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(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
//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();

A sample output is shown below

This post gives all the finer details of this interesting app. Do install it and give it a try.
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!