LoginSignup
30
29

More than 5 years have passed since last update.

透過画像に対応したコリジョン判定

Posted at

物理エンジンを使用しない場合、コリジョン判定(当たり判定)はスプライトの矩形で行うことが多いと思います。これを透過画像の透過部分を当たり判定に含めない方法を紹介します。

HelloWorld::areSpritesColliding メソッドでは、指定した2つのスプライトが透過部分を除いて重なっていれば、true を返します。スプライト同士の当たり判定に使用できます。

HelloWorld::collideAtPoint メソッドでは、指定したスプライトと指定した座標が透過していないピクセルなら true を返します。タップした場所に画像がある(透過されていない)か判定する場合に使用できます。

CCLayer クラスで実装していますが、少し改良して CCSpirte を拡張したクラスを作成して、使用するとよいかもしれません。

HelloWorld.cpp
bool HelloWorld::areSpritesColliding(cocos2d::CCSprite *spr1, cocos2d::CCSprite *spr2, bool pp) {
    bool isColliding = false;
    CCRect intersection;
    CCRect r1 = spr1->boundingBox();
    CCRect r2 = spr2->boundingBox();

    // Look for simple bounding box collision
    if (r1.intersectsRect(r2)) {
        // If we're not checking for pixel perfect collisions, return true
        if (!pp) {
            return true;
        }
        CCLOG("Bounding Box Collision");

        float tempX;
        float tempY;
        float tempWidth;
        float tempHeight;

        if (r1.getMaxX() > r2.getMinX()) {
            tempX = r2.getMinX();
            tempWidth = r1.getMaxX() - r2.getMinX();
        } else {
            tempX = r1.getMinX();
            tempWidth = r2.getMaxX() - r1.getMinX();
        }

        if (r1.getMinY() < r2.getMaxY()) {
            tempY = r1.getMinY();
            tempHeight = r2.getMaxY() - r1.getMinY();
        } else {
            tempY = r2.getMinY();
            tempHeight = r1.getMaxY() - r2.getMinY();
        }

        intersection = CCRectMake(tempX * CC_CONTENT_SCALE_FACTOR(), tempY  * CC_CONTENT_SCALE_FACTOR(), tempWidth * CC_CONTENT_SCALE_FACTOR(), tempHeight * CC_CONTENT_SCALE_FACTOR());

        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;

        if (numPixels<=0) return false;

        // Draw into the RenderTexture
        CCSize size = CCDirector::sharedDirector()->getWinSize();
        CCRenderTexture *rt = CCRenderTexture::create(size.width, size.height, kCCTexture2DPixelFormat_RGBA8888);
        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<numPixels; i+=step) {
            ccColor4B color = buffer[i];
            CCLOG("Pixel color: %d, %d, %d", color.r, color.g, color.b);
            if (color.r > 0 && color.g > 0) {
                isColliding = true;
                CCLOG("Colliding");
                break;
            }
        }

        // Free buffer memory
        free(buffer);
    }

    return isColliding;
}

bool HelloWorld::collideAtPoint(cocos2d::CCSprite* pSprite, cocos2d::CCPoint point) {
    bool bCollision = false;

    int searchWidth = 1;
    int searchHeight = 1;

    unsigned int numPixels = searchWidth * searchHeight;

    CCSize size = CCDirector::sharedDirector()->getWinSize();
    CCRenderTexture *rt = CCRenderTexture::create(size.width, size.height, kCCTexture2DPixelFormat_RGBA8888);
    rt->beginWithClear(0, 0, 0, 0);

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

    // Get color values of intersection area
    ccColor4B *buffer = (ccColor4B *)malloc( sizeof(ccColor4B) * numPixels );
    glReadPixels(point.x, point.y, searchWidth, searchHeight, GL_RGBA, GL_UNSIGNED_BYTE, buffer);

    unsigned int step = 1;
    for(unsigned int i=0; i<numPixels; i+=step) {
        ccColor4B color = buffer[i];
        //CCLog("Pixel color: %d, %d, %d", color.r, color.g, color.b);
        if (color.r > 0) {
            bCollision = true;
            CCLOG("Colliding");
            break;
        }
    }

    rt->end();

    return bCollision;

}
30
29
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
30
29