上一篇中介绍了坐标转换的问题,这一篇就来浅谈关于cocos2dx中比较重要的一个知识点-------触摸机制。
在游戏中,不仅仅只需要画面的变动,更多的是需要与其中的实体对象进行交互。PC端的游戏可以通过鼠标、键盘,而对于移动端更多的是用触摸。所以,这里所讲的触摸也基本针对移动端的。当然,往往在我们PC端开发过程中,鼠标能够当作一个触摸点来进行交互。但是,这远远不够的,毕竟移动端在触摸的时候肯定有多点的交互。
好了,说的那么多,我们就进入正题吧~
cocos2dx的触摸机制中,有单点触摸及多点触摸。这里先来说说单点的触摸。
我们先来看看我们需要做出什么效果,如下图所示:
通过上图可以看出,场景中有两个颜色方块,我们通过鼠标点击方块后移动鼠标可以拖动方块。移动后的方块可以显示在另外一个方块的上面,即覆盖它。
这是个简单的例子,在解释如何实现之前,我们需要知道要实现触摸大概的步骤,有三步:
1.创建触摸监听器;
2.为监听器分配相关的触摸回调方法;
3.分发监听器
好,现在就直接来看实现的源码吧:
TouchEventTest.h:
#ifndef __TOUCH_EVENT_TEST_H__ #define __TOUCH_EVENT_TEST_H__ #include "cocos2d.h" USING_NS_CC; class TouchEventTest : public Layer { public: static Scene* createScene(); virtual bool init(); CREATE_FUNC(TouchEventTest); }; #endif
#include "TouchEventTest.h" Scene* TouchEventTest::createScene() { auto scene = Scene::create(); auto layer = TouchEventTest::create(); scene->addChild(layer); return scene; } bool TouchEventTest::init() { if ( !Layer::init() ) { return false; } auto visibleSize = Director::getInstance()->getVisibleSize(); //方块一 LayerColor *layer1 = LayerColor::create(Color4B::RED, 100, 100); this->addChild(layer1); layer1->ignoreAnchorPointForPosition(false);<span style="white-space:pre"> </span>//不忽略锚点 layer1->setAnchorPoint(Vec2::ANCHOR_MIDDLE);<span style="white-space:pre"> </span>//设置锚点为中心点 layer1->setPosition(visibleSize.width / 2, visibleSize.height / 2); //方块二 LayerColor *layer2 = LayerColor::create(Color4B::GREEN, 100, 100); this->addChild(layer2); layer2->ignoreAnchorPointForPosition(false); layer2->setAnchorPoint(Vec2::ANCHOR_MIDDLE); layer2->setPosition(Vec2(layer1->getPositionX() + 200, layer1->getPositionY())); //创建监听器 auto listener1 = EventListenerTouchOneByOne::create(); listener1->setSwallowTouches(true); //为监听器分配回调函数 listener1->onTouchBegan = [](Touch *t, Event *e){ CCLOG("listener1 touch begin!!!!"); /******************************* **获取被点击的对象, **并获取点击的点是否在对象中,这里点击的点是OpenGL的坐标点,转换为当前对象内的点 **如果在,设置透明度为180, **并确认对象被点击事件,即return true ************************************/ auto target = dynamic_cast<Node*>(e->getCurrentTarget()); auto pos = target->convertToNodeSpace(t->getLocation()); Rect rect = { 0, 0, target->getContentSize().width, target->getContentSize().height }; if (rect.containsPoint(pos)){ //设置透明度,范围是:0~255,显示程度逐渐递增 target->setOpacity(180); return true; } return false; }; listener1->onTouchMoved = [](Touch *t, Event *e){ CCLOG("listener1 touch Move!!!!"); /************************************************* **移动被点击对象,随着鼠标位置的变化进行相对应移动 **************************************************/ auto target = dynamic_cast<Node*>(e->getCurrentTarget()); auto pos = Vec2(target->getPosition() + t->getDelta()); target->setPosition(pos); }; listener1->onTouchEnded = [=](Touch *t, Event *e){ CCLOG("listener1 touch Ended!!!!"); /**************************** **把被点击对象透明度设置回来,并判断应该覆盖的对象 **************************/ auto target = dynamic_cast<Node*>(e->getCurrentTarget()); target->setOpacity(255); if (target == layer1){ layer1->setLocalZOrder(10); layer2->setLocalZOrder(0); } else if (target == layer2){ layer1->setLocalZOrder(0); layer2->setLocalZOrder(10); } }; //克隆监听器一 auto listener2 = listener1->clone(); //分发监听事件 _eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, layer1); _eventDispatcher->addEventListenerWithSceneGraphPriority(listener2, layer2); return true; }以上就是那个例子的实现。可能在分发函数的回调的时候会有点疑虑,就是这个:
var->onTouchBegan = [](Touch *t, Event *e){ //.... }这是C++11所支持的新特性,lamda表达式,它是一个匿名函数。而这里所分发的就是回调的函数,所以里面所实现的就是回调函数所需要的。
在lamda表达式中,有一个关键的地方,就是[ ]里面的符号问题,我们来看下它的语法:
[capture list] (parameter list) ->return type { function body }
关于方括号里面的所填的内容一般如下:
"this" : 把当前节点作为捕获的值,所以可以捕获当前节点中所有的子类或是变量属性;
"=" : 把该lamda函数外的一层属性变量拷贝一份,所以可以捕获外层的属性变量;
"&" : 把该lamda函数外的一层属性变量引用进来,所以可以捕获外层的属性变量并改变其值。
对于上面的代码,方括号里面填了“=”的来获取外面一层的所有变量并复制一份。这样,外面一层的方块变量layer1和layer2均可获取得到。
好了,以上就是单点触摸的简单介绍,下一篇会更进一步的对触摸相关的进行讲解。