HIDE NAV

JavaFX JBox2D Demonstration.

This program demonstrates basic use of the JBox2d physics engine with Java FX shape nodes to manage visuals.
Note that this would require the incorporation of the library jar file which can be downloaded below.

[jar] JBox 2D Library v 2.2.1.1

PhysDemo.java


package ceccs;

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import org.jbox2d.collision.shapes.PolygonShape;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.*;

public class JFXBox2dDemo extends Application {

    float physScale = 10f;
    World world;
    Body boxBody, floorBody;
    //visuals
    Rectangle boxNode, floorNode;
    AnimationTimer aTimer;


    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        double boxPositionXInit = 300, boxPositionYinit = 100;
        Vec2 boxPositionInitial = 
	  new Vec2((float)boxPositionXInit/physScale,(float)boxPositionYinit/physScale);

        double wBox = 40,hBox = 15;
        boxNode = new Rectangle(wBox,hBox, Color.RED);

        double wFloor = 250, hFloor=10;
        floorNode = new Rectangle(wFloor,hFloor, Color.BLUE);

        world = new World(new Vec2(0,20/physScale));

        //making a single box.
        BodyDef boxBodyDef = new BodyDef();
        boxBodyDef.type = BodyType.DYNAMIC;
        boxBodyDef.position = boxPositionInitial;
        boxBodyDef.gravityScale = 1;
        boxBody = world.createBody(boxBodyDef);
        FixtureDef boxFixtureDef = new FixtureDef();
        boxFixtureDef.density = 1;
        boxFixtureDef.restitution = .1f;
        PolygonShape ps = new PolygonShape();
        Vec2[] vertices = {
                new Vec2(-(float)wBox/2/physScale,-(float)hBox/2/physScale),
                new Vec2((float)wBox/2/physScale,-(float)hBox/2/physScale),
                new Vec2((float)wBox/2/physScale,(float)hBox/2/physScale),
                new Vec2(-(float)wBox/2/physScale,(float)hBox/2/physScale),
                };
        ps.set(vertices, 4);
        boxFixtureDef.shape = ps;
        boxBody.createFixture(boxFixtureDef);

        //making the floor
        BodyDef floorBodyDef = new BodyDef();
        //floorBodyDef.fixedRotation = true;
        //floorBodyDef.gravityScale = 0;
        floorBodyDef.type = BodyType.STATIC;
        floorBodyDef.position = new Vec2(300/physScale, ((350-(float)hFloor))/physScale);
        floorBody = world.createBody(floorBodyDef);
        FixtureDef floorFixtureDef = new FixtureDef();
        PolygonShape psFloor = new PolygonShape();
        Vec2[] floorVertices = {
                new Vec2(-(float)wFloor/2/physScale,-(float)hFloor/2/physScale),
                new Vec2((float)wFloor/2/physScale,-(float)hFloor/2/physScale),
                new Vec2((float)wFloor/2/physScale,(float)hFloor/2/physScale),
                new Vec2(-(float)wFloor/2/physScale,(float)hFloor/2/physScale),
        };
        //EdgeShape es = new EdgeShape();
        //es.set(new Vec2(0,0), new Vec2((float)floorNode.getWidth()/physScale, 0));
        floorFixtureDef.shape = psFloor;
        psFloor.set(floorVertices, 4);
        floorBody.createFixture(floorFixtureDef);

        //scene setup
        StackPane root = new StackPane();
        root.setAlignment(Pos.TOP_CENTER);
        Pane physPane = new Pane();
        physPane.getChildren().addAll(floorNode,boxNode);
        root.getChildren().add(physPane);
        Scene scn = new Scene(root, 600,400);
        primaryStage.setScene(scn);
        primaryStage.setTitle("JavaFX - Box2D Basic Demonstration");
        primaryStage.setResizable(false);
        primaryStage.show();

        //time control
        aTimer = new AnimationTimer() {
            long prevTimeNanos;

            @Override
            public void start() {
                super.start();
                prevTimeNanos = System.nanoTime();
            }

            @Override
            public void handle(long now) {
                //framerate limit: 33,000 nanosec. = .033s per refresh
                //.033s period is approx. 30 frames per second.
                if(now - prevTimeNanos > 33_000) {
                    //update physics
                    float timeStep = .05f;
                    world.step(timeStep, 1, 1);

                    //graphics
                    boxNode.setLayoutX(boxBody.getPosition().x * physScale - wBox / 2);
                    boxNode.setLayoutY(boxBody.getPosition().y * physScale - hBox / 2);
                    boxNode.setRotate(Math.toDegrees(boxBody.getAngle()));

                    floorNode.setLayoutX(floorBody.getPosition().x * physScale - wFloor / 2);
                    floorNode.setLayoutY(floorBody.getPosition().y * physScale - hFloor / 2);
                    floorNode.setRotate(Math.toDegrees(floorNode.getRotate()));

                    prevTimeNanos = now;
                }

            }
        };

        //introduce some rotation to make things more interesting
        boxBody.setAngularVelocity(-1.75f);
        aTimer.start();

        //control instructions
        Label controlsLabel = new Label("Press Space to Reset Rectangle");
        controlsLabel.setFont(new Font(20));
        controlsLabel.setPadding(new Insets(50));
        root.getChildren().add(controlsLabel);

        //hotkey to respawn block
        scn.addEventHandler(KeyEvent.KEY_PRESSED, keyEvent -> {
            switch (keyEvent.getCode()){
                case SPACE -> {
                    //reset position and rotation
                    boxBody.setTransform(boxPositionInitial,0);

                    //randomize spin
                    float randSpin = ((float)Math.random() -.5f) * 4.0f;
                    boxBody.setAngularVelocity(randSpin);

                    //randomize initial velocity
                    float randVelX = (((float)Math.random() - .5f)*50)/physScale;
                    float randVelY = (((float)Math.random() - .5f)*50)/physScale;
                    Vec2 velInit = new Vec2(randVelX,randVelY);
                    boxBody.setLinearVelocity(velInit);
                }
            }
        });
    }
}