Showing posts with label JBox2D. Show all posts
Showing posts with label JBox2D. Show all posts

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>>


Wednesday, 30 November 2011

Hello World JBox2D with JavaFX 2.0

<<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.






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. 

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


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