Monday, January 19, 2015

[Tutorial] Cocos2d-x: Create the first simple game - Discover physical collision (Part 3)

In the two previous part, we built a half of project, but the most important that need to do in this project is: kill the monsters by the bullets shot out. How to do? With previous version Engine 1.x, 2.x when building physical collision among objects is not correct, so calculation of coordinator, array, and many kinds of vectors, is very difficult. However, now in this third part, that task is very simple with only some commands. Now, let's start.

Some tasks in the third part:
+ Set physical attributes for the objects ( character, bullets and monsters )
+ Catch events that physical collisions happen.
+ Build functions to process those collision.
That's all!

Let's go!

Step 1 - Set physical attributes for objects

You open file HelloWorldScene.cpp, and do simple tasks as follow:

In function createScene(), you edit as
auto scene = Scene::createScene() thành
auto scene = Scene::createWithPhysics();
// Temporarily consider as a Scene - a zoom-out world with physical attributes contains physical objects inside.

Add the following command
// The command debug allows us to see physical body frame applying to objects ( the red border around the object)
scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);
//Set the acceleration of weight = 0, for the objects not to fall into the bottom of screen
scene->getPhysicsWorld()->setGravity(Vect(0.0f,0.0f));

1/Character

You find to the line this->addChild(player) in function init()

In that line, you add this code block:

//Create the physical body frame with circle shape
auto playerBody= PhysicsBody::createCircle(player->getContentSize().width / 2);
//Set flag = 1, to check object when collision happens
player->setTag(1);
//If you remove this command, when collision happens, nothing happens
playerBody->setContactTestBitmask(0x1);
//Set physical body into character
player->setPhysicsBody(playerBody);

2/ Monsters

You find to the line this->addChild(target); in function addTarget()

On that line, add this code block:
// Explain the same as Character part
auto targetBody = PhysicsBody::createCircle(target->getContentSize().width / 2);
target->setTag(2);
targetBody->setContactTestBitmask(0x1);
target->setPhysicsBody(targetBody);

3/ Bullet

In function onTouchEnded you find the line projectile->setPosition( Point(20, winSize.height/2) );, 

Add below that the following block, the explanation as the two above parts

auto projectileBody = PhysicsBody::createCircle(projectile->getContentSize().width / 2);
projectile->setTag(3);
projectileBody->setContactTestBitmask(0x1);
projectile->setPhysicsBody(projectileBody);

Done for building physical body.

Step 2 - Catch collision events among objects

To catch these collision events, we also create a listener to listen to collision, then pass the function to process collision through a dispatcher, as following code:

Before the line return true; of function init() add the following code block:

//Create an object to listen to collision if happenning
auto contactListener = EventListenerPhysicsContact::create();
//When collision happens, call function onContactBegin to process it, notice the line CC_CALLBACK_1, in some documents is CC_CALLBACK_2 will show the message not running.
contactListener->onContactBegin = CC_CALLBACK_1(HelloWorld::onContactBegin, this);
//the Dispatcher connects to the object that catches collision
_eventDispatcher->addEventListenerWithSceneGraphPriority(contactListener, this);

you notice the variable _eventDispatcher, this variable has two special points
+ has not declared anywhere ( even in header file HelloWorldScene.h) 
+ has the character underscore(_) at the beginning

That is the special variable available belongs to the class Dispatcher in library, so using it is completely normal. If not use, you must declare the other with the same function. Notice the variables with the underscore at beginning, usually is the variables pre-defined in class.

Step 3 - The function to process collision

In file HelloWorldScene.h add a prototype function 

//You must declare exactly ( because here is the declaration override on the parent class)
bool onContactBegin(const PhysicsContact& contact);

Then we must define that function in HelloWorldScene.cpp as follow:

bool HelloWorld::onContactBegin(const PhysicsContact& contact)
{
//Get the first collided object, casting to Sprite*
auto bullet = (Sprite*)contact.getShapeA()->getBody()->getNode();
//Get the flag value to check which object ( bullet, monsters, or character )
int tag = bullet->getTag();

//Get the second collided object, casting to Sprite*
auto target = (Sprite*)contact.getShapeB()->getBody()->getNode();
//Get the flag value to check which object ( bullet, monsters, or character )
int tag1 = target->getTag();
//If collision happens between bullet and monster, processing deletes both bullet and monster from Layer in Scene ( disappear from screen )
if((tag==2&tag1==3)||(tag==3&tag1==2))
    {

this->removeChild(bullet,true); // Delete bullet

this->removeChild(target,true); // Delete monster
}
// If collision happens between monster and character, character will die and GameOver, and then calculate scores but not process that now.
if((tag==1&tag1==2)||(tag==2&tag1==1))
        {
// process GameOver
// calculate scores
}
    return true; // must return true
}

Done, now build, run and view the result.
But there are errors, although Code is correct




You must add into file HelloWorldScene.h the following line:

USING_NS_CC; ( you copy into under the line #include "cocos2d.h" in HelloWorldScene.h)

And here is the result now



Stop the 11th lesson here. Now we know how to:

+ create a Scene containing object that can reaction with physics
+ create physical body for objects
+ catch collision event by Listener Physics
+ build the function to process colliion onContactBegin

Download source file.


0 comments:

Post a Comment

Choose an Android item