Developers Manual > Cocos2d-x > How To > User Contributed Tutorials > User Tutorial-Accurate Hit Testing

Accurate hit testing with Cocos2d-x 3.0 integrated physics feature

Contributed By: xhcnb

Cocos2d-x 3.0 version has an integrated physics feature based on chipmunk. It's very easy to make accurate hit testing in our cocos2d-x game.

Source code at github/xhcnb/accurate_hit_testing_cocos2d_x_3_0

create bodies.json

How to run?

Clone source code, android copy cocos2d-x 3.0 version files under cocos2d, the project looks like:

create bodies.json

open proj.ios_mac/PhysicsDemo.xcodeproj to build for ios or mac

run proj.android/build_native.py to build for android.
I have put prbuilt files under prebuilt编译好的, please checkout and test.

Basic principle

There is an open source body editor https://code.google.com/p/box2d-editor/ , with this free&powerful tool we can get physicsbody polygons of an sprite. Then we import the polygons data into game and let the physics engine handle the rest thing.
All we need is to write an parse function which can load file exported by [box2d-editor] to cocos2d-x physics system.

Here we go.

1.create new project:

cocos new  -p com.example.phy -l cpp -d ~/Documents PhysicsDemo

2.open the new project in xcode(I use xcode, chose your favorite IDE)

open ~/Documents/PhysicsDemo/proj.ios_mac/PhysicsDemo.xcodeproj

3.make an image for test, I have downloaded the cocos2d-x logo from

http://www.cocos2d-x.org/wiki/Logo_Resources_of_Cocos2d-x

name it as 2dx.png, add the image to project.

4.download box2d-editor

https://code.google.com/p/box2d-editor/

get a jar file, open it.

Node: please use JRE6 to run it.

5.get the body data

open the editor, create one new project, name bodies.json and save under the project's Resource.
create bodies.json
Don't forget addbodies.json to project.

Create new body definition, name it 2dx.
create bodies.json
create bodies.json
create bodies.json

Use Auto-trace to get the image edge.
create bodies.json
create bodies.json

Save bodies.json
create bodies.json

Next, we should write some code to import bodies.json.

6.modify our scene

Edit method HelloWorld::createScene to enable physics feature.

1
2
3
    auto scene = Scene::createWithPhysics();
    //enable debug draw
    scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);

Add our sprite to the layer:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
        // add "2dx.png"
        sp_2dx = Sprite::create("2dx.png");
        // position the sprite on the center of the screen
        sp_2dx->setPosition(Point(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));
        //load
        MyBodyParser::getInstance()->parseJsonFile("bodies.json");
        //bind physicsbody to sprite
        auto _body = MyBodyParser::getInstance()->bodyFormJson(sp_2dx, "2dx");
        if (_body != nullptr) {
            _body->setDynamic(false); //set it static body.
            _body->setCollisionBitmask(0x000000); //don't collision with anybody.
            sp_2dx->setPhysicsBody(_body);
        }
        // add the sprite as a child to this layer
        this->addChild(sp_2dx, 0);

MyBodyParser is the helper class to load bodies.json, use rapidjson.
You can check the detailes in source code, key function is MyBodyParser::bodyFormJson.

Then, add touchListener, this's simple and nothing interesting to waste words.

7.check whether our sprite is clicked

In function HelloWorld::nodeUnderTouch:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    Node* HelloWorld::nodeUnderTouch(cocos2d::Touch *touch)
    {
        Node* node = nullptr;
        //translate the touch to layer coordinate.
        auto location = this->convertTouchToNodeSpace(touch);

        //retrive all physics shapes under the touch location though cocos2d-x.
        auto scene = Director::getInstance()->getRunningScene();
        auto arr = scene->getPhysicsWorld()->getShapes(location);

        //iterate the shapes, find our sprite!
        for (auto& obj : arr)
        {
            //find it!!!!
            if ( obj->getBody()->getNode() == sp_2dx)
            {
                node = obj->getBody()->getNode();
                break;
            }
        }
        return node;
    }

If this function return nullptr, means you havn't touch inside the Sprite's physics body.

This's all the magic, Checkout the source code and read more.

Sign up for our newsletter to keep up with the latest developments, releases and updates for Cocos2d-x.