240 likes | 377 Views
Android Game Development. 2D physics. Base project. Download our base project and open it in NetBeans cg.iit.bme.hu/ gamedev /KIC/11_AndroidDevelopment/11_03_Android_LevelsGameObjects_Final.zip Change the android sdk location path Per-user properties ( local.properties )
E N D
Android Game Development 2D physics
Base project • Downloadourbase project and open it inNetBeans • cg.iit.bme.hu/gamedev/KIC/11_AndroidDevelopment/11_03_Android_LevelsGameObjects_Final.zip • Changetheandroidsdklocationpath • Per-userproperties (local.properties) • sdk.dir=changepath here • Start an emulator • Build • Run
Physics • Box2D • 2D physics engine • Java JBox2D • Android version JBox2d4Android • JBox2D4Android_2.1.2.jar should be copied to the ./libs folder in our project folder • Create new package: Engine.Physics
PhysicsObject • Create PhysicsObject class in Physisc package public abstract class PhysicsObject{ protected Object userData = 0; public Object getUserData(){return userData;} public void setUserData(Object data){userData = data;} public abstract void destroy(); public abstract Vector3 getPosition(); public abstract Vector3 getVelocity(); public abstract void limitVelocity(Vector3 limit); public abstract void setVelocity(float x, float y, float z); public abstract void setLinearDamping(float value); public abstract Quaternion getOrientation(); public void update(){} public abstract void addForce(float x, float y, float z); public abstract void moveToPos(float x, float y, float z); public abstract void rotateToAngles(float x, float y, float z); }
PhysicsEngine2D I. • Create PhysicsEngine2D class public class PhysicsEngine2D { private static final PhysicsEngine2D instance = new PhysicsEngine2D(); private World world = new World(new Vec2(0.0F, -10.0F), false); public static PhysicsEngine2D getSingleton(){ return instance; } private PhysicsEngine2D(){} public Body createBody(BodyDef def){ return this.world.createBody(def); } public void destroyBody(Body body){ world.destroyBody(body); }
PhysicsEngine2D II. public void clear(){ Body nextB = world.getBodyList(); while(nextB != null) { Body b = nextB; nextB = b.getNext(); world.destroyBody(b); } } public void update(float dt){ this.world.step(dt, 6, 2); this.world.clearForces(); } public void setGravity(float x, float y) { this.world.setGravity(new Vec2(x, y)); } }
Physics2DObject I. • Create Ohysics2DObject class public class Physics2DObject extends PhysicsObject{ Body body = null; Vector3 position = new Vector3(); Vector3 velocity = new Vector3(); Vector3 velocityLimit = new Vector3(-1,-1,-1); Quaternion orientation = new Quaternion(); String groupName = null; public Physics2DObject(Body b) { this.body = b; this.position.set(b.getPosition().x, b.getPosition().y, 0.0F); this.orientation.set(0.0F, 0.0F, b.getAngle()); if(body.m_type != BodyType.DYNAMIC){ Fixture f = body.getFixtureList(); while(f!=null){ f.m_restitution = 0; f = f.getNext(); } } this.body.m_userData = this; }
Physics2DObject II. public void destroy(){ PhysicsEngine2D.getSingleton().destroyBody(body); } public Body getBody(){return body;} public Vector3 getPosition(){return this.position;} public Vector3 getVelocity(){return new Vector3(this.velocity);} public void setVelocity(float x, float y, float z){ velocity.set(x,y,z); body.setLinearVelocity(new Vec2(x, y)); } public void limitVelocity(Vector3 limit){ velocityLimit.set(limit.x(), limit.y(), limit.z()); } public void setLinearDamping(float value){body.setLinearDamping(value);} public Quaternion getOrientation(){return this.orientation;}
Physics2DObject III. public void update(){ this.velocity.set(body.getLinearVelocity().x, body.getLinearVelocity().y, 0); if(velocityLimit.x() > 0){ if(velocity.x() > velocityLimit.x()) body.setLinearVelocity(new Vec2(velocityLimit.x(), velocity.y())); if(velocity.x() < -velocityLimit.x()) body.setLinearVelocity(new Vec2(-velocityLimit.x(), velocity.y())); } if(velocityLimit.y() > 0){ if(velocity.y() > velocityLimit.y()) body.setLinearVelocity(new Vec2(velocity.x(), velocityLimit.y())); if(velocity.y() < -velocityLimit.y()) body.setLinearVelocity(new Vec2(velocity.x(), -velocityLimit.y())); } this.position.set(this.body.getPosition().x, this.body.getPosition().y, 0.0F); this.orientation.set(0.0F, 0.0F, this.body.getAngle()); this.velocity.set(body.getLinearVelocity().x, body.getLinearVelocity().y, 0); }
Physics2DObject IV. public void addForce(float x, float y, float z) { body.applyLinearImpulse(new Vec2(x,y), new Vec2(0.0f,0.0f)); } public void moveToPos(float x, float y, float z) { float angle = this.body.getAngle(); this.body.setTransform(new Vec2(x, y), angle); } public void rotateToAngles(float x, float y, float z) { Vec2 pos = this.body.getPosition(); this.body.setTransform(pos, z); } }//Physics2DObject end
MainEngine • MainEngine.update add new line: level.preUpdate(t, dt); PhysicsEngine2D.getSingleton().update(dt); level.update(t, dt);
GenericGameObject I. • Modify GenericGameObject to contain rigid body representation • New member: protected PhysicsObjectphysicsO = null; • Constructor public GenericGameObject(String name, MeshEntity entity, PhysicsObjectpo) { super(name); if (entity != null) { this.renderO = entity; this.renderNode = SceneManager.getSingleton().getRootNode().createChild(); this.renderNode.attachObject(this.renderO); } if (po != null) { this.physicsO = po; this.physicsO.setUserData(this); } }
GenericGameObject II. public void destroy(){ if(renderO != null){ renderNode.detachObject(renderO); renderNode.getParent().removeChild(renderNode); } if(physicsO != null) { physicsO.destroy(); } }
GenericGameObject III. public void update(float t, float dt) { if (this.physicsO != null) { this.physicsO.update(); if (this.renderNode != null) { this.renderNode.setPosition(this.physicsO.getPosition()); this.renderNode.setOrientation(this.physicsO.getOrientation()); this.renderO.update(t, dt); } } } public Vector3 getPosition() { return this.physicsO.getPosition(); } public Vector3 getVelocity() { return this.physicsO.getVelocity(); }
GenericGameObject IV. public void setPosition(float x, float y, float z) { if (this.physicsO != null) this.physicsO.moveToPos(x, y, z); if (this.renderNode != null) this.renderNode.setPosition(x, y, z); } public void setOrientation(float yaw, float pitch, float roll) { if (this.physicsO != null) this.physicsO.rotateToAngles(yaw, pitch, roll); if (this.renderNode != null) this.renderNode.setOrientation(yaw, pitch, roll); }
LevelGenerator I. • createPlane() GenericGameObject go = new GenericGameObject(name, me, null); • New method protected Physics2DObject createStaticPhyBox(float w, float h) { PolygonShape shape = new PolygonShape(); shape.setAsBox(w, h); BodyDefbd = new BodyDef(); bd.type = BodyType.STATIC; FixtureDeffd = new FixtureDef(); fd.shape = shape; fd.restitution = 0; Body body = PhysicsEngine2D.getSingleton().createBody(bd); body.createFixture(fd); return new Physics2DObject(body); }
LevelGenerator II. protected void createGroundElement(float posX) throws Exception{ Physics2DObject groundPhy = createStaticPhyBox(1.0f, 1); GenericGameObject ground = new GenericGameObject("ground_" + groundCount, groundME, groundPhy); … } protected void createPitElement(float posX) throws Exception{ Physics2DObject pitPhy = createStaticPhyBox(1.0f, 0.2f); GenericGameObject pit = new GenericGameObject("pit_" + pitCount, null, pitPhy); … } protected void createFloor1Element(float posX) throws Exception{ Physics2DObject floorPhy = createStaticPhyBox(1.0f, 0.1f); GenericGameObject floor1 = new GenericGameObject("floor1_" + floor1Count, floor1ME, floorPhy); … } protected void createFloor2Element(float posX) throws Exception{ Physics2DObject floorPhy = createStaticPhyBox(1.0f, 0.1f); GenericGameObject floor2 = new GenericGameObject("floor2_" + floor2Count, floor2ME, floorPhy); … }
LevelGenerator III. protected intboxCount = 0; protected void createBox(float x, float y) { PolygonShape shape = new PolygonShape(); shape.setAsBox(0.3f, 0.3f); BodyDefbd = new BodyDef(); bd.type = BodyType.DYNAMIC; FixtureDeffd = new FixtureDef(); fd.shape = shape; fd.restitution = 0.13f; fd.density = 100.0f; fd.friction = 0.5f; Body body = PhysicsEngine2D.getSingleton().createBody(bd); body.createFixture(fd); try{ MeshEntityitemME = new MeshEntity("box_" + boxCount, "UnitQuad"); itemME.setMeshScale(0.3f, 0.3f, 1); itemME.setMaterial("g_Box"); Physics2DObject itemPhy = new Physics2DObject(body); GenericGameObject item = new GenericGameObject("box_" + boxCount, itemME, itemPhy); item.setType(GameObject.ObjectType.UsefulThings); item.setPosition(x, y + 0.5f, 0); level.addGameObject(item); } catch(Exception e) { android.util.Log.e("LevelGenerator", "Unable to create item object: " + e.toString()); } boxCount++; }
LevelGenerator IV. public Level generate(){ … GenericGameObjectgroundL = new GenericGameObject("ground_l_" + i, groundME, null); … GenericGameObjectgroundR = new GenericGameObject("ground_r_" + i, groundME, null); … createBox(-levelSize + 3, 10); createBox(-levelSize + 3.2f, 13); createBox(-levelSize + 2.8f, 16); for(inti = 0; i < levelSize; ++i){ …. }
Make the simulation more stable • Physics2DEngine: public void update(float dt){ float maxDt = 0.09f; while(dt > maxDt){ this.world.step(maxDt, 5, 2); dt -= maxDt; } this.world.step(dt, 5, 2); this.world.clearForces(); } Play with these parameters!!
Border: invisible physics boxes • LevelGenerator.generate public Level generate() { … //generate background … Physics2DObject bPhy = createStaticPhyBox(1.0f, 10); GenericGameObject b1 = new GenericGameObject("border1",null,bPhy); b1.setPosition(-levelSize - 1, 0, 0); level.addGameObject(b1); Physics2DObject bPhy2 = createStaticPhyBox(1.0f, 10); GenericGameObject b2 = new GenericGameObject("border2",null,bPhy2); b2.setPosition(levelSize + 1, 0, 0); level.addGameObject(b2); for(int i = 0; i < 3; i++)