Thursday 29 December 2011

JBox2D With JavaFX : Write your first JBox2D with JavaFX 2 program

So far we have learned about JBox2D world, Bodies and world Simulation. With this we are ready to try our hands on JBox2D.

Today we will write one simple JBox2D application. In this application we will create one bouncy ball and release it into the JBox2D world. We will use JavaFX 2 for UI.

Our first step is to create JavaFX project. We will use NetBeans 7.1 for this. If you have not installed JavaFX SDK and NetBeans then you can download and install it form here. Once installed, open NetBeans IDE and follow the following steps

Click on File>New Project… menu. This will open “New Project” dialog box.
Select “JavaFX” under categories and then select JavaFX Application under projects
Click on “Next“ button.

In next window, type project name as “BouncyBallApp”.
Select project location.
Select “Create Application class” checkbox.
Select “Set as main project”
Click on finish.


This will create a project with main class “BouncyBallApp.java”

We will create two more class in this project – Utility.java and BouncyBall.java

Utility.Java – We will add all required constants and utility methods to this class.

We will add following constants to the Utility.java class
//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 = 600;
    public static final int HEIGHT = 600;
    
    //Ball radius in pixel
    public static final int BALL_RADIUS = 8;


We will add method “addGround” to Utility class. This method will help us to add ground/platform for our JBox2D world. Ground is an essential component of our application. This is where our bouncy ball will land and bounce back. If we do not add ground ball will move infinitely downwards.

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

As you can see we are using polygon shape for creating the ground. I will cover JBox2D shapes in detail in future post.

Next we will add method “addWall” to utility class. This method will allow us to add walls to our JBox2D world. Walls are required because we don’t want our bouncy ball to go outside the application viewable area.
//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);
}

Next we will add few utility methods which will allow us to convert JBox2D world coordinates to pixel coordinates and vise versa.
//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;
}


BouncyBall.java – Now we will create main actor of our application i.e. bouncy ball. First we will add class called as BouncyBall.java. We will add following attributes to this class.
//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;

Then we will add method “private Node create()” to this class. The return type of method is set to javafx.scene.Node. We will use this method to create a ball. To create ball we will have to:

Create graphical representation of the ball and set its x,y position
//Create an UI for ball - JavaFX code
        Circle ball = new Circle();
        ball.setRadius(radius);
        ball.setFill(color); //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));

Create body definition of the ball i.e. ball body type (Dynamic in this case) & body position
//Create an JBox2D body defination for ball.
        BodyDef bd = new BodyDef();
        bd.type = BodyType.DYNAMIC;
        bd.position.set(posX, posY);

Create ball shape
CircleShape cs = new CircleShape();
        cs.m_radius = radius * 0.1f;  //We need to convert radius to JBox2D equivalent

Create fixture for ball
// Create a fixture for ball
        FixtureDef fd = new FixtureDef();
        fd.shape = cs;
        fd.density = 0.6f;
        fd.friction = 0.3f;        
        fd.restitution = 0.8f;
And finally we will create body, associate it with its graphical representation and return it.
/**
        * 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;

We will call this method from class constructor.
public BouncyBall(float posX, float posY, int radius, Color color){
        this.posX = posX;
        this.posY = posY;
        this.radius = radius;
        this.color = color;
        node = create();
    }

Finally BouncyBall.java should look like this:

package bouncyballapp;

import javafx.scene.Node;
import javafx.scene.paint.Color;
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 BouncyBall{

    //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;
    
   
    private Color color;
    public BouncyBall(float posX, float posY, int radius, Color color){
        this.posX = posX;
        this.posY = posY;
        this.radius = radius;
        this.color = 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(color); //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));
       
        //Create an JBox2D body defination for ball.
        BodyDef bd = new BodyDef();
        bd.type = BodyType.DYNAMIC;
        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.6f;
        fd.friction = 0.3f;        
        fd.restitution = 0.8f;

        /**
        * 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;
    }
    
}


Our final step is to modify main class i.e. BouncyBallApp.java class.

We will have to do following changes to “start()” method.

Set application title and application window size. Also set full screen and resizable properties to false so user will not be able to resize application window.
primaryStage.setTitle("Bouncy Ball");
        primaryStage.setFullScreen(false);
        primaryStage.setResizable(false);
        Group root = new Group(); //Create a group for holding all objects on the screen
        Scene scene = new Scene(root, Utils.WIDTH, Utils.HEIGHT);

Add ball, ground and walls
//create ball   
        final BouncyBall ball = new BouncyBall(45, 90, Utils.BALL_RADIUS, Color.RED);
         
        //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

Add code for simulating the world.
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
                        Body body = (Body)ball.node.getUserData();
                        float xpos = Utils.toPixelPosX(body.getPosition().x);
                        float ypos = Utils.toPixelPosY(body.getPosition().y);
                        ball.node.setLayoutX(xpos);
                        ball.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);

Add code to start simulating the world on click of the button
//Create button to start simulation.
        final Button btn = new Button();
        btn.setLayoutX((Utils.WIDTH/2) -15);
        btn.setLayoutY((Utils.HEIGHT-30));
        btn.setText("Start");
        btn.setOnAction(new EventHandler<actionevent>() {
            public void handle(ActionEvent event) {
                        timeline.playFromStart(); 
                        btn.setVisible(false);
            }
        });

Finally add button and ball to the root group
root.getChildren().add(btn);
        root.getChildren().add(ball.node);
        primaryStage.setScene(scene);
        primaryStage.show();


Finally hit the “F6” to run the application.

<<Simulating JBox2D world                         Applying Force and Impulse on body>>

Wednesday 21 December 2011

JBox2D Tutorial : Simulating JBox2D world

In previous post we have learned how to create JBox2D world. We also learned how to create bodies and add them to the world. Now next step is to simulate the JBox2D world.

To simulate the world, we need to call step method of the world.

float timeStep = 1.0f / 60.f;
int velocityIterations = 6;
int positionIterations = 2;

for (int i = 0; i < 60; ++i) {
world.step(timeStep, velocityIterations, positionIterations);
      Vec2 position = body.getPosition();
      float angle = body.getAngle();
      System.out.printf("%4.2f %4.2f %4.2f\n", position.x, position.y, angle);
}
As you can see in above snippet, we are passing three arguments to the world.step

timeStep - This defines how much simulation should advance in one second. In above example simulation will advance by 1/60th second on every call to the step method.

velocityIterations – This define how accurately velocity will be simulated. Higher iteration value increases the accuracy of velocity simulation but decreases the performance. The recommended velocity iteration value is 6.

 positionIterations – This is similar to velocity iteration, higher value means more accurate position simulation but lesser performance. The recommended position iteration value is 3.

In above sample code snippet on every simulation step we are getting body’s new position and angle details and printing them to the console. So far we have learned about world, bodies and world simulation. In next post we will write our first JBox2D program with JavaFX 2.0

<<Creating Body                                      Writing first JBox2D program>>

Monday 19 December 2011

JBox2D Tutorial : Creating an object body

In last post we have learned how to create the JBox2D WorldNow our next step will be to create an object body and add it to the world. 

To create bodies in JBox2D world we need to first create:

  • Body definition
  • Body shape and
  • Body fixtures.


Body Definition

Body definition is created as below.

BodyDef bd = new BodyDef();
bd.position.set(50, 50);  
bd.type = BodyType.DYNAMIC;

Main properties of the body definition are

  • Position - position of the body in JBox2d world i.e. x and y coordinates.
  • Body type – type of the 
Body can be static, dynamic or kinematic.


Static Body

  • Static bodies have zero velocity.
  • Static bodies do not move under simulations.
  • Static bodies can be moved manually by user.
  • Static bodies have infinite mass.
  • Static bodies do not collide with other static and kinematic bodies.
  • Examples - Ground, Walls.


Dynamic Body –

  • Dynamic bodies move under simulation.
  • Dynamic bodies respond to the forces and they move accordingly.
  • Dynamic bodies can be moved manually.
  • Dynamic bodies always have non-zero mass. If mass is set to zero then it acquires 1Kg mass.
  • Dynamic bodies collide with dynamic, kinematic and static body types.
  • Examples – Ball, Box,


Kinematic Body –

  • Under simulation, kinematic bodies move according to its velocity.
  • Kinematic bodies do not move according to forces.
  • Kinematic bodies can be moved manually by user.
  • Kinematic bodies have infinite mass.
  • Kinematic bodies do not collide with static or kinematic bodies.
  • Kinematic body’s movement does not get affected by gravity.
  • Kinematic body’s movement does not get affected when dynamic bodies are collided with it.
  • Example – moving platforms in games.


Body Shape

Next we need to define the body shape. JBox2D support Circle shape, Polygon Shape, Edge Shape and Chain Shape. We will discuss each shape in details in future tutorials.

Following code snippet shows how to create a circle shape.

CircleShape cs = new CircleShape();
cs.m_radius = 0.5f;  

Fixtures

Fixture defines the material properties of the body. Fixtures are also used for attaching shape to the body. These material properties describe how two bodies should react when they collide with each other.

FixtureDef fd = new FixtureDef();
fd.shape = cs;
fd.density = 0.5f;
fd.friction = 0.3f;        
fd.restitution = 0.5f;

Density – This defines the heaviness of the body with respect to its area.

Friction - This defines how bodies slide when they come in contact with each other. Friction value can be set between 0 and 1. Lower value means more slippery bodies.

Restitution – This define how bouncy is the body. Restitution values can be set between 0 and 1. Here higher value means more bouncy body.

There are some more properties of fixture, will cover them in future post.

Creating body

Now final step is to create a body and add fixture to it. The bodies are created using World class.

Body body =  world.createBody(bd);
body.createFixture(fd);

The complete code snippet would look like:
//body definition
BodyDef bd = new BodyDef();
bd.position.set(50, 50);  
bd.type = BodyType.DYNAMIC;

//define shape of the body.
CircleShape cs = new CircleShape();
cs.m_radius = 0.5f;  

//define fixture of the body.
FixtureDef fd = new FixtureDef();
fd.shape = cs;
fd.density = 0.5f;
fd.friction = 0.3f;        
fd.restitution = 0.5f;

//create the body and add fixture to it
Body body =  world.createBody(bd);
body.createFixture(fd);
In next post we will learn how to simulate the JBox2D World.

<<JBox2D World                                                Simulating the JBox2D world>>

Tuesday 13 December 2011

JBox2D Tutorial : JBox2D World


From today I am starting JBox2D tutorial series. In each post I will explain few features of the JBox2D.  I will try to keep each post small and simple.

In today’s post I will explain how to create the JBox2D world.

What is a JBox2D?

JBox2D is a java based physics engine API for game development. This is a java port for a very popular C++ library called Box2d.  This can be used in games to move objects in a natural way. JBox2D works well with moving objects between 0.1 to 1 meters size.  Jbox2D doesn’t have its own UI. It creates an invisible object. We need to attach UI components to these invisible objects. 
             
Creating the JBox2D World

To write any JBox2D program, the first thing we need to do is to create a JBox2d world. World is a collection of bodies, fixtures and constraints. Memory, objects and simulations are managed by the World.

Following is a code snippet for creating a JBox2D World

Vec2 gravity = new Vec2(0.0f, -10.0f);
boolean doSleep = true;
World world = new World(gravity, doSleep);

As you can see in above code snippet, two parameters (Gravity and the doSleep) are passed to the World objects constructor. 

Gravity – gravity is an attraction of the mass for bodies present in the World. As you can see in above snippet, Vec2 object is used for defining the gravity. The first parameter defines the horizontal gravity and second parameter defines the vertical gravity.  In most cases first parameter is set to zero as requirement for horizontal gravity is very rare. If negative value is set for the second parameter then bodies are attracted downwards. And if positive value is set for the second parameter then bodies are attracted upwards.  In most cases negative value is set to the second parameter

doSleep – If doSleep is set to true, JBox2d world will allow bodies to sleep when they come to rest. The sleeping bodies are not part of simulations; it means better performance as body simulations are expensive. In most cases this parameter should be set to true.

I have created small application to understand gravity behavior.  This is the sample video.


Soon I will provide launch URL for this application.  


                                                                              Creating an object body>>