Box2D – porting to Android NDK

INTRODUCTION

Box2D is a wonderful physics engine for game developers(but not only). Its usability is proven by the fact that Angry Birds is basing on it(http://www.geek.com/articles/mobile/box2d-creator-asks-rovio-for-angry-birds-credit-at-gdc-2011032/). How to leverage from this easy-to-use and very robust engine in Android? There are already some java libraries for android which port Box2D like androidbox2d or jbox2d. But I think(maybe I’m wrong) that most of game developers want to write a Android Game in c/c++ using NDK. This article is about how to do it. A few weeks ago I decided to write a game(AirHockey) and to use Box2D(for learning reasons) and spent a some time to properly compile it to make it available from JNI code. It was hard to find any info about it in google, one book describe it but after following it step-by-step It didn’t work. After some research and attempts I finally forced it to work and decided to share complete solution with others.

LET’S GO

First you need to download Box2D from here: http://code.google.com/p/box2d/downloads/list. I have version 2.1.2 and don’t know if further steps is right for newer version(should be). Then unpack .zip file. You should get Box2D_vX.Y.Z folder. Inside this directory you have 2 dirs – Box2D and Contributions. Please copy the first folder(Box2D) to android-ndk-rX/sources. Now you should have a folder android-ndk-rX/sources/Box2D. Go inside it. You should see next bunch of directories: Box2D, Build, Building.txt, CMakeLists.txt, Documentation, freeglut, glui, HelloWorld, License.txt, Readme.txt, Testbed.
Now you need to add Android.mk file under above dir(Android-ndk-rX/sources/Box2D) with exactly this content:

LOCAL_PATH:= $(call my-dir)

LS_CPP:= $(subst $(1)/,,$(wildcard $(1)/$(2)/*.cpp))
BOX2D_CPP:= $(call LS_CPP, $(LOCAL_PATH), Box2D/Collision) \
            $(call LS_CPP, $(LOCAL_PATH), Box2D/Collision/Shapes) \
            $(call LS_CPP, $(LOCAL_PATH), Box2D/Common) \
            $(call LS_CPP, $(LOCAL_PATH), Box2D/Dynamics) \
            $(call LS_CPP, $(LOCAL_PATH), Box2D/Dynamics/Contacts) \
            $(call LS_CPP, $(LOCAL_PATH), Box2D/Dynamics/Joints) \
            $(call LS_CPP, $(LOCAL_PATH), Box2D/Rope)

include $(CLEAR_VARS)

LOCAL_MODULE:= box2d_static
LOCAL_SRC_FILES := Box2D \
Box2D/Collision/Shapes/b2CircleShape.cpp \
Box2D/Collision/Shapes/b2PolygonShape.cpp \
Box2D/Collision/b2BroadPhase.cpp \
Box2D/Collision/b2CollideCircle.cpp \
Box2D/Collision/b2CollidePolygon.cpp \
Box2D/Collision/b2Collision.cpp \
Box2D/Collision/b2Distance.cpp \
Box2D/Collision/b2DynamicTree.cpp \
Box2D/Collision/b2TimeOfImpact.cpp \
Box2D/Common/b2BlockAllocator.cpp \
Box2D/Common/b2Math.cpp \
Box2D/Common/b2Settings.cpp \
Box2D/Common/b2StackAllocator.cpp \
Box2D/Dynamics/Contacts/b2CircleContact.cpp \
Box2D/Dynamics/Contacts/b2Contact.cpp \
Box2D/Dynamics/Contacts/b2ContactSolver.cpp \
Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.cpp \
Box2D/Dynamics/Contacts/b2PolygonContact.cpp \
Box2D/Dynamics/Contacts/b2TOISolver.cpp \
Box2D/Dynamics/Joints/b2DistanceJoint.cpp \
Box2D/Dynamics/Joints/b2FrictionJoint.cpp \
Box2D/Dynamics/Joints/b2GearJoint.cpp \
Box2D/Dynamics/Joints/b2Joint.cpp \
Box2D/Dynamics/Joints/b2LineJoint.cpp \
Box2D/Dynamics/Joints/b2MouseJoint.cpp \
Box2D/Dynamics/Joints/b2PrismaticJoint.cpp \
Box2D/Dynamics/Joints/b2PulleyJoint.cpp \
Box2D/Dynamics/Joints/b2RevoluteJoint.cpp \
Box2D/Dynamics/Joints/b2WeldJoint.cpp \
Box2D/Dynamics/b2Body.cpp \
Box2D/Dynamics/b2ContactManager.cpp \
Box2D/Dynamics/b2Fixture.cpp \
Box2D/Dynamics/b2Island.cpp \
Box2D/Dynamics/b2World.cpp \
Box2D/Dynamics/b2WorldCallbacks.cpp
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
LOCAL_C_INCLUDES := $(LOCAL_EXPORT_C_INCLUDES)

include $(BUILD_STATIC_LIBRARY)

Ok, we have done everything by Box2D side. Now it will be attached to your project if you care of join this library. How?

Inside Android.mk of your project(in JNI directory) you need to 2 lines:
-LOCAL_STATIC_LIBRARIES := box2d_static – before “include $(BUILD_SHARED_LIBRARY)”
and
-$(call import-module,box2d) – after “”include $(BUILD_SHARED_LIBRARY)”).
For instance my Android.mk looks like:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := game_shared

LOCAL_MODULE_FILENAME := libgame

LOCAL_SRC_FILES := main.cpp \
                   ../../Classes/AppDelegate.cpp \
                   ../../Classes/GameLayer.cpp \
                   ../../Classes/Objects/Table.cpp \
                   ../../Classes/Objects/Player.cpp \
                   ../../Classes/Objects/Puck.cpp \
                   ../../Classes/Objects/GameObject.cpp
                   
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../Classes                   

LOCAL_WHOLE_STATIC_LIBRARIES := cocos2dx_static cocosdenshion_static cocos_extension_static
LOCAL_STATIC_LIBRARIES := box2d_static
            
include $(BUILD_SHARED_LIBRARY)

$(call import-module,CocosDenshion/android) \
$(call import-module,cocos2dx) \
$(call import-module,extensions) \
$(call import-module,box2d)

Now you can use Box2D in your project!:) Just include it: #include <Box2D/Box2D.h> in .h or .cpp files where you want to use Box2D objects;)

Here is API docs of Box2D: http://programanddesign.com/box2d/annotated.html

Enjoy your adventure with Box2D in Android NDK;)

Advertisements
This entry was posted in Android programming and tagged , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s