Pixel Perfect Collision Detection


#1

Hello everyone,
I am trying to port the pixel perfect collision detection in Cocos2d-x the original version was made for Cocos2D and can be found here: http://www.cocos2d-iphone.org/forums/topic/pixel-perfect-collision-detection-using-color-blending/

Here is my code for the Cocos2d-x version

bool CollisionDetection::areTheSpritesColliding(cocos2d::CCSprite *spr1, cocos2d::CCSprite *spr2, bool pp, CCRenderTexture* _rt) {
    bool isColliding = false;
    CCRect intersection;
    CCRect r1 = spr1->boundingBox();
    CCRect r2 = spr2->boundingBox();
    intersection = CCRectMake(fmax(r1.getMinX(),r2.getMinX()), fmax( r1.getMinY(), r2.getMinY()) ,0,0);
    intersection.size.width = fmin(r1.getMaxX(), r2.getMaxX() - intersection.getMinX());
    intersection.size.height = fmin(r1.getMaxY(), r2.getMaxY() - intersection.getMinY());

    // Look for simple bounding box collision
    if ( (intersection.size.width>0) && (intersection.size.height>0) ) {
        // If we're not checking for pixel perfect collisions, return true
        if (!pp) {
            return true;
        }

        unsigned int x = intersection.origin.x;
        unsigned int y = intersection.origin.y;
        unsigned int w = intersection.size.width;
        unsigned int h = intersection.size.height;
        unsigned int numPixels = w * h;
        //CCLog("Intersection X and Y %d, %d", x, y);
        //CCLog("Number of pixels %d", numPixels);

        // Draw into the RenderTexture
        _rt->beginWithClear( 0, 0, 0, 0);

        // Render both sprites: first one in RED and second one in GREEN
        glColorMask(1, 0, 0, 1);
        spr1->visit();
        glColorMask(0, 1, 0, 1);
        spr2->visit();
        glColorMask(1, 1, 1, 1);

        // Get color values of intersection area
        ccColor4B *buffer = (ccColor4B *)malloc( sizeof(ccColor4B) * numPixels );
        glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buffer);

        _rt->end();

        // Read buffer
        unsigned int step = 1;
        for(unsigned int i=0; i 0 && color.g > 0) {
                isColliding = true;
                break;
            }
        }

        // Free buffer memory
        free(buffer);
    }


    return isColliding;
}

My code is working perfectly if I send the “pp” parameter as false. That is if I do only a bounding box collision but I am not able to get it working correctly for the case when I need Pixel Perfect collision.
I think the opengl masking code is not working as I intended.

Here is the code for “*rt”
<pre>
*rt = CCRenderTexture::create(visibleSize.width, visibleSize.height);
*rt~~>setPosition);
this~~>addChild;
*rt->setVisible(true); //For testing

I think I am making a mistake with the implementation of this CCRenderTexture

Can anyone guide me with what I am doing wrong ?

Thank you for your time :slight_smile:


Pixel Perfect Collision Detection cocos2d-x v3
RenderTexture / Pixel perfect collision with Cocos2d 3.3
Pixel perfect touch or how to determine if a pixel of a sprite is transparent
#2

BUMP! Any help please :slight_smile:


#3

I finally figured out how to solve this.

Information with source code can be found in my blog post, any other doubts please throw it at me
http://blog.muditjaju.infiniteeurekas.in/?p=1


#4

This is awesome, Mudit~ :slight_smile:


#5

anytime :slight_smile: happy to help! :smiley:


#6

hi,Mudit!
http://blog.muditjaju.infiniteeurekas.in/?p=1
how can i get the SolidColorShader.fsh and SolidVertexShader.vsh?


#7

i have slove that problem,because i use the errror path.
it is a useful method, thank you:)


#8

please help me out in pixel perfect collision its not reading SolidColorShader.fsh and SolidVertexShader.vsh showing error in the console ;
“Cocos2d: Get data from file(SolidVertexShader.vsh) failed!”


#9

maheshit: I did experienced this problem, and solved it using absolute path instead of relative path, something not so portable.

However, after been able to load shader files, my trouble is that when the to sprites collide, they get shrunk.

Am I doing something wrong?

Any help would be appreciated.


#10

Hey,

I’ve been using you code for pixel perfect collision and it seems to have a problem where it sometimes works and sometimes crashes specifically on the call to glReadPixels. I noticed there was a comment on your blog post that had the same problem but no solution ? I’m using cocos2dx 2.2.3 with android

Any help would be appreciated thanks


#11

I’m having trouble too, for some reason it doesn’t work properly.
Can someone upload a sample project which uses this method?
I really want to use this in my game.

Thanks! :slight_smile:


#12

Thanks! I really need in such function, and I’ve added these 4 files in my project. But code is working strange, looks like REAL size of sprites more than displayed size. And after adding “CollisionDetection::GetInstance()->areTheSpritesColliding(….)” moving of my sprites working very strange.
I Use x-code and cocos2d-x v3 version (from GitHub)


#13

Who know how to solve this problem? Or may be there is other completed solution?


#14

Hi all,

Here’s a simple solution for pixel perfect detection. It should be enough to get you starting if you need something more complex.


#15

Hello,

I also posted a few months ago my own implementation:

Any feedback is appreciated.


#16

Hi, @happybirthday
I just checked your blog, and I wanted to implement my own version. Because, in my case there are no sprites, and only DrawNodes, and it seems like your version is for older Cocos2d-x.
http://blog.muditjaju.infiniteeurekas.in/?p=1

I want to ask few questions. You made the secondary buffer(_rt) invisible. Why?
glReadPixels seems to read only the pixels of showing frame buffer. So, I think it’s impossible to read the pixels of invisible nodes.
Actually, I thought it reads current buffer, and if we call glReadPixels, between _rt->beginWithClear( 0, 0, 0, 0); and _rt->end(); it returns the pixels of _rt even it’s invisible.
But, it seems it doesn’t work that way. It still returns the pixels of main frame buffer(visible screen).

Can you help me out? Thanks.


#17

Oh, I got it. In Cocos2d-x 3.x, visit() seems asynchronous.
So, I had to call Director::getInstance()->getRenderer()->render(); before glReadPixels.


#18

Hi ahlwong ,

Please tell me where I’m wrong in using your class for detecting pixel perfect collision.

I created HitDetectHelper.h and HitDetectHelper.cpp file in my project.

Then I copy and past code from http://alexanderwong.me/post/108850552513/cocos2d-x-3-x-pixel-perfect-hit-detection to HitDetectHelper.h and HitDetectHelper.cpp file.

Then I call hitTest function in my game class to check the pixel perfect collision like this

if (HitDetectHelper::hitTest(PlaneSprite, Point(topFloorSprite->getPosition().x, topFloorSprite->getPosition().y)))
{
showBlast();
}

But no collision is detected.

If I’m wrong please tell me how to use your solution for pixel perfect detection.


#19

the Point you pass into the method should be a point local to the Sprite you’re testing (a point relative to the sprite itself).

So, in your example, you’d want to do something like:

Point globalPoint = topFloorSprite->getParent()->convertToWorldSpace(topFloorSprite->getPosition());
Point testPoint = PlaneSprite->convertToNodeSpace(worldPoint);

if (HitDetectHelper::hitTest(PlaneSprite, testPoint))
{
showBlast();
}


#20

Hello ahlwong ,

Thanks for your reply.

I’m using the following code to detect collision between 2 sprite.

Point globalPoint = topFloorSprite->getParent()->convertToWorldSpace(topFloorSprite->getPosition());
//Point testPoint = PlaneSprite->convertToNodeSpace(worldPoint);
Point testPoint = PlaneSprite->convertToNodeSpace(globalPoint );

if (HitDetectHelper::hitTest(PlaneSprite, testPoint))
{
showBlast();
}

Above code is showing the collision only when the mid point of PlaneSprite and mid point of topFloorSprite collides.

I want the collision like as shown in the below image.

Why

How can I achieve this kind of collision ?