我们依据上一次介绍的触屏事件和事件队列等知识来实现触屏的单击,双击,三连击事件。
下图为我们实现的效果图:
单击精灵跳跃一个高度,
双击精灵跳跃的高度比单击的高
三连击精灵跳跃的跟高
好了。開始动手吧。
新建项目。删除多余的代码
接着在Classes文件夹下建立两个文件,这里我就命名为Human了
(在Classes上右键加入新建项,选择头文件,名称Human.h,位置浏览到Classes文件夹下)
由于要实现精灵能接受触屏事件,所以我们不能用CCSprite ,须要自己写个类继承CCSprite和CCTouchDelegate
还记得CCTouchDelegate类吗??
OK 我们先实现头文件
#ifndef _Human_H_ #include "cocos2d.h" USING_NS_CC; class Human:public CCSprite,public CCTouchDelegate { public: virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent); virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent); virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent); virtual void onEnter(); virtual void onExit(); //创建静态方法,用于创建Human精灵 static Human* create(const char *pszFileName); private: }; #endif // !_Human_H_
重写的这5个方法应该不用解释了,上一节介绍过的
(教大家一个小技巧。比方我不记得触屏事件的名称或參数怎么写来着。没事,不用死机硬背的。鼠标放在CCTouchDelegate上F12,就能够看到它们都在,多点。单点等等,你复制一份就哦了。
)
接着我们来实现CPP文件
#include "Human.h" bool Human::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent) { CCLOG("ccTouchBegan"); return true; } void Human::ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent) { CCLOG("ccTouchMoved"); } void Human::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent) { CCLOG("ccTouchEnded"); } void Human::onEnter() { //继承,重载方法的步骤我们实现了,接下来就是注冊 //第一步:将我们须要处理触屏事件的类加入到事件队列中dispatcher CCSprite::onEnter(); CCTouchDispatcher *dispatcher= CCDirector::sharedDirector()->getTouchDispatcher(); dispatcher->addTargetedDelegate(this,0,true); } void Human::onExit() { //第二步:卸载 CCTouchDispatcher *dispatcher= CCDirector::sharedDirector()->getTouchDispatcher(); dispatcher->removeDelegate(this); } Human* Human::create(const char *pszFileName) { Human *pobSprite = new Human(); if (pobSprite && pobSprite->initWithFile(pszFileName)) { pobSprite->autorelease(); return pobSprite; } CC_SAFE_DELETE(pobSprite); return NULL; }
这里凝视非常具体了,或许大家写不出create方法里面的代码吧?写不出没关系,看得懂即可了。以后熟练了就能够写出来了。我们找到CCSprite中的create方法的实现代码。照着写即可了,主要将
CCSprite *pobSprite = new CCSprite();
改为
Human *pobSprite = new Human();
F6编译一下看看是否出错?
成功了?那接着
bool HelloWorld::init() { ////////////////////////////// // 1. super init first if ( !CCLayer::init() ) { return false; } Human *humanSprite=Human::create("Icon.png"); humanSprite->setPosition(ccp(240,30)); this->addChild(humanSprite); return true; }
这里不是CCSprite了,是我们自己定义的精灵。它能够接受触屏事件的响应
OK 执行。点击屏幕。看输出窗体
有个小问题。不一定点击精灵才触发事件,点击屏幕的不论什么地方都会触发事件。这不是我们想要的结果。
我们须要的是仅仅有触摸点在精灵图片的范围内才触发事件
OK,我们在新增一个方法 containsTouchLocation
//推断触摸点是否在精灵范围内 bool containsTouchLocation(CCTouch *pTouch);
实现
#ifndef _Human_H_ #include "cocos2d.h" USING_NS_CC; class Human:public CCSprite,public CCTouchDelegate { public: virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent); virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent); virtual void onEnter(); virtual void onExit(); //创建静态方法,用于创建Human精灵 static Human* create(const char *pszFileName); //推断触摸点是否在精灵范围内 bool containsTouchLocation(CCTouch *pTouch); private: }; #endif // !_Human_H_
CPP
#include "Human.h" bool Human::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent) { return true; } void Human::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent) { if (containsTouchLocation(pTouch)) { CCLOG("ccTouchEnded"); } } bool Human::containsTouchLocation(CCTouch *pTouch) { //首先须要获得精灵的大小,将它转换为一个CCRect(矩形) CCSize spriteSize= this->getContentSize(); CCRect rect=CCRectMake(-spriteSize.width/2,-spriteSize.height/2,spriteSize.width,spriteSize.height); //通过CCRect中的containsPoint。来推断这个矩形是否包括这个点 //这个点为我们的触摸点 if(!rect.containsPoint(this->convertTouchToNodeSpaceAR(pTouch))) { return false; } return true; } void Human::onEnter() { //继承,重载方法的步骤我们实现了,接下来就是注冊 //第一步:将我们须要处理触屏事件的类加入到事件队列中dispatcher CCSprite::onEnter(); CCTouchDispatcher *dispatcher= CCDirector::sharedDirector()->getTouchDispatcher(); dispatcher->addTargetedDelegate(this,0,true); } void Human::onExit() { //第二步:卸载 CCTouchDispatcher *dispatcher= CCDirector::sharedDirector()->getTouchDispatcher(); dispatcher->removeDelegate(this); } Human* Human::create(const char *pszFileName) { Human *pobSprite = new Human(); if (pobSprite && pobSprite->initWithFile(pszFileName)) { pobSprite->autorelease(); return pobSprite; } CC_SAFE_DELETE(pobSprite); return NULL; }
这里都有凝视了。
第一。先获得精灵的大小(ContentSize)将其转换为CCRect(矩形)
第二,利用CCRect中的containsPoint方法来推断这个矩形是否包括这个点。包括返回true否则反之
(这里须要把触摸点的位置转换为相对当前精灵节点的相对位置
我们介绍坐标系统的时候貌似仅仅提到过UIKIT坐标,OPGL坐标,事实上还有个相对坐标和世界坐标
我们在讲完这个实列之后再介绍。如今先这样写着)
这里另一句
CCRect rect=CCRectMake(-spriteSize.width/2,-spriteSize.height/2,spriteSize.width,spriteSize.height);
非常纳闷为什么是 -spriteSize.width/2
刚開始我也非常郁闷,根本看不懂。后来直接盯着这段代码不眨眼盯了半小时,瞬间懂了,
我们学习坐标系统都知道默认锚点是在中心点吧?精灵也是
我们得求出左下角点的x和y坐标,然后后面两个參数都懂的
如果精灵是40X40的图片,锚点在中心,所以中心点为0,0坐标 然后四个角的坐标如上图。
如今我们要的出左下角的坐标,瞬间懂了吗??
如今我们几乎相同完毕一半了。事实上我们在CCTouchEnded方法中完毕我们的跳跃效果,可是这仅仅是单击跳跃。多连击还是得我们自己实现
#ifndef _Human_H_ #include "cocos2d.h" USING_NS_CC; class Human:public CCSprite,public CCTouchDelegate { public: virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent); virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent); virtual void onEnter(); virtual void onExit(); //创建静态方法,用于创建Human精灵 static Human* create(const char *pszFileName); //推断触摸点是否在精灵范围内 bool containsTouchLocation(CCTouch *pTouch); //构造方法,初始化变量 Human(); //单击调用 void SignleClicked(float dt); //双击 void DoubleClicked(float dt); //三连击 void ThreeClicked(); private: //记录点击的次数 int clickedCount; }; #endif // !_Human_H_
这里添加了些方法
//构造方法,初始化变量 Human::Human():clickedCount(0) {} //单击调用 void Human::SignleClicked(float dt){ if (clickedCount==1) { clickedCount=0; CCActionInterval* jumpto= CCJumpBy::create(1.4f,CCPointZero,50,1); this->runAction(jumpto); } } //双击 void Human::DoubleClicked(float dt){ if (clickedCount==2) { clickedCount=0; CCActionInterval* jumpto= CCJumpBy::create(1.4f,CCPointZero,120,1); this->runAction(jumpto); } } //三连击 void Human::ThreeClicked(){ clickedCount=0; CCActionInterval* jumpto= CCJumpBy::create(1.4f,CCPointZero,220,1); this->runAction(jumpto); }
方法的实现大致是这样,推断变量的值,假设是1则运行单击跳跃高度为50。后面的不说了
接着我们在ccTouchEnded函数中用延迟的一个方法来实现各种点击
void Human::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent) { if (!containsTouchLocation(pTouch)) { return; } //假设点击在精灵上,则运行 if (clickedCount==2) { ThreeClicked(); } else if (clickedCount==1) { //延迟0.25秒运行双击 scheduleOnce(schedule_selector(Human::DoubleClicked),0.25f); clickedCount++; } else { //延迟0.25秒运行单击 scheduleOnce(schedule_selector(Human::SignleClicked),0.25f); clickedCount++; } }
这里逻辑有点转只是来,
如果。我们点击一次,它将会运行最后的else 。而单击的方法要在0.25秒后才运行可是此时变量的值已经为1了
然后我们在0.25秒的时间内在继续点击,它将运行第二个IF中的语句。同理,双击的方法也要在0.25秒后运行,可是此时变量的值已经是2了
这个大家多断点。自己多想想,说不清楚
OK,截止我们的多连击已经搞定了
总结一下:
首先。我们学会了怎样制定自己的精灵
怎样使自己的精灵能处理触屏事件
理解怎样完毕处理触屏事件的几个步骤
怎样推断触摸点是否是点击在指定的矩形区域中,这个非常重要哦
利用计时器延迟巧妙实现处理多连击事件
(还有哪些不懂的代码。自己能够先baidu一下)