<<JBox2D Tutorial
This is a simple application to get your hands wet with JBox2D and JavaFX 2. I have chosen JavaFX 2.0 for GUI due to its power and simplicity. In this application user can draw different shapes, these shapes works as a hurdles. When user clicks on the “Start” button, balls starts falling, bouncing and reacting to the hurdles in a very natural way.
You can click here to launch this applications! If JavaFX 2 runtime is not installed on your PC then it will prompt you for installation. Launch this application and try drawing different hurdles and see how balls reacts to them. You can also click here to download the source code. Please note this is my first program in JBox2D and JavaFX so it might not be following all coding standards. So, your suggestions and feedback will help me to improve on this, so please leave your comments and rating at the end of this post.
If you are not able to launch the application from above link for any reason then this is a sample video of Hello World JBox2D with JavaFX 2.0application.
These are few sample snapshots of Hello World JBox2D with JavaFX 2.0 application.
This is a simple application to get your hands wet with JBox2D and JavaFX 2. I have chosen JavaFX 2.0 for GUI due to its power and simplicity. In this application user can draw different shapes, these shapes works as a hurdles. When user clicks on the “Start” button, balls starts falling, bouncing and reacting to the hurdles in a very natural way.
You can click here to launch this applications! If JavaFX 2 runtime is not installed on your PC then it will prompt you for installation. Launch this application and try drawing different hurdles and see how balls reacts to them. You can also click here to download the source code. Please note this is my first program in JBox2D and JavaFX so it might not be following all coding standards. So, your suggestions and feedback will help me to improve on this, so please leave your comments and rating at the end of this post.
If you are not able to launch the application from above link for any reason then this is a sample video of Hello World JBox2D with JavaFX 2.0application.
These are few sample snapshots of Hello World JBox2D with JavaFX 2.0 application.
JBox2D world, Ground, walls and balls are the main component of this application.
JBox2D World is the main component of any JBox2D application. Memory, objects and simulations are managed by the JBox2D World object. Gravity and the doSleep are two parameters of World object. If doSleep is set to true JBox2D world will allow bodies to sleep when they come to rest.
Ground is a bottom most part of application screen. If ground is not created then balls will travel downwards infinitely. Also left and right walls are created so balls will not move out of the viewable screen area.
JBox2D World is the main component of any JBox2D application. Memory, objects and simulations are managed by the JBox2D World object. Gravity and the doSleep are two parameters of World object. If doSleep is set to true JBox2D world will allow bodies to sleep when they come to rest.
Ground is a bottom most part of application screen. If ground is not created then balls will travel downwards infinitely. Also left and right walls are created so balls will not move out of the viewable screen area.
These are the code snippets for Hello World JBox2D with JavaFX 2.0. Please let me know if you have any queries on some part of code. I will be happy to answer.
Ball.java
JFXwithJBox2d.java
Utils.java
JavaFX 2 books
package jfxwithjbox2d; import javafx.scene.Node; import javafx.scene.paint.Color; import javafx.scene.paint.LinearGradient; import javafx.scene.shape.Circle; import org.jbox2d.collision.shapes.CircleShape; import org.jbox2d.dynamics.Body; import org.jbox2d.dynamics.BodyDef; import org.jbox2d.dynamics.BodyType; import org.jbox2d.dynamics.FixtureDef; /** * * @author dilip */ public class Ball{ //JavaFX UI for ball public Node node; //X and Y position of the ball in JBox2D world private float posX; private float posY; //Ball radius in pixels private int radius; /** * There are three types bodies in JBox2D – Static, Kinematic and dynamic * In this application static bodies (BodyType.STATIC – non movable bodies) * are used for drawing hurdles and dynamic bodies (BodyType.DYNAMIC–movable bodies) * are used for falling balls */ private BodyType bodyType; //Gradient effects for balls private LinearGradient gradient; public Ball(float posX, float posY){ this(posX, posY, Utils.BALL_SIZE, BodyType.DYNAMIC,Color.RED); this.posX = posX; this.posY = posY; } public Ball(float posX, float posY, int radius, BodyType bodyType, Color color){ this.posX = posX; this.posY = posY; this.radius = radius; this.bodyType = bodyType; this.gradient = Utils.getBallGradient(color); node = create(); } /** * This method creates a ball by using Circle object from JavaFX and CircleShape from JBox2D */ private Node create(){ //Create an UI for ball - JavaFX code Circle ball = new Circle(); ball.setRadius(radius); ball.setFill(gradient); //set look and feel /** * Set ball position on JavaFX scene. We need to convert JBox2D coordinates * to JavaFX coordinates which are in pixels. */ ball.setLayoutX(Utils.toPixelPosX(posX)); ball.setLayoutY(Utils.toPixelPosY(posY)); ball.setCache(true); //Cache this object for better performance //Create an JBox2D body defination for ball. BodyDef bd = new BodyDef(); bd.type = bodyType; bd.position.set(posX, posY); CircleShape cs = new CircleShape(); cs.m_radius = radius * 0.1f; //We need to convert radius to JBox2D equivalent // Create a fixture for ball FixtureDef fd = new FixtureDef(); fd.shape = cs; fd.density = 0.9f; fd.friction = 0.3f; fd.restitution = 0.6f; /** * Virtual invisible JBox2D body of ball. Bodies have velocity and position. * Forces, torques, and impulses can be applied to these bodies. */ Body body = Utils.world.createBody(bd); body.createFixture(fd); ball.setUserData(body); return ball; } }
JFXwithJBox2d.java
package jfxwithjbox2d; import java.util.Random; import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.application.Application; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.input.MouseEvent; import javafx.scene.paint.Color; import javafx.stage.Stage; import javafx.util.Duration; import org.jbox2d.dynamics.Body; import org.jbox2d.dynamics.BodyType; /** * * @author dilip */ public class JFXwithJBox2d extends Application { /** * @param args the command line arguments */ public static void main(String[] args) { Application.launch(args); } @Override public void start(Stage primaryStage) { primaryStage.setTitle("Hello JBox2d World!"); primaryStage.setFullScreen(false); primaryStage.setResizable(false); final Group root = new Group(); //Create a group for holding all objects on the screen final Scene scene = new Scene(root, Utils.WIDTH, Utils.HEIGHT,Color.BLACK); //Ball array for hold the balls final Ball[] ball = new Ball[Utils.NO_OF_BALLS]; Random r = new Random(System.currentTimeMillis()); /** * Generate balls and position them on random locations. * Random locations between 5 to 95 on x axis and between 100 to 500 on y axis */ for(int i=0;i<Utils.NO_OF_BALLS;i++) { ball[i]=new Ball(r.nextInt(90)+5,r.nextInt(400)+100); } //Add ground to the application, this is where balls will land Utils.addGround(100, 10); //Add left and right walls so balls will not move outside the viewing area. Utils.addWall(0,100,1,100); //Left wall Utils.addWall(99,100,1,100); //Right wall final Timeline timeline = new Timeline(); timeline.setCycleCount(Timeline.INDEFINITE); Duration duration = Duration.seconds(1.0/60.0); // Set duration for frame. //Create an ActionEvent, on trigger it executes a world time step and moves the balls to new position EventHandler<ActionEvent> ae = new EventHandler<ActionEvent>() { public void handle(ActionEvent t) { //Create time step. Set Iteration count 8 for velocity and 3 for positions Utils.world.step(1.0f/60.f, 8, 3); //Move balls to the new position computed by JBox2D for(int i=0;i<Utils.NO_OF_BALLS;i++) { Body body = (Body)ball[i].node.getUserData(); float xpos = Utils.toPixelPosX(body.getPosition().x); float ypos = Utils.toPixelPosY(body.getPosition().y); ball[i].node.setLayoutX(xpos); ball[i].node.setLayoutY(ypos); } } }; /** * Set ActionEvent and duration to the KeyFrame. * The ActionEvent is trigged when KeyFrame execution is over. */ KeyFrame frame = new KeyFrame(duration, ae, null,null); timeline.getKeyFrames().add(frame); //Create button to start simulation. final Button btn = new Button(); btn.setLayoutX((Utils.WIDTH/2)); btn.setLayoutY((Utils.HEIGHT-30)); btn.setText("Start"); btn.setOnAction(new EventHandler<ActionEvent>() { public void handle(ActionEvent event) { timeline.playFromStart(); btn.setVisible(false); } }); //Add button to the root group root.getChildren().add(btn); //Add all balls to the root group for(int i=0;i<Utils.NO_OF_BALLS;i++) { root.getChildren().add(ball[i].node); } //Draw hurdles on mouse event. EventHandler<MouseEvent> addHurdle = new EventHandler<MouseEvent>(){ public void handle(MouseEvent me) { //Get mouse's x and y coordinates on the scene float dragX = (float)me.getSceneX(); float dragY = (float)me.getSceneY(); //Draw ball on this location. Set balls body type to static. Ball hurdle = new Ball(Utils.toPosX(dragX), Utils.toPosY(dragY),2,BodyType.STATIC,Color.BLUE); //Add ball to the root group root.getChildren().add(hurdle.node); } }; scene.setOnMouseDragged(addHurdle); primaryStage.setScene(scene); primaryStage.show(); } }
Utils.java
import javafx.scene.paint.Color; import javafx.scene.paint.CycleMethod; import javafx.scene.paint.LinearGradient; import javafx.scene.paint.Stop; import org.jbox2d.collision.shapes.PolygonShape; import org.jbox2d.common.Vec2; import org.jbox2d.dynamics.BodyDef; import org.jbox2d.dynamics.FixtureDef; import org.jbox2d.dynamics.World; /** * * @author dilip */ public class Utils { //Create a JBox2D world. public static final World world = new World(new Vec2(0.0f, -10.0f), true); //Screen width and height public static final int WIDTH = 800; public static final int HEIGHT = 600; //Ball radius in pixel public static final int BALL_SIZE = 8; //Total number of balls public final static int NO_OF_BALLS = 400; //Ball gradient private final static LinearGradient BALL_GRADIENT = new LinearGradient(0.0, 0.0, 1.0, 0.0, true, CycleMethod.NO_CYCLE, new Stop[] { new Stop(0, Color.WHITE), new Stop(1, Color.RED)}); //This method adds a ground to the screen. public static void addGround(float width, float height){ PolygonShape ps = new PolygonShape(); ps.setAsBox(width,height); FixtureDef fd = new FixtureDef(); fd.shape = ps; BodyDef bd = new BodyDef(); bd.position= new Vec2(0.0f,-10f); world.createBody(bd).createFixture(fd); } //This method creates a walls. public static void addWall(float posX, float posY, float width, float height){ PolygonShape ps = new PolygonShape(); ps.setAsBox(width,height); FixtureDef fd = new FixtureDef(); fd.shape = ps; fd.density = 1.0f; fd.friction = 0.3f; BodyDef bd = new BodyDef(); bd.position.set(posX, posY); Utils.world.createBody(bd).createFixture(fd); } //This gives a look and feel to balls public static LinearGradient getBallGradient(Color color){ if(color.equals(Color.RED)) return BALL_GRADIENT; else return new LinearGradient(0.0, 0.0, 1.0, 0.0, true, CycleMethod.NO_CYCLE, new Stop[] { new Stop(0, Color.WHITE), new Stop(1, color)}); } //Convert a JBox2D x coordinate to a JavaFX pixel x coordinate public static float toPixelPosX(float posX) { float x = WIDTH*posX / 100.0f; return x; } //Convert a JavaFX pixel x coordinate to a JBox2D x coordinate public static float toPosX(float posX) { float x = (posX*100.0f*1.0f)/WIDTH; return x; } //Convert a JBox2D y coordinate to a JavaFX pixel y coordinate public static float toPixelPosY(float posY) { float y = HEIGHT - (1.0f*HEIGHT) * posY / 100.0f; return y; } //Convert a JavaFX pixel y coordinate to a JBox2D y coordinate public static float toPosY(float posY) { float y = 100.0f - ((posY * 100*1.0f) /HEIGHT) ; return y; } //Convert a JBox2D width to pixel width public static float toPixelWidth(float width) { return WIDTH*width / 100.0f; } //Convert a JBox2D height to pixel height public static float toPixelHeight(float height) { return HEIGHT*height/100.0f; } }Please try this application and let me know your feedback/queries. Let me know if you find it difficult to build and run this application, I will be happy to help you.
JavaFX 2 books
Amazing, I will give a try to this library !!
ReplyDeleteThanks Seb, let me know if you need any help.
ReplyDeletegreat work
ReplyDeleteThanks doska, I am glad you liked it.
DeleteI think this is the first example using JBox2D with JavaFX on the Internet. It is Clear and excellent explanation. I tried it and everything OK. But I tried to restart (add restart button) all over again by destroying the ball and creating the ball but it not worked. I also tried to change the gravity to positive but nothing happened. I would appreciate if you kindly give me suggestion on this matter.
ReplyDeleteHi, nice examples as very few of JBOX2D examples are available over internet.
ReplyDeleteI am having some problem when using JBOX2D with java for android.In my app, i am having a ball, which is moving and colliding to other physical objects.
but now i want to move that ball according to device rotation by accelerometer. i am not being able to figure it out, how to change the balls direction or speed based on accelerometer returned values.
when i searched over net, i found some examples for Box2D(not for JBOX2D):-
public void onAccelerationChanged(final AccelerationData pAccelerationData) {
gravity = Vector2Pool.obtain(pAccelerationData.getX(), pAccelerationData.getY());
this.mPhysicsWorld.setGravity(gravity);
body.applyForce(new Vector2(-pAccelerationData.getX(), -pAccelerationData.getY()), new Vector2(body.getWorldCenter()));
Vector2Pool.recycle(gravity);
}
but i couldnt being able to do this ("Vector2Pool.recycle(gravity)") in JBOX2D. as i couldnt found any class like this "Vector2Pool".
its very urgent dude, pls help if u can
Any help is appriciated.
Hi Ankur, Gravity is a key here. As I have not explored this API on Android, I am not sure what AccelerationData returns. But I am guessing that it will return current gravity positions. If so then you can try following code.
DeleteVec2 gravity = new Vec2(pAccelerationData.getX(), pAccelerationData.getY());
world.setGravity(gravity)
Let me know if it works
Hi thank you for your helpful guide.
ReplyDeleteI'm JBox2D beginner.
I'd try to simulate this example, but it doesn't show me the balls...
Could I know what is wrong?
Actually, I copied the codes and pasted on the NetBeans.
Deleteif i add rectangular the conversion doesn't work
ReplyDeletethe image of the object is elevated from the flour and the ball junb on top of nothing