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);
}
}
});
}
}