转自:http://blog.csdn.net/onerain88/article/details/7550009
一般经常用到的触屏的情况有两种:一种是Layer统一接收触屏消息,然后由程序根据需要分发给不同位置的精灵;另一种情况是自定义一个可以接收触屏消息的Sprite,比如类似于Button功能的Sprite,这就需要在定义Sprite的时候就要定义好触屏所触发的操作!
下面就两种情况分别记录一下基本用法:
1.Layer接收触屏消息
用法很简单,只需要覆写父类的4个方法(可以根据需要,但是ccTouchBegan()是必须要覆写的,并且其返回值对触屏事件的传递有影响,后面会总结),并在init()方法中将其添加到CCTouchDispacher中,代码如下
class TouchableLayer: public CCLayer { public: virtual bool init(); LAYER_NODE_FUNC(TouchableLayer); virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent); virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent); virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent); virtual void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent); };
在Layer的init()中添加如下代码,这个Layer就可以接收到触屏消息了
CCTouchDispatcher::sharedDispatcher()->addTargetedDelegate(this, 0, true);
如果想通过这种方式判断具体触摸的Sprite或者区域等信息,就需要自己写判断和分发消息的代码了!
2.自定义可以接收触屏消息的Sprite
这种稍微复杂一些,但是还是比较好理解的,首先要先继承CCSprite或者其父类,以满足精灵形状,位置等信息的要求,另外还需要继承触屏事件委托CCTargetedTouchDelegate,CCTargetedTouchDelegate中定义了接收触屏信息的回调虚函数,而这些虚函数,正是我们需要覆写的部分,代码如下
class TouchableSprite: public CCSprite, public CCTargetedTouchDelegate { public: TouchableSprite(); virtual ~TouchableSprite(); static TouchableSprite *touchSpriteWithFile(const char *file); bool initWithFile(const char *file); virtual void onEnter(); virtual void onExit(); CCRect rect(); bool containsTouchLocation(CCTouch *touch); virtual bool ccTouchBegan(CCTouch *touch, CCEvent *event); virtual void ccTouchMoved(CCTouch *touch, CCEvent *event); virtual void ccTouchEnded(CCTouch *touch, CCEvent *event); };
重点在于判断自定义Sprite是否被点击,这时就需要得到精灵所在的矩形了,这时又有两种判断方式
(1)得到触屏所在位置,然后根据精灵所在位置的矩形区域和触屏的点判断是否包含,如果包含,则说明触摸到了Sprite。这里写了一个得到精灵当前所在矩形的方法
CCRect TouchableSprite::rect() { CCSize size = getContentSize(); CCPoint pos = getPosition(); return CCRectMake(pos.x - size.width / 2, pos.y - size.height / 2, size.width, size.height); }
然后在每次点击的时候都需要将当前触屏位置转换为GL坐标的位置,然后和Sprite所在矩形做包含判断
bool TouchableSprite::containsTouchLocation(cocos2d::CCTouch *touch) { CCPoint touchPoint = touch->locationInView(touch->view()); touchPoint = CCDirector::sharedDirector()->convertToGL(touchPoint); return CCRect::CCRectContainsPoint(rect(), touchPoint); }
(2)其实cocos2d为我们提供了一种相对简单的方法,但是原理类似,调用CCNode中定义的convertTouchToNodeSpaceAR()方法,将触屏点转化为相对于结点的相对坐标
(ps:由于默认anchor点是中点,所以每一个Sprite上的相对坐标系是从(-width / 2, -height / 2)为左上角点坐标),所以上面的两个方法需要修改一下
CCRect TouchableSprite::rect() { CCSize size = getTexture()->getContentSize(); return CCRectMake(-size.width / 2, -size.height / 2, size.width, size.height); }
bool TouchableSprite::containsTouchLocation(cocos2d::CCTouch *touch) { return CCRect::CCRectContainsPoint(rect(), convertTouchToNodeSpaceAR(touch)); }
3.触屏传递顺序
另外需要主要的是
virtual bool ccTouchBegan(CCTouch *touch, CCEvent *event);
方法,其返回值是对此触屏消息有影响的,简单来说,如果返回false,表示不处理ccTouchMoved(),ccTouchEnded(),ccTouchCanceld()方法,而交由后续接收触屏消息的对象处理;如果返回true,表示会处理ccTouchMoved(),ccTouchEnded(),ccTouchCanceld()方法,并且消耗掉此触屏消息。
总结如下:
1.CCLayer 只有一层的情况:
4.自定义触屏事件
1、判断触摸点是否在指定区域内
HelloWorldScene.h
public: CCRect mPlayBounds; virtual void registerWithTouchDispatcher(); virtual bool ccTouchBegan(cocos2d::CCTouch* touch, cocos2d::CCEvent* event);
HelloWorldScene.cpp
删除bool HelloWorld::init()下do代码块中的所有代码,替换为:
CC_BREAK_IF(! CCLayer::init()); CCSize size = CCDirector::sharedDirector()->getWinSize(); //实例化一个精灵 CCSprite *mMainMenu = CCSprite::create("items.png", CCRectMake(0, 224, 300, 110)); CC_BREAK_IF(!mMainMenu); //设置精灵的位置 mMainMenu->setPosition(ccp(size.width / 2, size.height / 2)); this->addChild(mMainMenu); //绘制一个矩形 mPlayBounds = CCRectMake(size.width / 2 - 64, size.height / 2 + 18, 128, 36); //设置为可触摸 this->setTouchEnabled(true); bRet = true;
添加两个函数:
void HelloWorld::registerWithTouchDispatcher() { //注册触摸监听 CCDirector* pDirector = CCDirector::sharedDirector(); pDirector->getTouchDispatcher()->addTargetedDelegate(this, 0, true); } bool HelloWorld::ccTouchBegan(cocos2d::CCTouch* touch, cocos2d::CCEvent* event) { //取得触摸点 CCPoint location = touch->getLocationInView(); //将触摸点转换为GL坐标系的点 location = CCDirector::sharedDirector()->convertToGL(location); //如果触摸点在矩形范围内则执行代码,切换场景 if (mPlayBounds.containsPoint(location)) { CCScene *scene = SecondScene::scene(); CCDirector::sharedDirector()->replaceScene(CCTransitionJumpZoom::create(1.0f,scene)); } return true; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· [AI/GPT/综述] AI Agent的设计模式综述