com.hatstick.fireman.physics.Box2DPhysicsWorld.java Source code

Java tutorial

Introduction

Here is the source code for com.hatstick.fireman.physics.Box2DPhysicsWorld.java

Source

package com.hatstick.fireman.physics;

/*******************************************************************************
 * Copyright 2011 See AUTHORS file.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/
/*
 * Copyright 2010 Mario Zechner (contact@badlogicgames.com), Nathan Sweet (admin@esotericsoftware.com)
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS"
 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */

import java.util.ArrayList;
import java.util.Map;

import com.alex.model.Block;
import com.alex.model.FireMan;
import com.alex.model.Civilian;
import com.alex.model.Item;
import com.alex.model.Level;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer;
import com.badlogic.gdx.physics.box2d.CircleShape;
import com.badlogic.gdx.physics.box2d.Contact;
import com.badlogic.gdx.physics.box2d.ContactImpulse;
import com.badlogic.gdx.physics.box2d.ContactListener;
import com.badlogic.gdx.physics.box2d.Fixture;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.JointDef;
import com.badlogic.gdx.physics.box2d.Manifold;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.QueryCallback;
import com.badlogic.gdx.physics.box2d.RayCastCallback;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.physics.box2d.joints.MouseJoint;
import com.badlogic.gdx.physics.box2d.joints.MouseJointDef;
import com.badlogic.gdx.physics.box2d.joints.WeldJointDef;
import com.badlogic.gdx.utils.TimeUtils;

/** Base class for all Box2D Testbed tests, all subclasses must implement the createWorld() method.
 * 
 * @author badlogicgames@gmail.com */
public class Box2DPhysicsWorld implements RayCastCallback {

    /** The Explosion Engine **/
    private ExplosionEngine xEngine;

    /** the renderer **/
    private Box2DDebugRenderer renderer;

    /** our box2D world **/
    private World world;

    /** a hit body **/
    private Body hitBody = null;

    /** The level that we need to render **/
    private Level level;

    /** Bob that we need to render physics for **/
    private FireMan bob;

    /** our mouse joint **/
    private MouseJoint mouseJoint = null;
    private boolean destroyMousejoint = false;

    /** Used to keep track of id's **/
    private int numEnterPoints = 0;

    /** These two arrays are required for creating/removing bodies between world steps **/
    private ArrayList<JointDef> jointsToCreate = new ArrayList<JointDef>();
    private ArrayList<JointDef> jointsToDelete = new ArrayList<JointDef>();
    private ArrayList<BodyDef> bodiesToCreate = new ArrayList<BodyDef>();
    private ArrayList<Body> bodiesToDelete = new ArrayList<Body>();

    public enum ModelType {
        PLAYER, WALL, ENEMY, ITEM, FOOT_SENSOR, LEFT_SIDE_SENSOR, RIGHT_SIDE_SENSOR
    }

    public Box2DPhysicsWorld(Level level) {
        this.level = level;
        this.bob = level.getBob();
        createPhysicsWorld();
    }

    public void createPhysicsWorld() {

        xEngine = new ExplosionEngine();

        // create the debug renderer
        renderer = new Box2DDebugRenderer();

        // create the world
        world = new World(new Vector2(0, -3), true);

        bob.setBody(createPhysicsObject(bob.getBounds(), ModelType.PLAYER, -1).getBody());

        // Create our enemy's physical representations
        for (Map.Entry<Civilian, Integer> civilian : level.getEnemies().entrySet()) {
            civilian.getKey().setFixture(
                    createPhysicsObject(civilian.getKey().getBounds(), ModelType.ENEMY, civilian.getValue()));
        }

        // Create our item's physical representations
        for (Map.Entry<Item, Integer> item : level.getItems().entrySet()) {
            item.getKey()
                    .setFixture(createPhysicsObject(item.getKey().getBounds(), ModelType.ITEM, item.getValue()));
        }

        // Create our level out of blocks
        for (Block block : level.getBlocks()) {
            createBoxes(block.getBounds());
        }

        //   createDestruction();

        world.setContactListener(new ContactListener() {
            @Override
            public void beginContact(Contact contact) {

                // Get our UserData object, and check for contacts
                UserData dataA = (UserData) contact.getFixtureA().getUserData();
                UserData dataB = (UserData) contact.getFixtureA().getUserData();

                /** Used for determining if character can jump or not **/
                if (dataA.modelType == ModelType.FOOT_SENSOR) {
                    if (dataA.parentId == -1) { // PlayerCharacter's foot
                        bob.setNumFootContacts(1);
                        bob.canJump(true);
                    }
                }
                if (dataB.modelType == ModelType.FOOT_SENSOR) {
                    if (dataB.parentId == -1) { // PlayerCharacter's foot
                        bob.setNumFootContacts(1);
                    }
                }

                if (dataA.modelType == ModelType.LEFT_SIDE_SENSOR) {
                    if (dataA.parentId == -1) { // PlayerCharacter's foot
                        bob.setNumLeftSideContacts(1);
                        bob.canJump(true);
                    }
                }
                if (dataB.modelType == ModelType.LEFT_SIDE_SENSOR) {
                    if (dataB.parentId == -1) { // PlayerCharacter's foot
                        bob.setNumLeftSideContacts(1);
                    }
                }

                if (dataA.modelType == ModelType.RIGHT_SIDE_SENSOR) {
                    if (dataA.parentId == -1) { // PlayerCharacter's foot
                        bob.setNumRightSideContacts(1);
                        bob.canJump(true);
                    }
                }
                if (dataB.modelType == ModelType.RIGHT_SIDE_SENSOR) {
                    if (dataB.parentId == -1) { // PlayerCharacter's foot
                        bob.setNumRightSideContacts(1);
                    }
                }

                /** Touching an item (used for picking up items) **/
                if (dataA.modelType == ModelType.PLAYER && dataB.modelType == ModelType.ITEM
                        || dataB.modelType == ModelType.ITEM && dataA.modelType == ModelType.PLAYER) {

                    MouseJointDef def = new MouseJointDef();
                    def.bodyA = contact.getFixtureA().getBody();
                    def.bodyB = contact.getFixtureB().getBody();
                    dataA = (UserData) def.bodyA.getUserData();
                    def.collideConnected = false;
                    def.target.set(testPoint.x, testPoint.y);

                    if (dataA.modelType == ModelType.PLAYER) {
                        def.target.set(def.bodyA.getWorldCenter());
                        def.maxForce = 1000.0f * def.bodyA.getMass();
                    } else {
                        def.target.set(def.bodyB.getWorldCenter());
                        def.maxForce = 1000.0f * def.bodyB.getMass();
                    }
                    jointsToCreate.add(def);
                }
            }

            @Override
            public void endContact(Contact contact) {
                // Get our UserData object, and check for contacts
                UserData dataA = (UserData) contact.getFixtureA().getUserData();
                UserData dataB = (UserData) contact.getFixtureA().getUserData();

                /** Used for determining if character can jump or not **/
                if (dataA.modelType == ModelType.FOOT_SENSOR) {
                    if (dataA.parentId == -1) { // PlayerCharacter's foot
                        bob.setNumFootContacts(-1);
                    }
                }
                if (dataB.modelType == ModelType.FOOT_SENSOR) {
                    if (dataB.parentId == -1) { // PlayerCharacter's foot
                        bob.setNumFootContacts(-1);
                    }
                }
            }

            @Override
            public void preSolve(Contact contact, Manifold oldManifold) {
            }

            @Override
            public void postSolve(Contact contact, ContactImpulse impulse) {
            }
        });
    }

    public World getWorld() {
        return world;
    }

    public void render(OrthographicCamera camera) {
        // update the world with a fixed time step
        world.step(Gdx.app.getGraphics().getDeltaTime() * 10, 8, 3);
        if (mouseJoint != null)
            mouseJoint.setTarget(bob.getBody().getWorldCenter());

        // Destroy mouseJoint? (drop item)
        if (destroyMousejoint == true) {
            if (!world.isLocked()) {
                world.destroyJoint(mouseJoint);
                mouseJoint = null;
                destroyMousejoint = false;
            }
        }

        // Delete any bodies up for deletion
        if (!bodiesToDelete.isEmpty()) {
            // Make sure it is safe to delete!!
            if (!world.isLocked()) {
                for (Body body : bodiesToDelete) {
                    world.destroyBody(body);
                    body.setUserData(null);
                    body = null;
                }
                bodiesToDelete.clear(); // Don't forget to clear the null bodies!
            }
        }

        // Create any bodies up for creation
        if (!bodiesToCreate.isEmpty()) {
            // Make sure it is safe to create!!
            if (!world.isLocked()) {
                for (BodyDef body : bodiesToCreate) {
                    world.createBody(body);
                }
                bodiesToCreate.clear(); // Don't forget to clear!
            }
        }

        // Create any joints up for creation
        if (!jointsToCreate.isEmpty()) {
            // Make sure it is safe to create!!
            if (!world.isLocked()) {
                for (JointDef body : jointsToCreate) {
                    mouseJoint = (MouseJoint) world.createJoint(body);
                }
                jointsToCreate.clear(); // Don't forget to clear!
            }
        }
        // render the world using the debug renderer
        renderer.render(world, camera.combined);
    }

    private Fixture createPhysicsObject(Rectangle bounds, ModelType type, Integer id) {

        UserData userData = new UserData(numEnterPoints, type, null);
        CircleShape objectPoly = new CircleShape();
        objectPoly.setRadius(bounds.width / 2);

        BodyDef enemyBodyDef = new BodyDef();
        enemyBodyDef.type = BodyType.DynamicBody;
        enemyBodyDef.position.x = bounds.x;
        enemyBodyDef.position.y = bounds.y;
        Body objectBody = world.createBody(enemyBodyDef);
        FixtureDef objectFixtureDef = new FixtureDef();
        objectFixtureDef.shape = objectPoly;

        //   objectBody.setUserData(userData);
        objectFixtureDef.restitution = .025f;
        Fixture fixture = objectBody.createFixture(objectFixtureDef);
        fixture.setUserData(userData);
        objectBody.setLinearDamping(2f);
        objectBody.setGravityScale(.4f);
        objectBody.setFixedRotation(true);
        objectPoly.dispose();
        numEnterPoints++;

        //add a sensor on the bottom to check if touching ground (for jumping)
        PolygonShape polygonShape = new PolygonShape();
        polygonShape.setAsBox(bounds.width / 3, bounds.height / 8, new Vector2(0, -bounds.height / 2), 0);
        objectFixtureDef = new FixtureDef();
        objectFixtureDef.shape = polygonShape;
        objectFixtureDef.isSensor = true;
        Fixture footSensorFixture = objectBody.createFixture(objectFixtureDef);
        footSensorFixture.setUserData(new UserData(numEnterPoints, ModelType.FOOT_SENSOR, id));

        //add a sensor on left side to check if touching wall (for grappling)
        PolygonShape polygonShape2 = new PolygonShape();
        polygonShape2.setAsBox(bounds.width / 8, bounds.height / 3, new Vector2(-bounds.width / 2, 0), 0);
        objectFixtureDef = new FixtureDef();
        objectFixtureDef.shape = polygonShape2;
        objectFixtureDef.isSensor = true;
        Fixture leftSideSensorFixture = objectBody.createFixture(objectFixtureDef);
        leftSideSensorFixture.setUserData(new UserData(numEnterPoints, ModelType.LEFT_SIDE_SENSOR, id));

        //add a sensor on right side to check if touching wall (for grappling)
        polygonShape2.setAsBox(bounds.width / 8, bounds.height / 3, new Vector2(bounds.width / 2, 0), 0);
        objectFixtureDef = new FixtureDef();
        objectFixtureDef.shape = polygonShape2;
        objectFixtureDef.isSensor = true;
        Fixture rightSideSensorFixture = objectBody.createFixture(objectFixtureDef);
        rightSideSensorFixture.setUserData(new UserData(numEnterPoints, ModelType.RIGHT_SIDE_SENSOR, id));

        return fixture;
    }

    private void createDestruction() {
        UserData userData = new UserData(numEnterPoints, ModelType.WALL, null);
        PolygonShape brickPoly = new PolygonShape();
        brickPoly.setAsBox(0.5f, 0.5f);

        BodyDef brickBodyDef = new BodyDef();
        brickBodyDef.type = BodyType.DynamicBody;
        brickBodyDef.position.x = 2;
        brickBodyDef.position.y = 2;
        Body brickBody = world.createBody(brickBodyDef);

        FixtureDef brickFixtureDef = new FixtureDef();
        brickFixtureDef.shape = brickPoly;
        // For now, it seems the best way to tell our renderer what our 
        // object is through userData...
        //brickBody.setUserData(userData);
        Fixture fixture = brickBody.createFixture(brickFixtureDef);
        fixture.setUserData(userData);
        brickPoly.dispose();
        numEnterPoints++;

        xEngine.boom(new Vector2(2.1f, 2.1f), brickBody, this);
    }

    private void createBoxes(Rectangle bounds) {

        UserData userData = new UserData(numEnterPoints, ModelType.WALL, null);
        PolygonShape brickPoly = new PolygonShape();
        brickPoly.setAsBox(bounds.width / 2, bounds.height / 2);

        BodyDef brickBodyDef = new BodyDef();
        brickBodyDef.type = BodyType.StaticBody;
        brickBodyDef.position.x = bounds.x;
        brickBodyDef.position.y = bounds.y;
        Body brickBody = world.createBody(brickBodyDef);

        FixtureDef brickFixtureDef = new FixtureDef();
        brickFixtureDef.shape = brickPoly;
        // For now, it seems the best way to tell our renderer what our 
        // object is through userData...
        //brickBody.setUserData(userData);
        Fixture fixture = brickBody.createFixture(brickFixtureDef);
        fixture.setUserData(userData);
        brickPoly.dispose();
        numEnterPoints++;

    }

    // Bob-specific methods ************************************************************
    public void moveBob(Vector2 direction) {
        bob.getBody().applyForceToCenter(direction, true);
    }

    public void moveBody(Body body, Vector2 direction) {
        body.applyForceToCenter(direction, true);
    }

    public void jumpBody(Body body, float height) {
        body.applyLinearImpulse(new Vector2(0, height), body.getWorldCenter(), true);
    }

    public void jumpBob(Vector2 jump) {
        bob.getBody().applyLinearImpulse(jump, bob.getBody().getWorldCenter(), true);
    }

    public MouseJoint getMouseJoint() {
        return mouseJoint;
    }

    public void setdestroyMouseJoint() {
        destroyMousejoint = true;
    }

    /** Use this method to create when not on a time slice **/
    public void addBody(BodyDef body) {
        bodiesToCreate.add(body);
    }

    /** Use this method to delete when not on a time slice **/
    public void deleteBody(Body body) {
        bodiesToDelete.add(body);
    }

    // End Bob-specific methods ********************************************************

    /** we instantiate this vector and the callback here so we don't irritate the GC **/
    Vector3 testPoint = new Vector3();
    QueryCallback callback = new QueryCallback() {
        @Override
        public boolean reportFixture(Fixture fixture) {
            // if the hit point is inside the fixture of the body
            // we report it
            if (fixture.testPoint(testPoint.x, testPoint.y)) {
                hitBody = fixture.getBody();
                return false;
            } else
                return true;
        }
    };

    @Override
    public float reportRayFixture(Fixture fixture, Vector2 point, Vector2 normal, float fraction) {
        UserData data = (UserData) fixture.getUserData();
        if (data.modelType == ModelType.WALL) {

        }
        // TODO Auto-generated method stub
        return 0;
    }

    public void dispose() {
        renderer.dispose();
        world.dispose();
        renderer = null;
        world = null;
        hitBody = null;
    }

    public class UserData {
        public int id;
        public ModelType modelType;
        public Integer parentId;

        public UserData(int id, ModelType modelType, Integer parentId) {
            this.id = id;
            this.modelType = modelType;
            this.parentId = parentId;
        }
    }

    public int getNumEnterPoints() {
        return numEnterPoints;
    }
}