Android Development & Technology
  • 2D Physics on Android (using Box2D)

    Posted on March 4th, 2009 chris 4 comments

    This post is a brief tutorial on getting started with 2D physics on Android.

    2D physics can greatly enrich games by realistic behavior of objects such as polygons (boxes, rectangles, polys) and circles in a world setting. The engine calculates collisions, angles, forces and momentums based on user-defined settings such as gravity, density, friction, elasticity, etc.

    The Engine

    There are a couple of good open-source 2d physics engines, most notably Box2D and Chipmunk. For this project we’ll use Box2D due to it’s better performance (see next figure, detailled comparison and speed tests). The following figure is from benchmarks made on the xo laptop:
    graph

    Luckily there is a Java port of the Box2D libraries called JBox2D (released under the zlib license). JBox2D is using the processing library for displaying things, which we’re not gonna use on Android :D.

    JBox2D

    The library is bundled the 154kb file jbox2d-2.0.1-library-only.jar from their svn. This file includes the whole Box2D functionality and is very easy to implement in custom Java projects.

    Guides & Docs

    Importing the library

    Let’s import the jar file into our current project in Eclipse.

    1. Download jbox2d-2.0.1-library-only.jar and save it anywhere as jbox2d.jar
    2. In Eclipse
      1. Create a folder /lib/
      2. Right Click on /lib, select Import
      3. Select General / File System
      4. Choose the directory of jbox2d.jar
      5. Import the file jbox2d.jar
      6. Right click on the project and select “Properties”
      7. Click on “Java Build Path” and select the “Libraries” tab
      8. Click on “Add JARs…” and pick the file jbox2d.jar

    box2d_eclipse1That’s it; we can use Box2D by now and can access the library reference in Eclipse as seen in the figure to the right.

    Physical Hello World

    Let’s write a quick hello world app, that basically follows the Box2D User Manual, doing the following:

    • Initialize a new world
    • Add a ground box
    • Create some dynamic bodies (balls)
    • Simulate the world

    This code is not drawing anything on the screen yet. It only calculates the physical behaviour and prints a log message about the latest added element (position and angle).

    The following code is a class that handles the physics only. It can be implemented by any activity, and the update() function has to be called periodically.

    import org.jbox2d.collision.AABB;
    import org.jbox2d.collision.CircleDef;
    import org.jbox2d.collision.PolygonDef;
    import org.jbox2d.common.Vec2;
    import org.jbox2d.dynamics.Body;
    import org.jbox2d.dynamics.BodyDef;
    import org.jbox2d.dynamics.World;
    
    import android.util.Log;
    
    public class PhysicsWorld {
        public int targetFPS = 40;
        public int timeStep = (1000 / targetFPS);
        public int iterations = 5;
    
        private Body[] bodies;
        private int count = 0;
    
        private AABB worldAABB;
        private World world;
        private BodyDef groundBodyDef;
        private PolygonDef groundShapeDef;
    
        public void create() {
            // Step 1: Create Physics World Boundaries
            worldAABB = new AABB();
            worldAABB.lowerBound.set(new Vec2((float) -100.0, (float) -100.0));
            worldAABB.upperBound.set(new Vec2((float) 100.0, (float) 100.0));
    
            // Step 2: Create Physics World with Gravity
            Vec2 gravity = new Vec2((float) 0.0, (float) -10.0);
            boolean doSleep = true;
            world = new World(worldAABB, gravity, doSleep);
    
            // Step 3: Create Ground Box
            groundBodyDef = new BodyDef();
            groundBodyDef.position.set(new Vec2((float) 0.0, (float) -10.0));
            Body groundBody = world.createBody(groundBodyDef);
            groundShapeDef = new PolygonDef();
            groundShapeDef.setAsBox((float) 50.0, (float) 10.0);
            groundBody.createShape(groundShapeDef);
        }
    
        public void addBall() {
            // Create Dynamic Body
            BodyDef bodyDef = new BodyDef();
            bodyDef.position.set((float) 6.0+count, (float) 24.0);
            bodies[count] = world.createBody(bodyDef);
    
            // Create Shape with Properties
            CircleDef circle = new CircleDef();
            circle.radius = (float) 1.8;
            circle.density = (float) 1.0;
    
            // Assign shape to Body
            bodies[count].createShape(circle);
            bodies[count].setMassFromShapes();
    
            // Increase Counter
            count += 1;
        }
    
        public void update() {
            // Update Physics World
            world.step(timeStep, iterations);
    
            // Print info of latest body
            if (count > 0) {
                Vec2 position = bodies[count].getPosition();
                float angle = bodies[count].getAngle();
                Log.v("Physics Test", "Pos: (" + position.x + ", " + position.y + "), Angle: " + angle);
            }
        }
    }

    Using it in an Activity

    It implement the PhysicsWorld class in an Activity is as simple as the following code blueprint:

    import android.app.Activity;
    import android.os.Bundle;
    import android.os.Handler;
    
    public class Physics extends Activity {
        PhysicsWorld mWorld;
        private Handler mHandler;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            mWorld = new PhysicsWorld();
            mWorld.create()
    
            // Add 50 Balls
            for (int i=0; i<50; i++) {
                mWorld.addBall();
            }
    
            // Start Regular Update
            mHandler = new Handler();
            mHandler.post(update));
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            mHandler.removeCallbacks(update);
        }
    
        private Runnable update = new Runnable() {
            public void run() {
                mWorld.update();
                mHandler.postDelayed(update, (long) (mWorld.timeStep*1000));
            }
        };
    }

    That’s it; congratulations, you’re now ready to use Box2D in every way you’d like to!

    Drawing the Elements on the screen

    Drawing the elements is a delicate task, as code performance matters a lot and it can speed things up or slow them down greatly! The android docs on 2D Graphics suggest the android.graphics.drawable and android.view.animation packages are where you’ll find the common classes used for drawing and animating in two-dimensions.

    I’ll write about this with example code for drawing the elements another time, although it should be not very hard to get started with drawables, as there are many examples with source code.

    It is important to keep two things in mind:

    • Axis orientations: the coordinate (0, 0) with the G1 is typically the upper left corner of the screen, while (0, 0) in Box2D is the bottom left corner of the screen.
    • The other thing are dimensions: Box2D works fine with dimensions from 0.1 to 10 times the typical earth dimensions such as density, friction, gravity, …. Internally the engine is using meters and we will need to convert them to pixels. If we say, 1 meter shall be 10 pixels, that function could look like this:
    public Vec2 toScreen(Vec2 pos) {
        pos.x = pos.x*10;
        pos.y = 480 - (pos.y*10);
        return pos;
    }

    That’s it basically. If you’re doing cool stuff with it, we’d love to hear about it! :D.

    I’d be delighted to hear suggestions, remarks, feedback, … (please post a comment below!).

    [update]Further discussion about the performance and patches on anddev and box2d forums.[/update]

     

    4 Responses to “2D Physics on Android (using Box2D)”

    1. Very nice tutorial Chris! I was wondering how to do this and now you’ve gone and figured it out .. I guess its time to focus on the fun stuff now - what to *do* with such power! :)

    2. great tutorial but I keep getting a force close. :(

    3. Strange, I don’t get a force close here. Maybe have a look over to anddev and post about your problem (include the “adb logcat” output): http://www.anddev.org/viewtopic.php?t=5099

    4. Do you have complete working android project?

imprint