Tuesday, January 13, 2015

[Tutorial] Ball - Basic Physics in cocos2d-x

Let's start

First, create a new project using cmd

>cocos new Ball -p com.vn.Ball -l cpp -d E:/android/project

Explain a bit, the above command will create a Project named Ball in folder E:/android/project

-p com.vn.Ball is the syntax of package. You can change a bit but must have 2 dots (.) like above. 
-l cpp: is the choice of C++
-d E:/android/project: is the folder that Project saved

OK, done. As you see, Project Ball here is not different from Project HelloWorld in previous part, you can check if you don't believe ;), the structure and source file are also the same. But now we make them different, that we add physics ( temporarily called physical features) into this Ball program.

What is Physics, why do we add Physics?

Simply, Physics is to imitate the physics phenomena in game so that they can be the same as in real life. This imitation can be similar much or little upon to the idea of game, and the decision of programmers.

The basic physics you can easily regconize: Images, sound, acceleration, movement of the object, collision...
You can follow the path: E:/android/project/ball/class, open file HelloWorldScene.h. Code as follow:

#ifndef __HELLOWORLD_SCENE_H__

#define __HELLOWORLD_SCENE_H__

#include "cocos2d.h"

USING_NS_CC;

class HelloWorld : public cocos2d::Layer

{

public:

Sprite* _ball;

PhysicsWorld* m_world;

void setPhyWorld(PhysicsWorld* world){ m_world = world; };

static cocos2d::Scene* createScene();

virtual bool init(); 

virtual void onAcceleration(Acceleration* acc, Event* unused_event);

bool onContactBegin(const PhysicsContact &contact);

CREATE_FUNC(HelloWorld);

};


#endif // __HELLOWORLD_SCENE_H__

You don't edit anything, now study something strange here

Sprite* _ball; // is a pointer of Sprite type named _ball, this pointer is to manage the thing Ball in our program.

PhysicsWorld* m_world; // Pointer PhysicsWorld type named m_world, it is assigned some physical features

void setPhyWorld(PhysicsWorld* world){ m_world = world; }; //function to assign physical features for m_world,

virtual void onAcceleration(Acceleration* acc, Event* unused_event); //this function is relating to accelerator
bool onContactBegin(const PhysicsContact &contact); //This function is to discover the collision between 2 balls

Then you open HelloWorldScene.cpp (source file you can download below), you notice some in it.

In create function Scene : Scene* HelloWorld::createScene(){}

auto scene = Scene::createWithPhysics(); // This command creates a Scene attaching Physics attributes
---

auto layer = HelloWorld::create(); //Create a layer of class HelloWorld

layer->setPhyWorld(scene->getPhysicsWorld()); //set attribute Physics for m_world of object layer,

scene->getPhysicsWorld() //means get Physics of scene and then assign for m_world of layer

then, function init()

_ball = Sprite::create("Ball.jpg", Rect(0, 0, 52, 52)); // Create a ball in  a square with 52 pixel size

_ball->setPosition(Point(400,600)); //set position for the ball at 400, 600

auto ballBody = PhysicsBody::createCircle(_ball->getContentSize().width / 2); //Create the bound for body with physical attributes to discover collision, this bound with circle shape has a diameter equal to _ball size divided by 2.

ballBody->setContactTestBitmask(0x1); //This is very important, if it's not available, function onContactBegin isn't affected.

_ball->setPhysicsBody(ballBody); //Assign body for _ball

this->addChild(_ball); //Add the ball to layer HelloWorld

You can create ball2 the same as above ball.

Then, This block will create the bound of the screen, when the ball reaches, it stops, like reaches the wall ( a box )

auto edgeSp = Sprite::create();

auto boundBody = PhysicsBody::createEdgeBox(visibleSize, PHYSICSBODY_MATERIAL_DEFAULT, 3);

edgeSp->setPosition(Point(visibleSize.width / 2, visibleSize.height / 2));

edgeSp->setPhysicsBody(boundBody);

this->addChild(edgeSp);

edgeSp->setTag(0);

And then, important...

auto Listener = EventListenerPhysicsContact::create(); // This variable is to listen the physical reaction happened.

Listener->onContactBegin=CC_CALLBACK_1(HelloWorld::onContactBegin,this); //call function ontactBegin, this function will process when collision happens, this function is overloaded function.

_eventDispatcher->addEventListenerWithSceneGraphPriority(contactListener, this);

//This line is to process above Listener.

Conclusion, the above block is to discover the collision between 2 balls you created, and then call function onContactBegin to process.

And now see onContactBegin{}, its format is to be written as follow, and then we can add anything between the pairs of brackets

bool HelloWorld::onContactBegin(const PhysicsContact &contact)

{

return true;

}

Add this block to remove 2 balls when collision happens

auto ObjA = (Sprite*)contact.getShapeA()->getBody()->getNode();

auto ObjB = (Sprite*)contact.getShapeB()->getBody()->getNode();

this->removeChild(ObjB,true);

this->removeChild(ObjA,true);

Then, this function this->setAccelerometerEnabled(true); //the accelerator of the phone

Now run, you shouldn't forget this command

cocos run -s q:android/project/ball -p win32 

If you see 2 balls collide and disappear, you succeed.

Now you try removing this line ballBody->setContactTestBitmask(0x1); and you can see 2 balls collide but nothing happens.

The physics problem is now done.

Advance more a bit

Delete these line this->setAccelerometerEnabled(true); and layer->setPhyWorld(scene->getPhysicsWorld());, then delete function onAcceleration, and you can see the result not changing, the speed of falling is not changing (on Windows OS), 2 balls when colliding disappear. You can set and rotate the phone screen, you see that the balls will fall into the bottom side of screen

But when delete this line _ball->setPhysicsBody(ballBody); ball2->setPhysicsBody(ball2Body); You can see 2 balls is not moving. This function sets the ball into some weight.

And now add again 2 above commands setPhysicsBody, and add this line: scene->getPhysicsWorld()->setGravity(Vect(0.0f,-5000.0f)); You can see the ball falling very fast, Here is the place to set weight force for acceleration, if you set higher, you will see the ball falling faster.

Through this post, you can know how to set a basic Physics for program. And here are some things you should remember

auto scene = Scene::createWithPhysics(); // Create a Scene with Physics attributes ( including acceleration )

scene->getPhysicsWorld()->setGravity(Vect(0.0f,-3000.0f)); // Change acceleration, remember the mark "-"

auto ballBody = PhysicsBody::createCircle(_ball->getContentSize().width);

_ball->setPhysicsBody(ballBody);  // set physics attributes ( specially the weight and the bound of object )

ballBody->setContactTestBitmask(0x1);  // set the discovery for collision of 2 objects

// And this block is to listen to collision if any

auto contactListener = EventListenerPhysicsContact::create();

contactListener->onContactBegin = CC_CALLBACK_1(HelloWorld::onContactBegin, this);

_eventDispatcher->addEventListenerWithSceneGraphPriority(contactListener, this);

DOWNLOAD source code and Resource file



[ttaiit.blogspot.com translated]

0 comments:

Post a Comment

Choose an Android item