学习cocos2d-x像素级触摸处理

2015年03月18日 11:08 0 点赞 0 评论 更新于 2025-11-21 17:37

最近,我对Cocos2d-x中的像素级触摸处理进行了深入研究。在实际开发中,我们有时会使用不规则图形作为按钮,这些不规则图形通常以矩形PNG图片的形式呈现。然而,图片的实际有效显示内容可能仅占整个PNG图片的一小部分,其余大部分为透明区域。我们的目标是过滤掉这些透明区域,实现只有触摸到图片真实内容时按钮才会响应的效果。

实现思路

起初,我尝试通过CCSprite直接获取纹理的像素信息,但遗憾的是,Cocos2d-x并未提供这样的接口。经过对网上几个Demo的研究,我发现可以通过使用RenderTexture重绘来实现这一效果。

代码实现

1. 头文件包含与命名空间使用

#include "HelloWorldScene.h"
#include "SimpleAudioEngine.h"
using namespace cocos2d;
using namespace CocosDenshion;

2. 场景创建

CCScene* HelloWorld::scene()
{
// ‘scene’ 是一个自动释放对象
CCScene *scene = CCScene::create();
// ‘layer’ 是一个自动释放对象
HelloWorld *layer = HelloWorld::create();
// 将层添加为场景的子对象
scene->addChild(layer);
// 返回场景
return scene;
}

3. 初始化函数

bool HelloWorld::init()
{
if (!CCLayer::init())
{
return false;
}
// 启用触摸功能
this->setTouchEnabled(true);
// 创建精灵
this->m_imgMan = CCSprite::create("man.png");
this->m_imgMan->setPosition(ccp(400, 200));
this->addChild(this->m_imgMan, 1);
// 创建渲染纹理
this->m_pRenderTexture = CCRenderTexture::create(this->m_imgMan->getContentSize().width, this->m_imgMan->getContentSize().height, kCCTexture2DPixelFormat_RGBA8888);
this->m_pRenderTexture->ignoreAnchorPointForPosition(true);
this->m_pRenderTexture->setPosition(ccp(400, 200));
this->m_pRenderTexture->setAnchorPoint(CCPointZero);
this->addChild(this->m_pRenderTexture, 0, 1);
return true;
}

4. 触摸开始处理函数

bool HelloWorld::ccTouchBegan(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent) {
bool isTouched = false;
// 获取触摸点在视图中的位置
CCPoint touchPoint = pTouch->getLocationInView();
// 将触摸点转换为OpenGL坐标
CCPoint glPoint = CCDirector::sharedDirector()->convertToGL(touchPoint);
if (this->m_imgMan->boundingBox().containsPoint(glPoint)) {
ccColor4B color4B = {0, 0, 0, 0};
// 将触摸点转换为节点空间坐标
CCPoint nodePos = this->m_imgMan->convertTouchToNodeSpace(pTouch);
unsigned int x = nodePos.x;
unsigned int y = this->m_imgMan->getContentSize().height - nodePos.y;
CCPoint point = this->m_imgMan->getPosition();
// 开始准备绘制
this->m_pRenderTexture->begin();
// 绘制使用的临时精灵,与原图是同一图片
CCSprite* pTempSpr = CCSprite::createWithSpriteFrame(this->m_imgMan->displayFrame());
pTempSpr->setPosition(ccp(pTempSpr->getContentSize().width / 2, pTempSpr->getContentSize().height / 2));
// 绘制
pTempSpr->visit();
// 结束绘制
this->m_pRenderTexture->end();
// 通过画布拿到这张画布上每个像素点的信息,封装到CCImage中
CCImage* pImage = this->m_pRenderTexture->newCCImage();
// 获取像素数据
unsigned char* data_ = pImage->getData();
unsigned int *pixel = (unsigned int *)data_;
pixel = pixel + (y * (int)pTempSpr->getContentSize().width) * 1 + x * 1;
// R通道
color4B.r = *pixel & 0xff;
// G通道
color4B.g = (*pixel >> 8) & 0xff;
// B通道
color4B.b = (*pixel >> 16) & 0xff;
// Alpha通道,我们有用的就是Alpha
color4B.a = (*pixel >> 24) & 0xff;
CCLOG("当前点击的点的: alpha = %d", color4B.a);
if (color4B.a > 50) {
isTouched = true;
} else {
isTouched = false;
}
// 绘制完成后清理画布的内容
this->m_pRenderTexture->clear(0, 0, 0, 0);
}
if (this->m_pLabTips) {
this->m_pLabTips->removeFromParentAndCleanup(true);
this->m_pLabTips = NULL;
}
return isTouched;
}

5. 触摸结束处理函数

void HelloWorld::ccTouchEnded(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent) {
if (this->m_pLabTips) {
this->m_pLabTips->removeFromParentAndCleanup(true);
this->m_pLabTips = NULL;
}
this->m_pLabTips = CCLabelTTF::create("点击到非透明的像素点", "Courier", 30);
this->m_pLabTips->setAnchorPoint(CCPointZero);
this->m_pLabTips->setPosition(ccp(300.0f, 100.0f));
this->m_pLabTips->setColor(ccYELLOW);
this->addChild(this->m_pLabTips, 1);
}

6. 注册触摸分发器

void HelloWorld::registerWithTouchDispatcher() {
CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, CCLayer::getTouchPriority(), false);
}

实现原理

在点击图片时,我们对图片进行重绘。在重绘过程中,通过RenderTexture(画布)可以获取整个画布上的像素点信息。由于我们确保绘制的内容和画布大小一致,所以画布上的每一个像素点对应着我们想要绘制的图片的像素点。然后,通过判断像素点的Alpha通道值,我们可以确定该点是否为透明色。如果是透明色,则不进行触摸响应。

这里,我们将Alpha通道值小于50的像素点视为透明点。当点击到透明区域时,屏幕上不显示任何文字;当点击到有色区域时,我们可以观察打印日志信息。

通过这种方式,我们就实现了Cocos2d-x中的像素级触摸处理。

游戏开发网 - 最好的游戏编程开发技术网站!

作者信息

feifeila

feifeila

共发布了 3994 篇文章