Pixel Perfect Collision Detection (Using Cocos2d-x)

CollisionDetection.h




//
//  CollisionDetection.h
//  Created by Mudit Jaju on 30/08/13.
//
//  SINGLETON class for checking Pixel Based Collision Detection

#ifndef __CollisionDetection__
#define __CollisionDetection__

#include <iostream>
#include "cocos2d.h"

USING_NS_CC;

class CollisionDetection {
public:
    //Handle for getting the Singleton Object
    static CollisionDetection* GetInstance();
    //Function signature for checking for collision detection spr1, spr2 are the concerned sprites
    //pp is bool, set to true if Pixel Perfection Collision is required. Else set to false
    //_rt is the secondary buffer used in our system
    bool areTheSpritesColliding(CCSprite* spr1, CCSprite* spr2, bool pp, CCRenderTexture* _rt);
private:
    static CollisionDetection* instance;
    CollisionDetection();

    // Values below are all required for openGL shading
    CCGLProgram *glProgram;
    ccColor4B *buffer;
    int uniformColorRed;
    int uniformColorBlue;

};

#endif /* defined(__CollisionDetection__) */




CollisionDetection.cpp



//
//  CollisionDetection.cpp
//  Created by Mudit Jaju on 30/08/13.
//
//  SINGLETON class for checking Pixel Based Collision Detection

#include "CollisionDetection.h"
// Singleton Instance set to NULL initially
CollisionDetection* CollisionDetection::instance = NULL;

// Handle to get Singleton Instance
CollisionDetection* CollisionDetection::GetInstance() {
    if (instance == NULL) {
        instance = new CollisionDetection();
    }
    return instance;
}

// Private Constructor being called from within the GetInstance handle
CollisionDetection::CollisionDetection() {
    // Code below to setup shaders for use in Cocos2d-x
    glProgram = new CCGLProgram();
    glProgram->retain();
    glProgram->initWithVertexShaderFilename("SolidVertexShader.vsh", "SolidColorShader.fsh");
    glProgram->addAttribute(kCCAttributeNamePosition, kCCVertexAttrib_Position);
    glProgram->addAttribute(kCCAttributeNameTexCoord, kCCVertexAttrib_TexCoords);
    glProgram->link();
    glProgram->updateUniforms();
    glProgram->use();

    uniformColorRed = glGetUniformLocation(glProgram->getProgram(), "u_color_red");
    uniformColorBlue = glGetUniformLocation(glProgram->getProgram(), "u_color_blue");

    // A large buffer created and re-used again and again to store glReadPixels data
    buffer = (ccColor4B *)malloc( sizeof(ccColor4B) * 10000 );
}

bool CollisionDetection::areTheSpritesColliding(cocos2d::CCSprite* spr1, cocos2d::CCSprite* spr2, bool pp, CCRenderTexture* _rt) {
    bool isColliding = false;

    // Rectangle of the intersecting area if the sprites are colliding according to Bounding Box collision
    CCRect intersection;

    // Bounding box of the Two concerned sprites being saved
    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;
        }

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

        //OPTIMIZE FURTHER
        //CONSIDER THE CASE WHEN ONE BOUDNING BOX IS COMPLETELY INSIDE ANOTHER BOUNDING BOX!
        if (r1.getMaxX() > r2.getMinX()) {
            tempX = r2.getMinX();
            tempWidth = r1.getMaxX() - r2.getMinX();
        } else {
            tempX = r1.getMinX();
            tempWidth = r2.getMaxX() - r1.getMinX();
        }

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

        // We make the rectangle for the intersection area
        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;

        // Total pixels whose values we will get using glReadPixels depends on the Height and Width of the intersection area
        unsigned int numPixels = w * h;

        // Setting the custom shader to be used
        spr1->setShaderProgram(glProgram);
        spr2->setShaderProgram(glProgram);
        glProgram->use();

        // Clearing the Secondary Draw buffer of all previous values
        _rt->beginWithClear( 0, 0, 0, 0);

        // The below two values are being used in the custom shaders to set the value of RED and BLUE colors to be used
        glUniform1i(uniformColorRed, 255);
        glUniform1i(uniformColorBlue, 0);

        // The blend function is important we don't want the pixel value of the RED color being over-written by the BLUE color.
       // We want both the colors at a single pixel and hence get a PINK color (so that we have both the RED and BLUE pixels)
        spr1->setBlendFunc((ccBlendFunc){GL_SRC_ALPHA, GL_ONE});

        // The visit() function draws the sprite in the _rt draw buffer its a Cocos2d-x function
        spr1->visit();

        // Setting the shader program back to the default shader being used by our game        
spr1->setShaderProgram(CCShaderCache::sharedShaderCache()->programForKey(kCCShader_PositionTextureColor));
        // Setting the default blender function being used by the game
        spr1->setBlendFunc((ccBlendFunc){CC_BLEND_SRC, CC_BLEND_DST});

        // Setting new values for the same shader but for our second sprite as this time we want to have an all BLUE sprite
        glUniform1i(uniformColorRed, 0);
        glUniform1i(uniformColorBlue, 255);
        spr2->setBlendFunc((ccBlendFunc){GL_SRC_ALPHA, GL_ONE});

        spr2->visit();

        spr2->setShaderProgram(CCShaderCache::sharedShaderCache()->programForKey(kCCShader_PositionTextureColor));
        spr2->setBlendFunc((ccBlendFunc){CC_BLEND_SRC, CC_BLEND_DST});

        // Get color values of intersection area
        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];
            // Here we check if a single pixel has both RED and BLUE pixels
            if (color.r > 0 && color.b > 0) {
                isColliding = true;
                break;
            }
        }
    }
    return isColliding;
}

SolidColorShader.fsh



#ifdef GL_ES
precision lowp float;
#endif

varying vec2 v_texCoord;
uniform sampler2D u_texture;
uniform int u_color_red;
uniform int u_color_blue;

void main()
{
	vec4 color = texture2D(u_texture, v_texCoord);
    gl_FragColor = vec4(u_color_red, 0, u_color_blue, color.a);

}


 SolidVertexShader.vsh


attribute vec4 a_position;							
attribute vec2 a_texCoord;							
attribute vec4 a_color;								

#ifdef GL_ES										
varying lowp vec4 v_fragmentColor;					
varying mediump vec2 v_texCoord;					
#else												
varying vec4 v_fragmentColor;						
varying vec2 v_texCoord;							
#endif												

void main()											
{													
    gl_Position = CC_MVPMatrix * a_position;		
	v_fragmentColor = a_color;						
	v_texCoord = a_texCoord;						
}

For using the Collision Detection Class:

1. Initialize the CCRenderTexture object


    _rt = CCRenderTexture::create(visibleSize.width * 2, visibleSize.height * 2);
    _rt->setPosition(ccp(visibleSize.width, visibleSize.height));
    _rt->retain();
    _rt->setVisible(false);

2. Call the Singleton function whenever collision detection required


if (CollisionDetection::GetInstance()->areTheSpritesColliding(pSprite, pCurrentSpriteToDrag, true, _rt)) {
     //Code here
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值