Saturday, January 24, 2015

[Tutorial] Cocos2d-x: Box2D - another physics library of cocos2d-x (Part 1)

Filled under: ,

Now, you study how to use Box2D in Cocos2d-x. By default, Cocos2d-x is installed for users to use the library of Cocos2d-x + Chipmunk, if you want to use Box2D, you must do some task to import it into the compiler.

In this lesson, you study:
+ How to setup to use Box2D
+ An example of physic, applying Box2D physic

Bắt đầu chém nào!

Step 1 - Setup to use Box2D

Because by default, Cocos2d-x forces you to use Chipmunk, so you must do some following tasks:
1/ Open file CMakeLists.txt in Project  ( using NotePad++ to display line number ). Find to line number 162, and add "Box2D" as below:


(After adding box2d)

2/ Open file physics.sln ( physics is the name of Project ) by VS2012 as following path physics\proj.win32\physics.sln, 

- Notice the left, there are only three basic libraries that are already IMPORTED: Audio, Chipmunk, Cocos2d

Do the following steps:

*  FILE -> Add -> Existing Project

Notice the path below when choosing Box2D project ( it is in the path: physics\cocos2d\external\Box2D\proj.win32\Box2D.vcxproj )

Here is the result. Imported already, but you haven't used yet now, you must do two more steps:

Right click Project ( physics) choose Project Dependencies, check Box2D option

* Right click Project physics, choose References, it displays project Properties Page, Click the button Add New References, and tick Box2D, it's done now!

* Finally you must SAVE thisi Solution by Ctrl + S, check the last step: open file physics.vcxproj in the following path: physics\proj.win32\physics.vcxproj

If you see this following line, it means that Box2D is available in Project Physics, you search "Box2D"

If search not found Box2D in this file, it means that you import incorrect ( maybe you haven't SAVE solution in VS2012 ). Do again the above steps *, OK.

When you need to import some library, you also do as the above way.

Step 2 - A small physics practice

Create a new Project named Box2Dtest, ( you shouldn't name project - Box2D, because you will not import Box2D into VS)

>cocos new Box2Dtest -p -l cpp -d E/:android/project

Open file HelloWorldScene.h, do the following tasks:
+ Add #include "Box2D/Box2D.h" in #include area
+ Add the following code block in Public area:

b2World *world; // World with physic
b2Body *ballBody ; // Body of the ball
b2BodyDef bodyDef; // Define the above Body
b2FixtureDef fixtureDef; // Define some static features: friction, restitution, density, etc.
b2CircleShape bodyShape; // the shape of body

Sprite *ball; // Ball shape
float deltaTime; // The variable to calculate time

void addWall(float w,float h,float px,float py); // Create the Wall edge around the screen for the ball to collide with.

void update(float dt); // Update scene by time

Open file HelloWorldScene.cpp, do the following tasks:
+ Add #define SCALE_RATIO 32.0 ( because Box2D uses the unit "mm", so you must have the factor to convert from pixel to mm)
+ In init() function, delete from the line this->addChild(label, 1); to the line return true; then add the following block

b2Vec2 gravity = b2Vec2(0.0f,-10.0f); // Vector of acceleration ( the mark "-" is for down direction, because the y axis is upwards )

world = new b2World(gravity); // Create world with vector of acceleration

    // Create a ball Sprite
    ball = Sprite::create("ball.png");

    // Set the position in the center of the screen
    ball->setPosition(Point(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));

// This block is the most important to apply body in Box2D

//---------------------physics body in BOX2D--------------------

bodyShape.m_radius = 45 / SCALE_RATIO; // The radius of body

fixtureDef.shape=&bodyShape; // point to bodyShape

bodyDef.type = b2_dynamicBody; // Dynamic collision
bodyDef.userData = ball; // Attach to Sprite ball

// Set position, and remember to convert the unit

ballBody = world->CreateBody(&bodyDef); // Create Body
ballBody->CreateFixture(&fixtureDef); // Create static features
ballBody->SetGravityScale(10); // Set the ratio for acceleration, more higher more faster to fall


    // Place the ball into layer of Scene
    this->addChild(ball, 0);

scheduleUpdate(); // Update again the scene by time

+ Building the function update(float dt) as follow:

void HelloWorld::update(float dt){
   int positionIterations = 10;  // Location
   int velocityIterations = 10; // Velocity

   deltaTime = dt; // Time step

// Simulate the physical movement by time, study here and here

// Each Step happens in dt seconds , this dt in file AppDelegate.cpp is defined by command director->setAnimationInterval(1.0 / 60); you try replacing 1/60 = 1/1 , it falls very slow

   world->Step(dt, velocityIterations, positionIterations);  

// Navigate all bodies of world
   for (b2Body *body = world->GetBodyList(); body != NULL; body = body->GetNext())   
// Consider which body is attached to Sprite
     if (body->GetUserData()) 

       // return the ball sprite 
       Sprite *sprite = (Sprite *) body->GetUserData();  
// Set the position again for this Sprite follow the position of body ( body is gradually falling by time), remember to multiply with RATIO to convert into pixel
       sprite->setPosition(Point(body->GetPosition().x * SCALE_RATIO,body->GetPosition().y * SCALE_RATIO));  
      // Set the rotation ability
       sprite->setRotation(-1 * CC_RADIANS_TO_DEGREES(body->GetAngle())); 

    world->ClearForces(); // Clear forces of Body
    world->DrawDebugData();  // Draw shapes to check collision in debug mode

Build and run, if you see the ball falls into the bottom of the screen, you are successful. Congratulation!

Notices in Box2D

+ There must be a function with input param that is time, here is update (float dt)
+ When attaching body into sprite, the position of sprite always depends on the position of body
+ The way to convert rate, here we have two coordinate system: the coordinate of the screen, and the coordinate of Box2D. Remember the following:

- When setting position, size for objects, or components of Box2D (body, shape)  if the input param is the coordinate of screen, you must divide by the scale ratio ( "/SCALE_RATIO" ), i.e:


- On the contrary, when setting position, size for objects, or components of the screen  ( sprite, label, etc.) if the input param is the coordinate of  Box2D, you must multiply with the (*SCALE_RATIO),i.e:

  sprite->setPosition(Point(body->GetPosition().x * SCALE_RATIO,body->GetPosition().y * SCALE_RATIO));  

[ translated]


Post a Comment

Choose an Android item