更新时间:2022-04-05 22:25:54
// // 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 // 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; }
#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); }
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; }
_rt = CCRenderTexture::create(visibleSize.width * 2, visibleSize.height * 2); _rt->setPosition(ccp(visibleSize.width, visibleSize.height)); _rt->retain(); _rt->setVisible(false);
if (CollisionDetection::GetInstance()->areTheSpritesColliding(pSprite, pCurrentSpriteToDrag, true, _rt)) { //Code here }