2D Pixel collision detection

Started by
0 comments, last by justL 3 years, 11 months ago

Hello everyone, my previous game which is using cocos v3x was using pixel collision detection from this post : Pixel collision detection for v3.x . Its works nice and properly.
But now i want to upgrade my game into v4, so far i know Cocos remove GlProgram to Program. So i tried to upgrade it by looking cocos2dx reference v4, but now im ran out of idea how to do it in v4. I mean the new Program Class doesnt have class that supposed to be as the GlProgram class be, Its totaly change. i’ve took a look at cocos2dx reference v4 and still cant make pixel detection in v4.

What i want to do is when user hit the sprite area it will run the touch event. But, the problem is when user hit out of the sprite area its still run the touch event. So i want make this perfect pixel collision detection. Here my sprite looks like:

Here my last code that iam used for hit detection in cocos2dx v3.

HitDetectHelper.h

#ifndef PIXEL_COLLISION_H_

#define PIXEL_COLLISION_H_

#include <iostream>
#include "../../Implement.h"

USING_NS_CC;

class PixelCollision {
public:
static PixelCollision *getInstance(void);
static void destroyInstance(void);

bool collidesWithPoint(Sprite *sprite, const cocos2d::Point &amp;amp;point);
 
private:
class PixelReaderNode : public Node {
public:
 static PixelReaderNode* create(const cocos2d::Point &amp;amp;readPoint);

 PixelReaderNode(const cocos2d::Point &amp;amp;readPoint);
 virtual ~PixelReaderNode(void);

 virtual void draw(cocos2d::Renderer *renderer, const cocos2d::Mat4&amp;amp; transform, uint32_t flags) override;
 inline void reset();

 inline const cocos2d::Point &amp;amp;getReadPoint(void) const;
 inline void setReadPoint(const cocos2d::Point &amp;amp;readPoint);

 inline const Size &amp;amp;getReadSize(void) const;
 inline void setReadSize(const Size &amp;amp;readPoint);

 inline GLubyte *getBuffer(void);

private:
 void onDraw(void);

 CustomCommand _readPixelCommand;
 cocos2d::Point _readPoint;
 Size _readSize;
 GLubyte *_buffer;
};

PixelCollision(void);
virtual ~PixelCollision(void);

Rect getIntersection(const Rect &amp;amp;r1, const Rect &amp;amp;r2) const;
cocos2d::Point renderSprite(Sprite *sprite, CustomCommand &amp;amp;command, bool red);
void resetSprite(Sprite *sprite, const cocos2d::Point &amp;amp;oldPosition);

// Singleton
static PixelCollision *s_instance;

cocos2d::backend::Program *_glProgram;
RenderTexture *_rt;
PixelReaderNode *_pixelReader;
};

// Inline methods
inline void PixelCollision::PixelReaderNode::reset(void) {
memset(_buffer, 0, 4 * _readSize.width * _readSize.height);
}

inline const cocos2d::Point &amp;amp;PixelCollision::PixelReaderNode::getReadPoint(void) const {
return _readPoint;
}

inline void PixelCollision::PixelReaderNode::setReadPoint(const cocos2d::Point &amp;amp;readPoint) {
_readPoint = readPoint;
}

inline const Size &amp;amp;PixelCollision::PixelReaderNode::getReadSize(void) const {
return _readSize;
}

inline void PixelCollision::PixelReaderNode::setReadSize(const Size &amp;amp;readSize) {
if (_readSize.width * _readSize.height < readSize.width * readSize.height) {
 free(_buffer);
 _buffer = (GLubyte*)malloc(4 * readSize.width * readSize.height);
}
_readSize = readSize;
}

inline GLubyte *PixelCollision::PixelReaderNode::getBuffer(void) {
return _buffer;
}

#endif /* PIXEL_COLLISION_H_ */

HitDetectHelper.cpp

#include "HitDetectHelper.h"

static const auto kVertexShader = "shaders/SolidColorShader.vsh";
static const auto kFragmentShader = "shaders/SolidColorShader.fsh";
static const auto kShaderRedUniform = "u_color_red";
static const auto kShaderBlueUniform = "u_color_blue";
static const auto kOpacityThreshold = 50;

PixelCollision* PixelCollision::s_instance = nullptr;

// Private Constructor being called from within the GetInstance handle
PixelCollision::PixelCollision(void) :
_glProgram(nullptr),
_rt(nullptr),
_pixelReader(nullptr) {

if (!FileUtils::getInstance()->isFileExist(EducaRes::additionalPath + kVertexShader)) return;
if (!FileUtils::getInstance()->isFileExist(EducaRes::additionalPath + kFragmentShader)) return;

_glProgram = GLProgram::createWithFilenames(EducaRes::additionalPath + kVertexShader, kFragmentShader);
_glProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_POSITION, GLProgram::VERTEX_ATTRIB_POSITION);
_glProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_TEX_COORD, GLProgram::VERTEX_ATTRIB_TEX_COORD);
_glProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_COLOR, GLProgram::VERTEX_ATTRIB_COLOR);

const Size &amp;amp;size = Director::getInstance()->getWinSize();
_rt = RenderTexture::create(size.width, size.height, cocos2d::backend::PixelFormat::RGBA8888);
_pixelReader = PixelReaderNode::create(cocos2d::Point::ZERO);

_glProgram->retain();
_rt->retain();
_pixelReader->retain();
}

PixelCollision::~PixelCollision(void) {
_glProgram->release();
_rt->release();
_pixelReader->release();
}

PixelCollision* PixelCollision::getInstance(void) {
if (!s_instance) {
 s_instance = new PixelCollision();
}
return s_instance;
}

void PixelCollision::destroyInstance(void) {
delete s_instance;
s_instance = nullptr;
}

bool PixelCollision::collidesWithPoint(Sprite *sprite, const cocos2d::Point &amp;amp;point) {
_rt->beginWithClear(0, 0, 0, 0);
glColorMask(1, 0, 0, 1);

auto oldColor = sprite->getColor();
auto prnt = sprite->getParent();
cocos2d::Point oldPosition = prnt->convertToWorldSpace(prnt->convertToNodeSpace(sprite->getPosition()));///sprite->getPosition();
sprite->setScale(prnt->getScaleX());
sprite->setColor(Color3B::WHITE);
sprite->setPosition(sprite->getParent()->convertToWorldSpace(oldPosition));
sprite->visit();

auto readPoint = sprite->getParent()->convertToWorldSpace(point) * CC_CONTENT_SCALE_FACTOR();
_pixelReader->setReadPoint(readPoint);
_pixelReader->setReadSize(Size(1, 1));
_pixelReader->visit();

auto color = _pixelReader->getBuffer();
_rt->end();
Director::getInstance()->getRenderer()->render();
glColorMask(1, 1, 1, 1);
sprite->setColor(oldColor);
sprite->setPosition(oldPosition);
sprite->setScale(1.0f);

return color[0] > 0;
}


Any advice would be appreciated, Thanks.

This topic is closed to new replies.

Advertisement