希望官方下一个版本可以加入像素级的碰撞检测

碰撞检测是很多游戏的基础,2dx的碰撞一般是boundingBox实现的,对于非方形的sprite,基本上不能愉快的碰撞了……
虽然断断续续研究过像素级的处理,但目前还木有形成切实可行的代码……虽然也有通过物理手段的碰撞,但是与一条代码的interact()函数相比,工作量倍增有木有……
就在最近发现了外国友人在2.2版本上实现的像素级碰撞,在boundingBox的基础上检测双方的有色像素是否重叠,还可以选择是否进行像素级的碰撞,
http://blog.muditjaju.infiniteeurekas.in/?p=1
本来想移植到3.2,结果也是以失败告终,发帖提问也没有有效的解决方法,只能期待大神们做出成功的移植,最好能出现在今后的2DX中,对引擎绝对是一个提升。

小白能做到的只有指路了,等九月份买到了3.0的新书(你们一定知道是哪本),再系统深入的学习

像素级碰撞。。。非常消耗资源啊

其实需要像素级碰撞的地方并不是很多,并不是所有sprite都是奇形怪状的,但是如果没有这个功能,万一用到了的时候就非常拙计……你可以去看一下那个外国大神在2.2上的实现方案,先检查boundingBox,交叉之后才进行像素级检测,这么一来基本上就不会太消耗了,如果你用的是2.2版本,应该可以直接用了,只是我不知道如何移植到3.x来

确实是有备无患,移植的话应该不算麻烦吧,只需要可以获取到像素点就行了,texture里面似乎有相应的功能,而且,这个底层基于opengl es的,里面本身有像素的获取函数

呃,本身在这方面基本上就是小白,将2.2的代码直接粘贴过来确实不能用,3.x很多函数还弃用了,所以究竟要改哪条就更不清楚了,你能成功移植过来么?

没有人做 就自己研究 移植过来呗

呃,实在是研究过后没成功,才来吐槽的,算是半个求助帖吧

你可以给我个链接,我来看看,也不能担保可以搞定,不过应该可以帮你分析一下

就是我开始说的这个链接
http://blog.muditjaju.infiniteeurekas.in/?p=1

在做物理切割类游戏时候还是需要的吧

啊,我去看过了,实现思路也和我想的差不多,代码看起来并不复杂,我晚上回家试试

我昨晚上进行了移植,现在把代码贴上来,并没有实现效果,我得调试一下,有很奇怪的bug,坐标会偏移,不过3.2版本代码大概就是我这样了,我再核对一下,希望能成功
PS:我根据自己的习惯改了一些命名和编程风格,但是没有改变算法本身,因为我也希望我能用上,至于vsh和fsh两个文件,还请自行拷贝然后放到Resource下面,使用方法按照那个博客上的就行了,如果我试成功了,我会再回复这个帖子的

#ifndef PIXEL_COLLISION_DETECTION_H_
#define PIXEL_COLLISION_DETECTION_H_

#include "cocos2d.h"

USING_NS_CC;

class PixelCollisionDetection {
public:
    PixelCollisionDetection();
    ~PixelCollisionDetection();

    static PixelCollisionDetection* getInstance();

    bool isCollided(Sprite *pObjA, Sprite *pObjB, RenderTexture *pRenderTex);

private:
    DISALLOW_COPY_AND_ASSIGN(PixelCollisionDetection);

    bool init();

    GLProgram *pGLProgram_;;
    Color4B *pPixelBuffer_;

    int uniformColorRed_;
    int uniformColorBlue_;
};

#endif


```


#include "pixel_collision_detection.h"

static PixelCollisionDetection *pInstance = nullptr;

PixelCollisionDetection::PixelCollisionDetection()
    : pGLProgram_(nullptr),
      pPixelBuffer_(nullptr),
      uniformColorRed_(255),
      uniformColorBlue_(255)
{
}

PixelCollisionDetection::~PixelCollisionDetection()
{
    CC_SAFE_DELETE(pInstance);
    CC_SAFE_RELEASE(pGLProgram_);
    CC_SAFE_DELETE_ARRAY(pPixelBuffer_);
}

PixelCollisionDetection* PixelCollisionDetection::getInstance()
{
    if(!pInstance) {
        pInstance = new PixelCollisionDetection;

        if(!pInstance || !pInstance->init()) 
        {
            delete pInstance;
            pInstance = nullptr;
        }
    }

    return pInstance;
}

bool PixelCollisionDetection::isCollided(Sprite *pObjA, Sprite *pObjB, RenderTexture *pRenderTex)
{
    bool bRet = false;

    Rect rectA = pObjA->getBoundingBox();
    Rect rectB = pObjB->getBoundingBox();

    if(rectA.intersectsRect(rectB))
    {
        float tempX = 0.0f;
        float tempY = 0.0f;
        float tempWid = 0.0f;
        float tempHgt = 0.0f;

        //more optimization,one rect is completely inside another
        if(rectA.getMaxX() > rectB.getMinX()) {
            tempX = rectB.getMinX();
            tempWid = rectA.getMaxX() - rectB.getMinX();
        }
        else {
            tempX = rectA.getMinX();
            tempWid = rectB.getMaxX() - rectA.getMinX();
        }

        if (rectB.getMaxY() < rectA.getMaxY()) {
            tempY = rectA.getMinY();
            tempHgt = rectB.getMaxY() - rectA.getMinY();
        } 
        else {
            tempY = rectB.getMinY();
            tempHgt = rectA.getMaxY() - rectB.getMinY();
        }

        Rect intersectionRect(tempX * CC_CONTENT_SCALE_FACTOR(), tempY * CC_CONTENT_SCALE_FACTOR(),
            tempWid * CC_CONTENT_SCALE_FACTOR(), tempHgt * CC_CONTENT_SCALE_FACTOR());

        unsigned x = intersectionRect.origin.x;
        unsigned y = intersectionRect.origin.y;
        unsigned w = intersectionRect.size.width;
        unsigned h = intersectionRect.size.height;
        
        //total pixels
        unsigned pixelsNum = w * h;

        pObjA->setGLProgram(pGLProgram_);
        pObjB->setGLProgram(pGLProgram_);
        pGLProgram_->use();

        pRenderTex->beginWithClear(0.0f, 0.0f, 0.0f, 0.0f);

        glUniform1i(uniformColorRed_, 255);
        glUniform1i(uniformColorBlue_, 0);

        //set an appropriate blend mode so that we can get a new color by two color blending 
        pObjA->setBlendFunc(BlendFunc::ADDITIVE);
        pObjA->visit();

        pObjA->setGLProgram(ShaderCache::getInstance()->getGLProgram(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR));

        pObjA->setBlendFunc(BlendFunc::ALPHA_PREMULTIPLIED);

        glUniform1i(uniformColorRed_, 0);
        glUniform1i(uniformColorBlue_, 255);

        pObjB->setBlendFunc(BlendFunc::ADDITIVE);
        pObjB->visit();

        pObjB->setGLProgram(ShaderCache::getInstance()->getGLProgram(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR));
        pObjB->setBlendFunc(BlendFunc::ALPHA_PREMULTIPLIED);

        glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pPixelBuffer_);

        pRenderTex->end();

        unsigned step = 1;
        for(int i = 0; i < pixelsNum; i += step)
        {
            Color4B pxl = pPixelBuffer_*;
            //both have two color,it must be the collision area
            if(pxl.r > 0 && pxl.b > 0)
            {
                bRet = true;
                break;
            }
        }
    }

    return bRet;
}

//-------------------private----------------------
bool PixelCollisionDetection::init()
{
    bool bRet = false;

    do 
    {
        pGLProgram_ = GLProgram::createWithFilenames("solid_vs.vsh", "solid_fs.fsh");
        pGLProgram_->retain();
        pGLProgram_->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_POSITION, GLProgram::VERTEX_ATTRIB_POSITION);
        pGLProgram_->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_TEX_COORD, GLProgram::VERTEX_ATTRIB_TEX_COORD);
        pGLProgram_->link();
        pGLProgram_->updateUniforms();
        pGLProgram_->use();

        uniformColorRed_ = glGetUniformLocation(pGLProgram_->getProgram(), "u_color_red");
        uniformColorBlue_ = glGetUniformLocation(pGLProgram_->getProgram(), "u_color_blue");

        pPixelBuffer_ = new Color4B;

        bRet = true;
    } while(0);
    
    return bRet;
}


```
*

我基本上也是这么移植的,但是一运行过pRenderTex->end();之后,下一帧开始屏幕上就只显示pRenderTex的内容了,而且坐标也不对,我也写了求助帖,在2L截了图
http://www.cocoachina.com/bbs/read.php?tid=215635

似乎是visit函数的问题,你改写后把renderTexture渲染出来能够看到蓝色和红色的绘制效果吗,我试了2.23版本确实可以的,不过3.2渲染方式改变了,,我还在研究中,Opengl知识都还回给书本了。。。努力查资料

确实颜色没有变化,我都忘了这回事了:12:

目前能定位到问题出在setGLProgram上,如果不调用这个,就不会偏移,似乎不能这么简单的移植,代码的结构也有变化,只能继续找找方法了。。。要是两年前说不定我还能快速点。。现在还得看书,逻辑写多了退化了。。。

我又想了一下,我觉得作者的意图是通过pRenderTex的处理,得出是否碰撞的结论,而这个新建的rendertexture是不应该显示在屏幕上的,就像对一个数组进行一些,但最后并没有printf数组中的数据。这么一想或许颜色不改变反而是对的,如何让pRenderTex只在后台处理而不对屏幕显示产生影响才是目标

确实是不让显示出来。。我只是想说明着色器工作并不正常,显示出来只是为了测试,看看是否真的有效,2.23版本我用着一切正常,但是移植过来确实不行,还是没有找到症结所在,或者说,可能找的方向错了,关于3.2着色编程的资料确实有点少,只能分析源代码,感觉好吃力啊。。。

我是完全没有方向了……最近也有自己的项目要做,所以打算九月份买到那本3.0的新书后,花一个月研究这方面的内容

加油吧,也不一定要这个方法,像素级碰撞只需要能获取到像素点就能有办法完成,我再抽空研究下,不行我换换方法