Cocos2dx 像素判断碰撞检测

本文详细介绍了如何在Cocos2d-x游戏引擎中进行像素级别的碰撞检测,通过实例代码解析了关键步骤,包括获取精灵的像素数据、比较颜色差异以及判断碰撞发生,确保精确的碰撞响应。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


最近研究了一下透明图片的点击事件即png图片中透明区域的点击。当时用j2me的时候,记得设置个值就可以处理是像素点击还是图片点击,不对,是碰撞检测。看了看jdk,它处理了像素,处理如下:
  1. public void handlesinglepixel(int x, int y, int pixel) {
  2. int alpha = (pixel >> 24) & 0xff;
  3. int red = (pixel >> 16) & 0xff;
  4. int green = (pixel >> 8) & 0xff;
  5. int blue = (pixel ) & 0xff;
  6. // Deal with the pixel as necessary...
  7. }
复制代码



这时候使用的像素格式是ARGB。
  1. bool CCTexture2D::initPremultipliedATextureWithImage(CCImage *image, unsigned int width, unsigned int height)

  2. {

  3. unsigned char* tempData = image->getData();

  4. this->setFDImageData(tempData);

  5. unsigned int* inPixel32 = NULL;

  6. unsigned char* inPixel8 = NULL;

  7. unsigned short* outPixel16 = NULL;

  8. bool hasAlpha = image->hasAlpha();

  9. CCSize imageSize = CCSizeMake((float)(image->getWidth()), (float)(image->getHeight()));

  10. CCTexture2DPixelFormat pixelFormat;

  11. size_t bpp = image->getBitsPerComponent();

  12. // compute pixel format

  13. if(hasAlpha)

  14. {

  15. pixelFormat = g_defaultAlphaPixelFormat;

  16. }

  17. else

  18. {

  19. if (bpp >= 8)

  20. {

  21. pixelFormat = kCCTexture2DPixelFormat_RGB888;

  22. }

  23. else

  24. {

  25. pixelFormat = kCCTexture2DPixelFormat_RGB565;

  26. }

  27. }

  28. // Repack the pixel data into the right format

  29. unsigned int length = width * height;

  30. if (pixelFormat == kCCTexture2DPixelFormat_RGB565)

  31. {

  32. if (hasAlpha)

  33. {

  34. // Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGGGBBBBB"

  35. tempData = new unsigned char[width * height * 2];

  36. outPixel16 = (unsigned short*)tempData;

  37. inPixel32 = (unsigned int*)image->getData();

  38. for(unsigned int i = 0; i < length; ++i, ++inPixel32) { *outPixel16++ = ((((*inPixel32 >> 0) & 0xFF) >> 3) << 11) | // R ((((*inPixel32 >> 8) & 0xFF) >> 2) << 5) | // G ((((*inPixel32 >> 16) & 0xFF) >> 3) << 0); // B } } else { // Convert "RRRRRRRRRGGGGGGGGBBBBBBBB" to "RRRRRGGGGGGBBBBB" tempData = new unsigned char[width * height * 2]; outPixel16 = (unsigned short*)tempData; inPixel8 = (unsigned char*)image->getData();

  39. for(unsigned int i = 0; i < length; ++i) { *outPixel16++ = (((*inPixel8++ & 0xFF) >> 3) << 11) | // R (((*inPixel8++ & 0xFF) >> 2) << 5) | // G (((*inPixel8++ & 0xFF) >> 3) << 0); // B } } } else if (pixelFormat == kCCTexture2DPixelFormat_RGBA4444) { // Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRGGGGBBBBAAAA" inPixel32 = (unsigned int*)image->getData();

  40. tempData = new unsigned char[width * height * 2];

  41. outPixel16 = (unsigned short*)tempData;

  42. for(unsigned int i = 0; i < length; ++i, ++inPixel32) { *outPixel16++ = ((((*inPixel32 >> 0) & 0xFF) >> 4) << 12) | // R ((((*inPixel32 >> 8) & 0xFF) >> 4) << 8) | // G ((((*inPixel32 >> 16) & 0xFF) >> 4) << 4) | // B ((((*inPixel32 >> 24) & 0xFF) >> 4) << 0); // A } } else if (pixelFormat == kCCTexture2DPixelFormat_RGB5A1) { // Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGGBBBBBA" inPixel32 = (unsigned int*)image->getData();

  43. tempData = new unsigned char[width * height * 2];

  44. outPixel16 = (unsigned short*)tempData;

  45. for(unsigned int i = 0; i < length; ++i, ++inPixel32) { *outPixel16++ = ((((*inPixel32 >> 0) & 0xFF) >> 3) << 11) | // R ((((*inPixel32 >> 8) & 0xFF) >> 3) << 6) | // G ((((*inPixel32 >> 16) & 0xFF) >> 3) << 1) | // B ((((*inPixel32 >> 24) & 0xFF) >> 7) << 0); // A } } else if (pixelFormat == kCCTexture2DPixelFormat_A8) { // Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "AAAAAAAA" inPixel32 = (unsigned int*)image->getData();

  46. tempData = new unsigned char[width * height];

  47. unsigned char *outPixel8 = tempData;

  48. for(unsigned int i = 0; i < length; ++i, ++inPixel32) { *outPixel8++ = (*inPixel32 >> 24) & 0xFF; // A

  49. }

  50. }

  51. if (hasAlpha && pixelFormat == kCCTexture2DPixelFormat_RGB888)

  52. {

  53. // Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRRRRGGGGGGGGBBBBBBBB"

  54. inPixel32 = (unsigned int*)image->getData();

  55. tempData = new unsigned char[width * height * 3];

  56. unsigned char *outPixel8 = tempData;

  57. for(unsigned int i = 0; i < length; ++i, ++inPixel32) { *outPixel8++ = (*inPixel32 >> 0) & 0xFF; // R

  58. *outPixel8++ = (*inPixel32 >> 8) & 0xFF; // G

  59. *outPixel8++ = (*inPixel32 >> 16) & 0xFF; // B

  60. }

  61. }

  62. initWithData(tempData, pixelFormat, width, height, imageSize);

  63. if (tempData != image->getData())

  64. {

  65. delete [] tempData;

  66. }

  67. m_bHasPremultipliedAlpha = image->isPremultipliedAlpha();

  68. return true;

  69. }
复制代码

那么,在2dx中,我们也是可以这么处理的,首先看纹理中的一个函数:
这里面针对kCCTexture2DPixelFormat_RGB888像素格式的图片进行了这么的处理:

  1. *outPixel8++ = (*inPixel32 >> 0) & 0xFF; // R

  2. *outPixel8++ = (*inPixel32 >> 8) & 0xFF; // G

  3. *outPixel8++ = (*inPixel32 >> 16) & 0xFF; // B
复制代码



那么,我们就可以考虑在点击事件中处理这个透明区域的问题了,began事件如下:
  1. bool FDPixelSprite::ccTouchBegan(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent)

  2. {

  3. if (this->isContainTouchLocation(pTouch) ) {

  4. ccColor4B c = {0, 0, 0, 0};

  5. CCSize winSize = CCDirector::sharedDirector()->getWinSize();

  6. CCPoint touchPoint = pTouch->getLocationInView();

  7. CCSize cSize = this->getContentSize();

  8. CCPoint pos(this->getPositionX() - cSize.width/2,winSize.height-this->getPositionY()- cSize.height/2);

  9. CCPoint localPoint = ccp(touchPoint.x - pos.x,

  10. touchPoint.y -pos.y);

  11. unsigned int x = localPoint.x, y = localPoint.y;

  12. unsigned char *data_ = this->getTexture()->getFDImageData();

  13. unsigned int *pixel = (unsigned int *)data_;

  14. pixel = pixel + (y * (int)this->getContentSize().width)* 1 + x * 1;

  15. c.r = *pixel & 0xff;

  16. c.g = (*pixel >> 8) & 0xff;

  17. c.b = (*pixel >> 16) & 0xff;

  18. c.a = (*pixel >> 24) & 0xff;

  19. if (c.a == 0) {

  20. CCLog("firedragonpzy:ccTouchBegan");

  21. return false;

  22. }else

  23. {

  24. return true;

  25. }

  26. }

  27. return false;

  28. }
复制代码



处理原理
获取点击的像素,判断当前的a值是否为0,若为0,则是透明区域。
注意点:
图片的坐标原点在图片的左上角,这里大家需要做一下坐标的转化,把点击屏幕的坐标转化为相对于图像左上角的坐标即可。
关于图像,它的颜色表示分为:R、G、B、A四部分,各占八位。
代码中:*pixel >> (n)bit,为了得到单独的red,green,blue,alpha值,具体得到什么,目前不是很清楚,貌似什么进制【时间原因,改日谈……】不过可以给大家提供个例子。
网上例子(jdk):
比如大红色用整数表示就是00 FF 00 00
pixel >> somebits是为了得到单独的alpha,red,green,blue值
右移24与255与操作得到alpha
16位得到red……
如果不& 0xff的话,上面的int green = (pixel >>  8) & 0xff;
得到的green值是FF 00 也就是65280,当然就不是我们要得到值
与操作是为了把高位削去!!!!
【因为pixel是一个整数
图像的表示分四部分:alpha值,red,green,blue
每一个值占一个字节,一个字节有8位二进制】
求解释……欢迎拍砖……
推荐阅读http://www.cocos2d-x.org/boards/6/topics/3472
注意啦,注意啦,下面还有个赠送篇、、、、【产生赠送篇的缘由:一群友说如果设置了锚点,怎么处理啊,那代码起不是不对了,所以我又产生了赠送篇,不过使用精灵的时候,基本都是以(0.5,0.5)为锚点,我开始没考虑这问题是源于这,呵呵,假设你锚点不是(0.5,0.5)旋转什么的可能就……效果不好。不过既然有不是CCPointZero的需求,我就写了支持不同锚点的FDPixelSprite,不过建议大家使用针对锚点为(0.5,0.5)的,效率高……】
现在贴出我的FDPixelSprite,大家可以直接使用此精灵处理含有透明区域图片的点击问题:
FDPixelSprite.h
  1. //

  2. // FDPixelSprite.h

  3. // PixelDemo

  4. //

  5. // Created by firedragonpzy on 13-2-19.

  6. //

  7. //

  8. #ifndef __PixelDemo__FDPixelSprite__

  9. #define __PixelDemo__FDPixelSprite__

  10. #include "cocos2d.h"

  11. USING_NS_CC;

  12. class FDPixelSprite : public CCSprite, public CCTargetedTouchDelegate {

  13. public:

  14. FDPixelSprite();

  15. virtual ~FDPixelSprite();

  16. void onEnter();

  17. void onExit();

  18. static FDPixelSprite* create( const char *pszFileName );

  19. CCRect atlasRect();

  20. bool isContainTouchLocation(CCTouch *pTouch);

  21. bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);

  22. void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent);

  23. void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);

  24. CC_SYNTHESIZE(const char*, m_pName,Name);

  25. };

  26. #endif /* defined(__PixelDemo__FDPixelSprite__) */
复制代码



FDPixelSprite.cpp
  1. //

  2. // FDPixelSprite.cpp

  3. // PixelDemo

  4. //

  5. // Created by firedragonpzy on 13-2-19.

  6. //

  7. //

  8. #include "FDPixelSprite.h"

  9. FDPixelSprite::FDPixelSprite()

  10. {}

  11. FDPixelSprite::~FDPixelSprite()

  12. {}

  13. FDPixelSprite* FDPixelSprite::create(const char *pszFileName)

  14. {

  15. FDPixelSprite *sprite = new FDPixelSprite();

  16. if (sprite && sprite->initWithFile(pszFileName)) {

  17. sprite->setName(pszFileName);

  18. sprite->autorelease();

  19. return sprite;

  20. }

  21. CC_SAFE_DELETE(sprite);

  22. sprite = NULL;

  23. return NULL;

  24. }

  25. void FDPixelSprite::onEnter()

  26. {

  27. CCSprite::onEnter();

  28. CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, 0, true);

  29. }

  30. void FDPixelSprite::onExit()

  31. {

  32. CCSprite::onExit();

  33. CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this);

  34. }

  35. bool FDPixelSprite::ccTouchBegan(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent)

  36. {

  37. if (this->isContainTouchLocation(pTouch) ) {

  38. ccColor4B c = {0, 0, 0, 0};

  39. CCSize winSize = CCDirector::sharedDirector()->getWinSize();

  40. CCPoint touchPoint = pTouch->getLocationInView();

  41. CCSize cSize = this->getContentSize();

  42. CCPoint pos(this->getPositionX() - cSize.width/2,winSize.height-this->getPositionY()- cSize.height/2);

  43. CCPoint localPoint = ccp(touchPoint.x - pos.x,

  44. touchPoint.y -pos.y);

  45. unsigned int x = localPoint.x, y = localPoint.y;

  46. unsigned char *data_ = this->getTexture()->getFDImageData();

  47. unsigned int *pixel = (unsigned int *)data_;

  48. pixel = pixel + (y * (int)this->getContentSize().width)* 1 + x * 1;

  49. c.r = *pixel & 0xff;

  50. c.g = (*pixel >> 8) & 0xff;

  51. c.b = (*pixel >> 16) & 0xff;

  52. c.a = (*pixel >> 24) & 0xff;

  53. if (c.a == 0) {

  54. CCLog("firedragonpzy:ccTouchBegan");

  55. return false;

  56. }else

  57. {

  58. return true;

  59. }

  60. }

  61. return false;

  62. }

  63. void FDPixelSprite::ccTouchMoved(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent)

  64. {

  65. CCPoint pos = this->getPosition();

  66. CCPoint sub = pTouch->getDelta();

  67. this->setPosition(ccpAdd(pos, sub));

  68. }

  69. void FDPixelSprite::ccTouchEnded(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent)

  70. {

  71. CCLog("firedragonpzy:ccTouchEnded");

  72. }

  73. CCRect FDPixelSprite::atlasRect()

  74. {

  75. CCSize cSize = this->getContentSize();

  76. return CCRectMake(-cSize.width/2, -cSize.height/2, cSize.width, cSize.height);

  77. }

  78. bool FDPixelSprite::isContainTouchLocation(cocos2d::CCTouch *pTouch)

  79. {

  80. return this->atlasRect().containsPoint(convertTouchToNodeSpaceAR(pTouch));

  81. }
复制代码



————————————–赠送篇———————————————-
为什么产生赠送篇 ,上面已经解释的很清楚了,不废话了,开门见山:
改为适配不同锚点需要改动两个地方:
(一):区域的判断:
  1. CCRect FDPixelSprite::atlasRect()

  2. {

  3. CCSize cSize = this->getContentSize();

  4. CCPoint point = this->getAnchorPointInPoints();

  5. return CCRectMake( -point.x, -point.y, cSize.width,cSize.height);

  6. }
复制代码



(二)相对于图片像素的转化
复制代码
  1. bool FDPixelSprite::ccTouchBegan(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent)

  2. {

  3. if (this->isContainTouchLocation(pTouch) ) {

  4. ccColor4B c = {0, 0, 0, 0};

  5. CCSize winSize = CCDirector::sharedDirector()->getWinSize();

  6. CCPoint touchPoint = pTouch->getLocationInView();

  7. CCSize cSize = this->getContentSize();

  8. CCPoint point =this->getAnchorPointInPoints();

  9. point = ccp(cSize.width - point.x,cSize.height- point.y);

  10. CCPoint pos(this->getPositionX() - point.x,winSize.height-this->getPositionY()- point.y);

  11. CCPoint localPoint = ccp(touchPoint.x - pos.x,

  12. touchPoint.y -pos.y);

  13. unsigned int x = localPoint.x, y = localPoint.y;

  14. unsigned char *data_ = this->getTexture()->getFDImageData();

  15. unsigned int *pixel = (unsigned int *)data_;

  16. pixel = pixel + (y * (int)this->getContentSize().width)* 1 + x * 1;

  17. c.r = *pixel & 0xff;

  18. c.g = (*pixel >> 8) & 0xff;

  19. c.b = (*pixel >> 16) & 0xff;

  20. c.a = (*pixel >> 24) & 0xff;

  21. if (c.a == 0) {

  22. CCLog("firedragonpzy:ccTouchBegan----------");

  23. return false;

  24. }else

  25. {

  26. return true;

  27. }

  28. }

  29. return false;

  30. }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值