Box2D Game demo in Android

January 10th, 2012 by aabhaanjan

Lets see in this tutorial we will learn how to develop an android game with Box2d. There are following steps :

Step :1. Create a project using motodev.
1

Step :2. Create a lib folder inside the project and put jbox2d-2.0.1-full.jar file there.
lib_folder
Step :3. Open the project properties and add the jar file in the library.
import_Jbox
Step :4. Rename the MainActivity.java into Box2dGame.java put the same in AndroidManifest.xml. Now open the class and put following code

[xml]
package com.physicssample;
import android.app.Activity;
import android.opengl.GLSurfaceView;
import android.os.Bundle;

public class Box2dGame extends Activity
{
private GLSurfaceView _surfaceView;

@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
_surfaceView = new ClearGLSurfaceView(this);
setContentView(_surfaceView);
}

@Override
protected void onPause() {
super.onPause();
_surfaceView.onPause();
}

@Override
protected void onResume() {
super.onResume();
_surfaceView.onResume();
}

}

[/xml]

Step :5. Now create a ClearGLSurfaceView.java class and put following code inside the class

[xml]
package com.physicssample;

import android.content.Context;
import android.opengl.GLSurfaceView;
import android.view.MotionEvent;

public class ClearGLSurfaceView extends GLSurfaceView
{
ClearRenderer _refRenderer;
public ClearGLSurfaceView(Context context) {
super(context);
_refRenderer = new ClearRenderer(context);
setRenderer(_refRenderer);
}

public boolean onTouchEvent(final MotionEvent event) {
_refRenderer.setSize(this.getWidth(),this.getHeight());
queueEvent(new Runnable(){
public void run() {
_refRenderer.touchEvent(event.getX(), event.getY(), event.getAction());
}});
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
return true;
}
}
[/xml]

Step :5. Now create a ClearRenderer.java class and put following code inside the class

[xml]
package com.physicssample;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import org.jbox2d.collision.PolygonShape;
import org.jbox2d.collision.Shape;
import org.jbox2d.collision.ShapeType;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.Body;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.opengl.GLU;
import android.view.MotionEvent;

public class ClearRenderer implements GLSurfaceView.Renderer
{
private PhysicsWorld _physicsWorld;
private ObjectCreater _refBox;
private Context _context;
private int _width;
private int _height;

public ClearRenderer(Context newContext)
{
_context = newContext;
_refBox = new ObjectCreater(new float[]{-1,-1,0,1,-1,0,1,1,0,-1,1,0}, new float[]{ 0f,1f, 1f,1f, 1f,0f,0f,0f},new short[]{0,1,2,3,0},5);
_physicsWorld = new PhysicsWorld();
_physicsWorld.createWorld();
_physicsWorld.addBox(0f, -25f, 50f, 10f, 0f, false);
}

public void onSurfaceCreated(GL10 gl, EGLConfig config)
{
GLU.gluOrtho2D(gl, -12f, 12f, -20f, 20f);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,
GL10.GL_REPEAT);
gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,
GL10.GL_REPEAT);
_refBox.loadTexture(gl, _context, R.drawable.box);
}

public void onSurfaceChanged(GL10 gl, int w, int h)
{
gl.glViewport(0, 0, w, h);
}

public void onDrawFrame(GL10 gl)
{
gl.glClearColor(0f, 0, 0.5f, 1.0f);
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glTexEnvx(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE,
GL10.GL_REPLACE);
gl.glColor4f(1f, 1f, 1f, 1f);
Vec2 vec;
Body _body = _physicsWorld.getBodyList();
do
{
Shape _shape = _body.getShapeList();
if (_shape != null)
{
vec = _body.getPosition();
float rot = _body.getAngle() * 57f;
if (ShapeType.POLYGON_SHAPE == _shape.getType())
{
Vec2[] _vertexes = ((PolygonShape)_shape).getVertices();
_refBox.draw(gl, vec.x, vec.y, 0f, rot, _vertexes[2].x, _vertexes[2].y);
}

}
_body = _body.getNext();
}
while (_body != null);
_physicsWorld.update();
}

public void touchEvent(float x, float y, int eventCode)
{
float _worldX = ((x-(this._width/2))*12f)/(this._width/2);
float _worldY = ((y-(this._height/2))*-20f)/(this._height/2);
if (eventCode == MotionEvent.ACTION_UP)
{
_physicsWorld.addBox(_worldX, _worldY, .98f, .98f, 0f, true);

}
}

public void setSize(int x, int y)
{
this._width = x;
this._height = y;
}
}

[/xml]

Step :6. Now create a PhysicsWorld.java class and put following code inside the class

[xml]
package com.physicssample;
import org.jbox2d.collision.AABB;
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;

public class PhysicsWorld
{
final private int MAXBOX = 20;
final private float FRAMERATE = 30f;
private float _timeStep = (1f / FRAMERATE);
private int _iterations = 5;
private int _count = 0;

private AABB _box2dWorld;
private World _myWorld;

public void createWorld()
{
_box2dWorld = new AABB();
_box2dWorld.lowerBound.set(new Vec2(-100f, -100f));
_box2dWorld.upperBound.set(new Vec2(100f, 100f));

Vec2 gravity = new Vec2(0f, -10f);
boolean doSleep = false;
_myWorld = new World(_box2dWorld, gravity, doSleep);

}

public void setGrav(float x, float y)
{
_myWorld.setGravity(new Vec2(x,y));
}

public void addBox(float x, float y, float xr, float yr, float angle, boolean dynamic)
{
if (_count < (MAXBOX-1)) { BodyDef _groundBody; _groundBody = new BodyDef(); _groundBody.position.set(new Vec2(x, y)); _groundBody.angle = angle; Body groundBody = _myWorld.createBody(_groundBody); PolygonDef _groundShape; _groundShape = new PolygonDef(); _groundShape.setAsBox(xr, yr); _groundShape.density = 1.0f; groundBody.createShape(_groundShape); if (dynamic) { groundBody.setMassFromShapes(); } if (dynamic) { _count++; } } } public void update() { _myWorld.step(_timeStep, _iterations); } public int getCount() { return _count; } public Body getBodyList() { return _myWorld.getBodyList(); } } [/xml] Step :6. Now create a ObjectCreater.java class and put following code inside the class [xml] package com.physicssample; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import java.nio.ShortBuffer; import javax.microedition.khronos.opengles.GL10; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.opengl.GLUtils; public class ObjectCreater { private FloatBuffer _vertexBuffer; private ShortBuffer _indexBuffer; private FloatBuffer _texBuffer; private int _vertexCount = 0; private boolean _hasTexture = false; private int[] _texture = new int[1]; public ObjectCreater(float[] coords, float[] tcoords, short[] icoords, int vertexes) { this(coords, icoords, vertexes); _texBuffer = makeFloatBuffer(tcoords); } public ObjectCreater(float[] coords, short[] icoords, int vertexes) { _vertexCount = vertexes; _vertexBuffer = makeFloatBuffer(coords); _indexBuffer = makeShortBuffer(icoords); } protected static FloatBuffer makeFloatBuffer(float[] arr) { ByteBuffer bb = ByteBuffer.allocateDirect(arr.length*4); bb.order(ByteOrder.nativeOrder()); FloatBuffer fb = bb.asFloatBuffer(); fb.put(arr); fb.position(0); return fb; } protected static ShortBuffer makeShortBuffer(short[] arr) { ByteBuffer bb = ByteBuffer.allocateDirect(arr.length*4); bb.order(ByteOrder.nativeOrder()); ShortBuffer ib = bb.asShortBuffer(); ib.put(arr); ib.position(0); return ib; } public void loadTexture(GL10 gl, Context mContext, int mTex) { _hasTexture = true; gl.glGenTextures(1, _texture, 0); gl.glBindTexture(GL10.GL_TEXTURE_2D, _texture[0]); Bitmap bitmap; bitmap = BitmapFactory.decodeResource(mContext.getResources(), mTex); GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0); bitmap.recycle(); gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR ); gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR ); } public void draw(GL10 gl) { if (_hasTexture) { gl.glEnable(GL10.GL_TEXTURE_2D); gl.glBindTexture(GL10.GL_TEXTURE_2D, _texture[0]); gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, _texBuffer); } else { gl.glDisable(GL10.GL_TEXTURE_2D); } gl.glFrontFace(GL10.GL_CCW); gl.glVertexPointer(3, GL10.GL_FLOAT, 0, _vertexBuffer); gl.glDrawElements(GL10.GL_TRIANGLE_FAN, _vertexCount, GL10.GL_UNSIGNED_SHORT, _indexBuffer); gl.glDisable(GL10.GL_TEXTURE_2D); } public void draw(GL10 gl, float x, float y, float z, float rot, float scale) { this.draw(gl, x, y, z, rot, scale, scale); } public void draw(GL10 gl, float x, float y, float z, float rot, float scaleX, float scaleY) { gl.glPushMatrix(); gl.glTranslatef(x, y, z); gl.glRotatef(rot, 0f, 0f, 1f); gl.glScalef(scaleX, scaleY, 1f); this.draw(gl); gl.glPopMatrix(); } } [/xml] Step :6. Run your app it will look like this . If you have any question or need more clarification please write on forum.dremsus.com. final