Powered by PulpCore

Physics.java  Ball.png  BridgePiece.png 

// Click to add a ball. Press R to reset
//
// Physics example using JBox2D, the Java port of Erin Catto's Box2D.
// www.jbox2d.org
// www.box2d.org
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 org.jbox2d.dynamics.joints.RevoluteJointDef;
import pulpcore.Input;
import pulpcore.animation.BindFunction;
import pulpcore.image.Colors;
import pulpcore.scene.Scene2D;
import pulpcore.sprite.FilledSprite;
import pulpcore.sprite.ImageSprite;
import pulpcore.sprite.Sprite;

public class Physics extends Scene2D {
    // JBox2D recommends objects should be in size from 0.1 to 10.
    // If the world is 1/10th the size of the stage, objects can be as small as 1x1 pixels and
    // as large as 100x100 pixels. Adjust the scale for your own needs.
    private static final float WORLD_TO_STAGE_SCALE = 10;

    private World world;
    private float time;
    private float dt = 1 / 60f;
    private float ballRadius = 31 / WORLD_TO_STAGE_SCALE;

    @Override
    public void load() {
        add(new FilledSprite(Colors.BLACK));

        world = new World(new AABB(new Vec2(0,0), new Vec2(64,48)),
            new Vec2(0.0f, 40), true);
        time = 0;

        createBridge("BridgePiece.png");

        // Add a ball
        Sprite ball = new ImageSprite("Ball.png", 0, 0);
        Body ballBody = createBallBody(new Vec2(32, 8), ballRadius);
        bindSpriteToBody(ball, ballBody);
        ball.setTag(ballBody);
        add(ball);
    }

    @Override
    public void update(int elapsedTime) {
        // Update Physics.
        // This can be improved, see http://gafferongames.com/game-physics/fix-your-timestep/
        time += (elapsedTime / 1000f);
        while (time >= dt) {
            world.step(dt, 10);
            time -= dt;
        }

        if (Input.isPressed(Input.KEY_R)) {
            reload();
        }
        if (Input.isMousePressed()) {
            int mouseX = Input.getMousePressX();
            int mouseY = Input.getMousePressY();
            Sprite s = getMainLayer().pick(mouseX, mouseY);
            if (s != null && s.getTag() instanceof Body) {
                // Remove an old ball
                s.removeFromParent();
                world.destroyBody((Body)s.getTag());
            }
            else {
                float x = mouseX / WORLD_TO_STAGE_SCALE;
                float y = mouseY / WORLD_TO_STAGE_SCALE;

                // Check if the position in valid
                if (world.inRange(new AABB(new Vec2(x-1,y-1), new Vec2(x+1, y+1)))) {
                    // Create a new ball and bind the view (Sprite) to the data (Body)
                    Sprite ball = new ImageSprite("Ball.png", 0, 0);
                    Body ballBody = createBallBody(new Vec2(x, y), ballRadius);
                    bindSpriteToBody(ball, ballBody);
                    ball.setTag(ballBody);
                    add(ball);
                }
            }
        }
    }

    private void bindSpriteToBody(Sprite sprite, final Body body) {
        sprite.setAnchor(0.5, 0.5);
        sprite.x.bindTo(new BindFunction() {
            public Number f() {
                return body.getPosition().x * WORLD_TO_STAGE_SCALE;
            }
        });
        sprite.y.bindTo(new BindFunction() {
            public Number f() {
                return body.getPosition().y * WORLD_TO_STAGE_SCALE;
            }
        });
        sprite.angle.bindTo(new BindFunction() {
            public Number f() {
                return body.getAngle();
            }
        });
    }

    private void addSpriteForBody(String imageName, Body body) {
        Sprite sprite = new ImageSprite(imageName, 0, 0);
        bindSpriteToBody(sprite, body);
        add(sprite);
    }

    private Body createBallBody(Vec2 pos, float radius) {
        CircleDef cd = new CircleDef();
        cd.radius = radius;
        cd.density = 2.0f;
        cd.friction = 0.2f;
        BodyDef bd = new BodyDef();
        bd.position.set(pos);
        Body body = world.createBody(bd);
        body.createShape(cd);
        body.setMassFromShapes();
        return body;
    }

    private void createBridge(String imageName) {

        PolygonDef sd = new PolygonDef();
        sd.setAsBox(0.6f, 0.2f);
        sd.density = 60.0f;
        sd.friction = 0.2f;

        RevoluteJointDef jd = new RevoluteJointDef();
        int numPlanks = 40;

        Body prevBody = null;
        Body firstBody = null;
        for (int i = 0; i < numPlanks; i++) {
            BodyDef bd = new BodyDef();
            bd.position.set(3f + 1.5f * i, 32f);
            Body body = world.createBody(bd);
            body.createShape(sd);

            addSpriteForBody(imageName, body);

            if (prevBody == null) {
                firstBody = body;
            }
            else {
                if (i != numPlanks - 1) {
                    body.setMassFromShapes();
                }
                Vec2 anchor = new Vec2(2.4f + 1.5f * i, 32f);
                jd.initialize(prevBody, body, anchor);
                world.createJoint(jd);
            }

            prevBody = body;
        }

        Vec2 anchor = new Vec2(2.4f + 1.5f * numPlanks, 32f);
        jd.initialize(prevBody, firstBody, anchor);
        world.createJoint(jd);
    }
}