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

In the last post, we have created a basic 3D demo application with Irrlicht, in which we put a stack of crates, and we topple them by shooting a cube or a sphere.

In this post, we will try to create an on-screen control so that you can move around with it, like using a hardware control. What we want to have is something like this, in the following screenshot:

What we have here is a control knob, sitting on a base. The knob is in the centre of the base. The on-screen control always stays on top of the game scene, and the position should stay still regardless of how you move the camera. However, users can press on the knob, and drag it left and right, and this, in turn, moves the camera left and right accordingly.

Obviously, you can implement movement direction along more than one axis too. And you can also have more than one on-screen control if you want, since it is a device with multi-touch screen. But that’s left to you as an exercise.

Placing an on-screen control is actually quite easy. All you have to do is to load a picture as texture, then draw it as 2D image on the screen, at the location you want to put the control. But since we want the on-screen control to be always on top, we have to draw the 2D image after the game scene (and all the scene objects) are drawn. If we draw the 2D image first, it will hidden by the game scene. There, in your loop, you would have something like this:

  1. driver->beginScene(true, true, SColor(0, 200, 200, 200));
  2. smgr->drawAll();
  3. guienv->drawAll();
  4. // Draw the on-screen control now
  5. onScreenControl->draw(driver);
  6. driver->endScene();

That’s the basic idea. Here, we have created an OnScreenControl class, which encloses two objects, one of VirtualControlBase class and the other,  of VirtualControlKnob class. The draw() method of the OnScreenControl class looks like this:

  1. void OnScreenControl::draw(IVideoDriver* driver)
  2. {
  3.     base->draw(driver);
  4.     knob->draw(driver);
  5. }

It just relegates the drawing works to its sub-objects, the control base and the control knob. Note that the knob has to be drawn after the base, otherwise, it will be hidden behind the base, instead of sitting on top of it. The draw() method of the base looks like:

  1. void VirtualControlBase::draw(IVideoDriver* driver)
  2. {
  3.     driver->draw2DImage(_texture,
  4.         position2d<s32>(pos_x, pos_y),
  5.         rect<s32>(0, 0, width, height),
  6.         0,
  7.         SColor(255,255,255,255),
  8.         true);
  9. }

As you see, it just draws a 2D image with the texture, at the location specified. That’s it.

After putting the on-screen control in place, we have to handle user touch events on the screen. If users press on the knob (i.e. pressing within the square boundary of the knob image), and move the finger around, we update the position of the knob according to the movement direction. Here, we want to make sure that users can not drag the knob out of the control base boundary (or too far out of the boundary anyway), to make it look and behave like a real control. As users move the knob around, you want to update your camera’s position accordingly. And when the knob is released, you want to reset its position back to the centre of the control base.

That’s basically the idea. You can grab the source code here. Ugly codes, I warn you.

The major problem of programming Irrlicht on Android is the separation of Java codes and the C/C++ codes. If you want to limit your program to only Android 2.3 or later, you can probably write the whole program in C/C++, using the native activity class. That way, you don’t have to move back and forth between Java and C++. But if you want to run your program on older versions of Android, your Activity must be written in Java, and the main game logic written in C/C++. You then have to catch user interaction events in your Java code, pass them through JNI to your C/C++ code. There will be loss of information as you move back and forth, not to mention that there will be quite a bit of code duplication. You can certainly create a full wrapper for the Irrlicht and Bullet libraries, but that will be taxing your mobile device heavily, and will certainly have a negative impact on performance. And creating a full wrapper for these two libraries would be a heck of a job.

The other problem is that, Irrlicht is an engine developed for the desktop, where keyboard and mouse are the main input devices. The Irrlicht port to Android mainly concerns with a display driver for Android, but the port has not really gone deep into this area of user interaction. Therefore, as you write your Irrlicht-based Android program, you would have to hack together user input handling model, event model, etc. In my demo, I haven’t even touched that, I have just kludged together some primitive event handling codes. In order to have our program fit in those multi-touch based devices, we would have to dig into the Irrlicht scene node animator and event handling mechanisms, and work it out from there. For example, we will have to define our own scene node animator which would be based on touch events instead of keyboard and mouse events, and add it to the scene node that we want to animate. This is something that we are going to look into in our future posts.

34 Comments

  1. Paul Verlaine says:

    Thanks for sharing. Using on-screen controls looks easy with this method. And it looks great too.

    And I agree with you, the Android port looks half-hearted. I’m having difficulties wrapping my head around the event handling mechanism too. Using mouse with Irrlicht feels so natural, as it is built in. But once you get away from the traditional keyboard and mouse, I feel like I’m totally at loss.

    I’m trying to translate touch events into keyboard and mouse events, and pass them into Irrlicht for processing. This is an attempt for a shortcut, but I’m not sure how it will work out yet.

  2. Matt Danton says:

    Thanks for an example on how to do on-screen control with Irrlicht.

    I’ll be following your future posts on the area. Waiting for your solution on the touch-based event handling :)

    Keep it up.

  3. xp says:

    @Paul: Let us know how your work with translating touch events into keyboard and mouse events go. I have a feeling that it is not a good idea, but I might be wrong.

  4. James says:

    Thankyou for this. You served up more win than charlie sheen with these. The only issues that i had were with the implementation and building of the cpp file. Perhaps making a number 1.5 that explains the layout of everything, because it took me about 4 hours to get my own project working.

    Once again thankyou for these tutorials

  5. xp says:

    James,

    Please give a small description of the problem you encountered for building the cpp codes. If you have installed all the necessary tools, you should be able to build by issuing the command ndk-build.

    But then again, if you refer to another post for describing how to install all the tools, that would be another issue :)

  6. Melanie says:

    Thank your for sharing. I just tested it on my phone, and it works quite nicely. Not as fast and smooth as on a PC, but it is very acceptable.

    This will serve as a base for me to work on my little game. It is much easier than coding OpenGL directly.

    Melanie

  7. Mark says:

    Thanks a lot for sharing ideas. I’m waiting for more of your posts on programming with Irrlicht and Bullet, especially on Android.

    Now that we have a real 3D game engine for Android, I hope to see more 3D games released.

  8. Tony Blake says:

    That is interesting. I’d like to know how would people play complex games, with complicated actions and moves, on a device that has no hardware button? It seems to me that virtual controls could never be as fast as hardware controls, be it button, mouse, or joystick.

    Unfortunately, everyone is emulating Apple, and most mobile devices do not have buttons now. I tried to write my own little games, and I find that really annoying.

    Thanks for putting the libraries together, and thanks for sharing. Looking forward to more posts on the subject.

  9. Manish says:

    I thought there will be a part 4, when will it be posted? :)

    I’m eager to know, lol.

    Thanks

    Manish

  10. xp says:

    @Tony,

    Virtual controls surely will not be as fast, but you get no choice, don’t you? As you said, most devices do not have buttons now.

    @Manish,

    Yes, there will be a part 4, but I’m currently busy on my work. Hope to have some times to post it soon.

    Thanks to all for the feedback.

  11. Jay Wong says:

    Thanks for the posts, looking forward to more posts on the subject.

    Jay Wong

  12. Jean-Paul Trenet says:

    Very interesting. I’m wondering how hard would it be to port existing Irrlicht-based games to the Android platform. There are already a lot of 3D games developed with Irrlicht, if we can port them easily to Android, that would be nice.

    Thanks

    Jean-Paul

  13. xp says:

    @Jean-Paul:

    I think a lot of Irrlicht programs could be ported without too much modification. The important places to work on would be the interaction logic of the players, i.e. how the players will interact with the games, what buttons to push, how to control movements, etc.

    The interaction of Irrlicht engine is based on keyboard and mouse, which are not available on mobile devices. You would have to come up with a new interaction scheme. That would solve most of the problems for porting.

    The other important thing is that, you have to reconsider some of the game logic, especially regarding game object interaction. On desktop or laptop computers, you can easily get over 1000 FPS, you can have a lot of 3D objects interaction, and the game still run smoothly. On mobile devices, you would have to reduce the number of objects, otherwise, the game would not be playable.

    The third important thing is, you have to take care of screen size issues. There are a variety of screen sizes on mobile devices, if you want your games to play on most devices, you need to consider that issue.

  14. Gidools says:

    Thanks a lot for this good post.

    I got some good tips (making makefile, link file etc..)

    And I have a question on irrlicht engine initialization.

    How can I drop irrlicht device?

    Every time I run this game I can see same log.

    “CIrrDeviceAndroid::CIrrDeviceAndroid”

    And I think this means new allocation is occurred.

    There is no device drop code.

    Is there possibility memory leakage?

  15. jorgerosa says:

    Thankyou for the light :)

  16. xp says:

    @Gidools,

    Sorry, it’s a while, was really busy on my projects.

    Regarding your thought about memory leakage, I don’t think there is memory leak in the Irrlicht code, but one thing is going to cause you memory leak if you are not careful about what you do.

    Irrlicht’s model assume that your game is loaded, and will run continuously until you close it. At that time, you will release the resources that you have used in your code. That’s fine.

    But once you are on Android, that “run continuously” model does not always work. If you play your game just like you do on computer, and you close it after you’re done playing, that’s not a problem.

    But if Android puts your game to “pause”, and then resume it, what you get is a messed up screen (I think there’s a problem in the ported library, it didn’t consider the normal use case on Android), and you’d have to re-initialize to get things work again. In this case, if you are not careful, you would end up with memory leak.

  17. craig says:

    Thanks for your sharing.
    but the source code tar.gz is broken,
    could you upload it again?

  18. new says:

    hi,

    if choose opengles2.0 , will print log

    E/libEGL called unimplemented opengl es api
    E/libEGL called unimplemented opengl es api
    E/libEGL called unimplemented opengl es api

    do you know some ideas? thanks.

  19. Andrew says:

    Thank you for the great tutorial, after playing around with the source I finally managed to build my own version of your demo. I’m looking forward to your 4th post when it eventually comes out.

    I noticed that the demo runs with a title bar and you can see the time at the top as well. Is there a way to make the engine run in full screen mode?

  20. Cord says:

    Hmm these demos aren’t working with textures. I get the same problem in my own irrlicht android build, running a logcat of this example shows the same problem…

    12-01 23:21:10.571: I/log(4697): Irrlicht Engine version 1.7.0-beta
    12-01 23:21:10.571: I/log(4697): Using renderer: OpenGL ES-CM 1.1
    12-01 23:21:10.571: I/log(4697): Qualcomm
    12-01 23:21:10.571: I/log(4697): GL_AMD_compressed_3DC_texture GL_AMD_compressed_ATC_texture GL_AMD_performance_monitor GL_APPLE_texture_2D_limited_npot GL_EXT_texture_filter_anisotropic GL_EXT_texture_format_BGRA8888 GL_EXT_texture_type_2_10_10_10_REV GL_OES_blend_equation_separate GL_OES_blend_func_separate GL_OES_blend_subtract GL_OES_compressed_ETC1_RGB8_texture GL_OES_compressed_paletted_texture GL_OES_depth_texture GL_OES_draw_texture GL_OES_framebuffer_object GL_OES_matrix_palette GL_OES_packed_depth_stencil GL_OES_point_size_array GL_OES_point_sprite GL_OES_read_format GL_OES_rgb8_rgba8 GL_OES_stencil_wrap GL_OES_EGL_image GL_OES_texture_cube_map GL_OES_texture_env_crossbar GL_OES_texture_float GL_OES_texture_half_float GL_OES_texture_half_float_linear GL_OES_texture_npot GL_OES_texture_mirrored_repeat GL_QCOM_binning_control GL_QCOM_extended_get GL_QCOM_tiled_rendering
    12-01 23:21:10.581: I/log(4697): GL_INVALID_ENUM
    12-01 23:21:10.581: I/log(4697): Could not bind Texture
    12-01 23:21:10.651: I/log(4697): Loaded texture
    12-01 23:21:10.661: I/log(4697): Loaded texture
    12-01 23:21:10.671: I/log(4697): Loaded texture
    12-01 23:21:10.671: I/log(4697): Loaded texture

    The could not bind texture is the problem…any help?

  21. Mike says:

    Nice tutorial, but as has been said, building it is a terrifying nightmare. Why? Part 1 contains the sources needed to build the irrlicht and bullet libraries, but subsequent sources like part 2 and 3 contain only source code regarding the example game. It is obvious that those game projects will not compile as there are no headers (for example, irrlicht.h) shipped with it. So one must start building their own hybrid of the library and game projects and that’s when frustration kicks in.

  22. Cord says:

    @Mike – make a folder called ‘lib’ (NOT libs), next to libs folder. take a compiled libirrlichtbullet.so, be it your own or from Part 1, and stick it in the lib folder.

    Add this to your Android.mk just after the LOCAL_PATH := line:

    include $(CLEAR_VARS)
    LOCAL_MODULE := irrlichtbullet
    LOCAL_SRC_FILES := $(NDK_APP_PROJECT_PATH)/../lib/libirrlichtbullet.so
    include $(PREBUILT_SHARED_LIBRARY)

    Now add the module to the Application.mk file so it can be found from Java side:

    STLPORT_FORCE_REBUILD := true # NOTE: only need to compile once with this as true for every clean/rebuild
    APP_MODULES := main_module irrlichtbullet

    As for Eclipse finding the include paths to code in it, go to Project->Properties->C/C++ General and in the Includes tab add:
    Java JDK include path
    Java JDK include path + /win32 (I had to add win32 directory for it to find “minw.h” or somethin)
    Part 1′s JNI/Irrlicht/includes
    Part 1′s JNI/IrrBullet
    Part 1′s JNI/Bullet

    Then right click your Project in a PROJECT explorer (NOT package explorer) and go to Index->Rebuild.

    I’d be happy to help you get it working more if you need assistance, I rewrote all of the activity, renderer and native code from these tutorials as they were, as admitted, ugly. I wrote a barebones test.

    SADLY – I cannot get texturing to work, not even with these examples running on my phone… the texture is loaded but unable to bind texture, i believe glBindTexture is forcing a GL_INVALID_ENUM error meaning it cant find the GLuint texture id meaning some issue in either A) stl-c++ static_cast on android is broken? or B) the binding function itself is broken on OGL side :\

  23. xp says:

    Oh, I haven’t though it could be so much trouble for everyone. Ok, I made quite a few assumptions in the posts, assuming that you follow from the first to this one, and you download the code all the way, including the initial package that builds the Irrlicht and Bullet libraries.

    If you have all the codes and have them in the same Eclipse workspace, you should be able to build fine.

    One thing I didn’t specify clearly, but I had answered to a question in the comments, was the location of the asset files (including the texture). It’s supposed to be in /sdcard/renzhi/. Just copy all files in the assets folder to that location. I forgot to mention in the post, and somehow assumed that since it’s specified in the code, people might figure out anyway. Sorry for that.

    As for OpenGLES 2.0, I have no idea, as all my Android devices only have v1.x. So I have no device to work on.

    @Andrew, I haven’t had a chance to see how to make it full screen. Might do when I have a chance.

    @Cord, thanks for answering other people questions :)

    This project was not really meant to create a full game, it was intended to test how fast my Android device can handle 3D. I got a new device, I’d like to know, hence, I just messed around with some codes. I’m not a gamer, nor a game programmer, by looking at the code, you’ve probably figured that already.

    Been busy on other projects, so this has been put aside for a while now. Anyway, if you have some specific question, please let me know, I’ll try to answer as best as I can.

    Again, sorry for all the trouble :)

  24. zhouzhi says:

    hello, i have question about running irrlicht on android. My sample program can run on android, but textures cannot be set correctly. I can’t see any texture…

    There on some indications, like “GL_OUT_OF_MEMORY”, “Could not glTexImage2D()”, “called unimplemented OpenGL ES API”…

    why?? and what should i do? …. help me…

  25. Lysenko says:

    @Cord:
    I think that bug is in COGLES1MaterialRenderer_SOLID::OnSetMaterial:

    // thanks to Murphy, the following line removed some
    // bugs with several OGLES1 implementations.
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    After removing glTexEnvf, I can see small part of texture:)

    I am on Samsung Ace, Android 2.2, maybe this bug is device specific?

  26. Mark Gilmour says:

    hi there, ive been looking for a way to do 3d physics and graphics and didnt know how to start so thanks for the tutorials , it took me a while to work out how to build the project but got there after much coffee.

    Now to go off and learn irrlicht and bullet ;)

    Mark

  27. Roger Agusti says:

    Hi, as other people here it was hell to build the project but finally i did it, never worked with eclipse or android. I’m having trouble now trying to create new functions on the irrbullet code (to create a compound shape interface class like IBoxShape or ISphereShape) but it didn’t work, so I made a very simple test and gave me a strange result: when I declared a function at bulletworld.h like this one:

    int getIntNumber() { return 2; }

    And then i call it from bullet.cpp everything is fine, but when i declare the function at bulletworld.cpp it gives me an undefined reference error. So the code I have at bulletworld.h is:

    int getIntNumber();

    and at bulletworld.cpp:

    int irrBulletWorld::getIntNumber()
    {
    return 2;
    }

    And when I try to call it from bullet.cpp and build the project the compiler returns an undefined reference error… I guess this has something to do with the android.mk file or something like that, but i don’t really know. I created other new files with new classes in the project and I never had this kind of error.

    Any help will be really apreciated.

  28. Roger Agusti says:

    I am almost sure that the error comes from the static library libirrlichtbullet.so that I copy pasted from the source code on the tar.gz in the lib folder as Cord said, I will try to recompile the library with the new code and I will tell you if it was the correct solution.

  29. Roger Agusti says:

    That was exactly what was happening.

    Now I need to compile libirrlichtbullet.so in a linux machine (because of the argument too long error on cygwin and compile my other project which uses libirrlichtbullet in a windows machine… I think I love developing on android xD

  30. Mary says:

    Thanks for your sharing.
    But the project I downloaded had broken.It didn’t throw any excaptions,but shutdown.I wanted to know how to resolve it.Thank you.

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

  32. Reply says:

    Anyone figure out how to get “touch” and “accelleration/device rotation” data? This is a great start, but I need user input. Thanks XP for parts 1 through 3! Really looking forward to part 4!

  33. Did says:

    Hi,

    Very nice and helpful work. I succeeded in compiling and testing some apps on my (old) Xperia X10 on GL ES 2.0 but got some strange effects.
    1 – Background color of the screen is not as I expected (set to (128,128,128,0) and got a dirty green/blue… Seems the coding is AGBR instead of RGBA.
    2 – my model (used sydney MD2 model and texture) is not textured. Completely black. I got no error on texture loading.

    Any ideas.

    My contribution : to avoid “Call to unimplemented method” issues, I had to force to GL ES 2.0 by setting a new EGLContextFactory to my GLView on Java Side (see in Hello-gl2 sample on NDK).

    Did

  34. HaroldBawls says:

    I found out the texturing wont work with the stock sydney .bmp. its not measured in multiples of 2, i.e. 64×64,128×128. Resize the texture and it works… but not in bmp format i used png just fine.

Leave a Reply

*


Switch to our mobile site