Programming 3D games on Android with Irrlicht and Bullet (Part 2)

In the last post, we have built the Bullet Physics, Irrlicht and irrBullet libraries together to create a shared library for the Android platform. In this post, we are going to create a small demo 3D game for Android, using the libraries that we have built earlier.

This demo is not really anything new, I am going to just convert an Irrlicht example to run on Android. In this simple game, we are going to stack up a bunch of crates, and then we will shoot a sphere or a cube, from a distance, to topple the crates. The Irrlicht engine will handle all the 3D graphics, and the Bullet Physics library will take care of rigid body collision detection and all realistic physical kinetics. For example, when we shoot a sphere from the distance, how the sphere follows a curve line when flying over the air, how far it will fly, where it is going to fall on to the ground, how it reacts when it hits the ground, how it reacts when it hits the crates, and how the crates will react when being hit, etc, all these will be taken care of by Bullet Physics, and Irrlicht will render the game world accordingly.

Since it is easier to create Android project in Eclipse, we are going to work with Eclipse here. You will need to following tools to work with:

  1. Android SDK
  2. Android NDK
  3. Eclipse IDE
  4. Eclipse plugin for Android development.

I’m assuming you have all these tools installed and configured correctly. And I’m assuming you have basic knowledge on Android programming too, so I won’t get into the basic details here.

Let’s create a project called ca.renzhi.bullet, with an Activity called BulletActivity. The onCreate() method will look something like this:

  1. /** Called when the activity is first created. */
  2. @Override
  3. public void onCreate(Bundle savedInstanceState) {
  4.     super.onCreate(savedInstanceState);
  5.     // Lock screen to landscape mode.
  6.     this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
  7.  
  8.     mGLView = new GLSurfaceView(getApplication());
  9.     renderer = new BulletRenderer(this);
  10.     mGLView.setRenderer(renderer);
  11.  
  12.     DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
  13.     width = displayMetrics.widthPixels;
  14.     height = displayMetrics.heightPixels;
  15.  
  16.     setContentView(mGLView);
  17. }

This just tells Android that we want an OpenGL surface view. We will create a Renderer class for this, something very simple like the following:

  1. public class BulletRenderer implements Renderer
  2. {
  3.     BulletActivity activity;
  4.  
  5.     public BulletRenderer(BulletActivity activity)
  6.     {
  7.         this.activity = activity;
  8.     }
  9.  
  10.     public void onDrawFrame(GL10 arg0)
  11.     {
  12.         activity.drawIteration();
  13.     }
  14.  
  15.     public void onSurfaceChanged(GL10 gl, int width, int height)
  16.     {
  17.         activity.nativeResize(width, height);
  18.     }
  19.  
  20.     public void onSurfaceCreated(GL10 gl, EGLConfig config)
  21.     {
  22.         activity.nativeInitGL(activity.width, activity.height);
  23.     }
  24. }

The renderer class’s method will be invoked every time a frame needs to be rendered. There’s nothing special here. When the methods are invoked, we just invoke the native methods in the activity class, which will then call the C native functions through JNI. Since Irrlicht and Bullet are C++ libraries, we will have to write the main part of the game in C/C++. We keep very little logic in Java code.

When the surface is first created, the onSurfaceCreated() method is invoked, and here, we just call nativeInitGL(), which will initialize our game world in Irrlicht. This will initialize the device, the scene manager, create a physical world to manage the rigid bodies and their collision, create a ground floor, and put a stack of crates in the middle point. Then, we create a first-person-shooter (FPS) camera to look at the stack of crates. The player will look at this game world through the FPS camera.

I’m not going to describe the codes line by line, since you can download the codes to play with it. But when you create the Irrlicht device with the following line of code:

  1. device = createDevice( video::EDT_OGLES1, dimension2d(gWindowWidth, gWindowHeight), 16, false, false, false, 0);

Make sure you select the correct version of OpenGL ES library on your Android device. I have version 1.x on mine. But if you have version 2.x, change to video::EDT_OGLES2 instead.

After the initialization, we would have a scene that looks like this:

When a frame is changed and needs to render, the onDrawFrame() method of the renderer is invoked. And here, we just call the nativeDrawIteration() function and will handle the game logic in C/C++ codes. The code looks like this:

  1.    void Java_ca_renzhi_bullet_BulletActivity_nativeDrawIteration(
  2.         JNIEnv* env,
  3.         jobject  thiz,
  4.         jint direction,
  5.         jfloat markX, jfloat markY)
  6.     {
  7.         deltaTime = device->getTimer()->getTime() – timeStamp;
  8.         timeStamp = device->getTimer()->getTime();
  9.  
  10.         device->run();
  11.  
  12.         // Step the simulation
  13.         world->stepSimulation(deltaTime * 0.001f, 120);
  14.  
  15.         if ((direction != -1) || (markX != -1) || (markY != -1))
  16.             handleUserInput(direction, markX, markY);
  17.  
  18.         driver->beginScene(true, true, SColor(0, 200, 200, 200));
  19.         smgr->drawAll();
  20.         guienv->drawAll();
  21.         driver->endScene();
  22.     }

As you can see, this is very standard Irrlicht game loop, the only thing added here is a function to handle user input.

User input includes moving left and right, forward and backward, shooting sphere and cube. Irrlicht engine depends on keyboard and mouse for user interaction, which are not available on Android devices. So, we will create a very basic kludge to allow users to move around and shoot. We will use touch and tap to handle user input. Users will move their finger left and right, on the left part of the screen, to move left and right in the game world. Users will move their finger up and down, on the right part of screen, to move forward and backward in the game world. And tap on the screen to shoot. Therefore, the movement direction is translated into a parameter, called direction, and passed to the native code to be handled. We also grab the X and Y coordinates of the shooting mark, and pass them as parameters to native codes as well.

That’s it. You can now build it, package into an apk, install it on your Android device, and play with it. When you shoot on the stack of crates, you would have a scene that looks like this:

The performance on my Samsung Vibrant is ok, I get about 56 or 57 FPS, which is quite smooth. But if there are too many objects to animate, especially after we have shot many spheres and cubes, we will have a screen that hangs and jumps a bit, or sometimes, it stops to react to user input for a fraction of second. In a real game, we might want to remove objects that have done their work, so that the number of objects to animate is significantly reduced to maintain an acceptable performance.

The other important thing that we want to improve is user interaction and control. The Irrlicht engine is developed for desktop computers, it relies mainly on keyboard and mouse for user interaction. These are not available on mobile devices. The current demo attempted to use touch and tap on screen as user control, but it does not work very well. In a next post, we will try to create virtual controls on screen (e.g. buttons, dials, etc), and we might want to take advantage of the sensor as well, which is a standard feature on mobile devices now.

You can download the source codes of the demo here.

15 Comments

  1. Paul Verlaine says:

    Again, thanks for the demo code on how to use the libraries. I was trying to use triangle selector in Irrlicht, but the performance is so bad it barely moves. I got about 1 fps with Irrlicht triangle selector. With Bullet, I get about 55 fps.

  2. Paul Verlaine says:

    Can’t wait to learn from you how to do on screen controls :)

    Thanks

  3. Rex says:

    Thanks, it works quite smoothly on my HTC Evo. I’ll use this shared library to do some little programming too, it looks like fun.

  4. Brian O'Sullivan says:

    I run the program, but it does not have texture. The ground is just a flat white space. What did it go wrong?

    Thanks

  5. xp says:

    Oh, sorry I forgot to mention as I thought this could be found out from the code. You need to copy the texture files from the assets folder to the /sdcard/renzhi folder on your device.

  6. Brian O'Sullivan says:

    Thanks, I got it. It works fine now.

  7. Tim Turner says:

    This is interesting. But I’m new to Android programming, and don’t know much about this game engine. It would be nice if you could give more detailed, step-by-step instructions.

    Thanks you very much.

    Tim

  8. Bryan says:

    Thanks, it works great on my phone. I will use this as a base for my own programming.

  9. 32BitCoder says:

    Thanks for sharing.

    Wouldn’t it be better to have a wrapper in Java on the Irrlicht and Bullet library, so we can code the game logic in Java, instead of C++? I think it would be easier to manage too.

    Just thinking.

  10. xp says:

    @32BitCoder:

    That would be a lot of work to create wrapper for all classes in Irrlicht and Bullet. I haven’t seen anyone who is willing to undertake this yet :)

  11. xp says:

    @Tim:

    There are more detailed instruction on the Irrlicht site, regarding programming Irrlicht.There are quite a few examples too. I’m mainly interested in writing small games on my new phone, that’s why I didn’t go into any details of Irrlicht logic. I’ve made quite a bit of assumptions here, assuming that you are familiar with Java/C++/Android programming. The codes provided here are Java and C++ codes, therefore, I just gave some descriptions in places where it involved the specificity of Android programming.

    Sorry for the confusion.

  12. Mike says:

    That looks cool. Thanks a lot.

    Mike

  13. Cord says:

    Great articles, very nice entry point for Irrlicht on Android.

    NOTE: Don’t confuse the System.loadLibrary(“bullet”) with anything to do with irrlicht and bullet, it is just the name of the module in this particular project that uses libirrlichtbullet.so – to the creator: probably not the best name lol

  14. David.wan says:

    Nice post. I’m trying to run the demo on the emulator(I’ve tried AVD2.3 & AVD 3.2), but failed with only some black and while stripes, without any texture rendered. However, It runs perfect on my HP Streak pad(about 56 fps). After some research on this, I got that the android irrlicht ports supports only opengles 2.0 driver though providing both gles1 & gles2 render, while android emulator supports only opengles 1.0, that is why I got so many error like “calling unsupported opengles api”. There is also something to note, the opengles 2.0 is supported on most devices(with android version > 1.5), but you can only use them through JNI.

  15. xittx says:

    thanks for this great code. fortunately i,m able to run the code in emulator using eclips without texture but how to run this on my device?. one other thing, the change in code doesnt effect i.e it runs the same old code. even i removed all bullet.cpp code still runs the old code . help me plzzz

Leave a Reply

*


Switch to our mobile site