Layer类的一个重要作用就是接受输入事件,它封装了触摸输入的处理接口。一般情况下,我们可以通过setTouchEnabled方法来开启或关闭接收触摸输入。事实上并不是只有Layer才支持接收触摸事件,任何一个游戏元素都可以接收事件,只不过Layer提供了现成的支持。
我们只需通过创建一个事件监听器用来实现各种触发后的逻辑,然后添加到事件分发器_eventDispatcher中,所有事件监听器由这个分发器统一管理,即可完成事件响应。
为一个精灵添加触摸事件的四个步骤
1.创建一个精灵
2.创建一个事件监听器(单点触摸或多点触摸)
3.实现各种触发后的逻辑(onTouchBegan,onTouchMoved,onTouchEnded等)
4.将事件监听器添加到事件分发器中
// 1.首先添加一个精灵元素 bool GameScene::init() { sprite = Sprite::create(); sprite->setPosition(100, 100); this->addChild(sprite); } void GameScene::addTouchEvent() { // 2.创建一个单点触摸监听器 auto touchListener = EventListenerTouchOneByOne::create(); // 3.实现触摸后的逻辑处理,使用lambda表达式实现触摸事件处理的回调函数 // 触摸开始 touchListener->onTouchBegan = [](Touch *touch, Event *event) { // 获取点击的openGL坐标 auto touchPos = touch->getLocation(); // 获取触摸事件的相关目标,即玩家飞机 auto target = static_cast<Sprite *>(event->getCurrentTarget()); // 获取飞机所在区域 auto playerPos = target->getPosition(); auto playerSize = target->getContentSize(); auto rect = Rect(playerPos.x - playerSize.width/2, playerPos.y - playerSize.height/2, playerSize.width, playerSize.height); if(rect.containsPoint(touchPos)) { return true; } // 返回false会导致后面的onTouchMoved和onTouchEnded不会执行 return false; }; // 滑动 touchListener->onTouchMoved = [](Touch *touch, Event *event) { auto touchPos = touch->getLocation(); auto target = static_cast<Sprite *>(event->getCurrentTarget()); target->setPosition(touchPos); }; // 触摸结束 touchListener->onTouchEnded = [](Touch *touch, Event *event) { log("touch end"); }; /* 4.最后将事件监听器添加到事件分发器_eventDispatcher中 _eventDispatcher是Node的属性,通过它管理当前节点(场景、层、精灵等)的所有事件的分发。但它本身是一个单例模式值的引用,在Node的构造函数中,通过Director::getInstance()->getEventDispatcher(); 获取,有了这个属性,就能方便的处理事件。 */ // _eventDispatcher = Director::getInstance()->getEventDispatcher(); _eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, sprite); // 为第二个精灵添加触摸监听_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener->clone(), sprite2); }
当再次使用touchListener 的时候,需要使用clone()方法创建一个新的克隆,因为在使用addEventListenerWithSceneGraphPriority或者addEventListenerWithFixedPriority方法时,会对当前使用的事件监听器添加一个已注册的标记,这使得它不能够被添加多次。另外,有一点非常重要,FixedPriority listener添加完之后需要手动remove,而SceneGraphPriority listener是跟Node绑定的,在Node的析构函数中会被移除。具体的示例用法可以参考引擎自带的tests。
我们可以通过以下方法移除一个已经被添加了的监听器。
_eventDispatcher->removeEventListener(listener);
也可以使用如下方法,移除当前事件分发器中所有监听器。
_eventDispatcher->removeAllEventListeners();
当使用removeAll的时候,此节点的所有的监听将被移除,推荐使用指定删除的方式。removeAll之后菜单也不能响应。因为它也需要接受触摸事件。
参考
事件分发机制