因为cocos2d-x引擎具有跨平台的特点,因此能够接收并处理的事件包括触摸事件,键盘事件,鼠标事件,加速度事件以及自定义事件等等。
现在的人机交互中,事件处理机制一般包括三个角色:事件、事件源和事件处理者。事件源是事件发生的场所(例如cocos里面的node),事件接收者是接收事件并处理事件的一段程序。
1.事件
cocos提供的事件类是Event,其子类主要包括触摸事件(EventTouch)、鼠标事件(EventMouse)、键盘事件(EventKeyboard)、加速度事件(EventAccleration)和自定义事件(EventCustom),其事件类图如下:
2.事件处理者
在cocos2d-x中的事件处理者是事件监听器类EventListener。子类主要包括单点触摸监听器(EventListenerTouchOneByOne), 多点触摸监听器(EventListenerTouchAllAtOnce), 键盘事件监听器(EventListenerKeyBoard), 鼠标事件监听器(EventListenerMouse), 加速度事件监听器(EventListenerAccleration), 自定义事件监听器(EventListenerCustom)。其类图如下所示:
3.由上面可以看出每一种事件都与其相对应的事件监听器绑定在一起,而这种绑定关系的过程被称为”注册监听器”。在cocos2d-x中,提供了一个事件分发器(EventDispatcher)来负责这种关系。也就是说事件监听器负责注册监听器、注销监听器、分发事件。
EventDispatcher类是一个单例类,Director::getInstance()->getEventDispatcher()可以得到事件分发器实例。EventDispatcher有两个注册监听器的函数,分别为:
void addEventListenerWithSceneGraphPriority(EventListener* listener, Node* node);
//这个注册函数是将精灵显示的优先级作为作为事件的优先级
void addEventListenerWithFixedPriority(EventListener* listener, int fixedPriority);
//制定固定的的时间优先级注册监听器,时间的优先级决定事件的响应优先级别,
//值越小,其优先级越高
EventListenerCustom* addCustomEventListener(const std::string &eventName, const std::function<void(EventCustom*)>& callback);
//注册一个自定义事件,第一个参数时自定义事件的名称,
//第二个参数时响应事件的事件处理函数
4.在不需要进行事件响应时,需把先前注册的事件监听器给注销掉, cocos给我们提供了如下几个注销函数
void removeEventListener(EventListener* listener);
//注销指定的事件监听器
void removeEventListenersForType(EventListener::Type listenerType);
//根据事件类型注销所有的事件监听器
void removeEventListenersForTarget(Node* target, bool recursive = false);
//根据与事件绑定的节点来注销事件监听器
void removeCustomEventListeners(const std::string& customEventName);
//根据事件名注销自定义事件监听器
void removeAllEventListeners();
//注销所有事件监听器,使用该函数,所有触摸将不可用,包括菜单
二、事件运用
1.触摸事件
EventListenerTouchOneByOne处理函数
std::function<bool(Touch*, Event*)> onTouchBegan;
//当手指刚开始触摸时调用,返回true时调用后面的函数
std::function<void(Touch*, Event*)> onTouchMoved;
//当手指在屏幕上移动时调用
std::function<void(Touch*, Event*)> onTouchEnded;
//当手指离开屏幕时调用
std::function<void(Touch*, Event*)> onTouchCancelled;
//当单点触摸事件被取消时调用
EventListenerTouchAllAtOnce(多点触控)
std::function<void(const std::vector<Touch*>&, Event*)> onTouchesBegan;
std::function<void(const std::vector<Touch*>&, Event*)> onTouchesMoved;
std::function<void(const std::vector<Touch*>&, Event*)> onTouchesEnded;
std::function<void(const std::vector<Touch*>&, Event*)> onTouchesCancelled;
单点触摸实例:
Scene* HelloWorld::createScene()
{
// 'scene' is an autorelease object
auto scene = Scene::create();
// 'layer' is an autorelease object
auto layer = HelloWorld::create();
// add layer as a child to scene
scene->addChild(layer);
// return the scene
return scene;
}
// on "init" you need to initialize your instance
bool HelloWorld::init()
{
//
Size visibleSize = Director::getInstance()->getVisibleSize();
Point origin = Director::getInstance()->getVisibleOrigin();
// 1. super init first
if ( !Layer::init() )
{
return false;
}
auto labe1 = LabelBMFont::create("HelloWorld", "fonts/Roboto.bmf.fnt");
addChild(labe1, 1);
labe1->setPosition(Point(visibleSize.width / 2, visibleSize.height / 2));
labe1->setOpacity(200); //设置透明度
// add the label as a child to this layer
//创建一个单点触控事件监听器
auto listener = EventListenerTouchOneByOne::create();
//如果事件被处理,则吞没该事件不继续分发
listener->setSwallowTouches(true);
listener->onTouchBegan = CC_CALLBACK_2(HelloWorld::touchBegin, this);
listener->onTouchMoved = CC_CALLBACK_2(HelloWorld::touchMoved, this);
listener->onTouchEnded = CC_CALLBACK_2(HelloWorld::touchEnded, this);
//注册监听器
EventDispatcher *eventDispatcher = Director::getInstance()->getEventDispatcher();
eventDispatcher->addEventListenerWithSceneGraphPriority(listener, labe1);
return true;
}
bool HelloWorld::touchBegin(Touch *touch, Event *event)
{
log("touchbegin");
return true;
}
void HelloWorld::touchMoved(Touch *touch, Event *event)
{
log("touchmove");
}
void HelloWorld::touchEnded(Touch *touch, Event *event)
{
log("touchend");
}
运行结果
在cocos3.0之后,可以使用C++11标准的lambda表达式简化回掉代码
//创建一个单点触控事件监听器
auto listener = EventListenerTouchOneByOne::create();
//如果事件被处理,则吞没该事件不继续分发
listener->setSwallowTouches(true);
listener->onTouchBegan = [](Touch *touch, Event *event)
{
log("touchbegin");
return true;
};
listener->onTouchMoved = [](Touch *touch, Event *event)
{
log("touchmove");
};
listener->onTouchEnded = [](Touch *touch, Event *event)
{
log("touchend");
};
//注册监听器
EventDispatcher *eventDispatcher = Director::getInstance()->getEventDispatcher();
eventDispatcher->addEventListenerWithSceneGraphPriority(listener, labe1);
2.键盘事件
使用方法与单点触控类似
std::function<void(EventKeyboard::KeyCode, Event*)> onKeyPressed; //按键按下调用
std::function<void(EventKeyboard::KeyCode, Event*)> onKeyReleased; //按键弹起调用
3.鼠标事件
std::function<void(Event* event)> onMouseDown; //鼠标按下
std::function<void(Event* event)> onMouseUp; //鼠标抬起
std::function<void(Event* event)> onMouseMove; //鼠标移动
std::function<void(Event* event)> onMouseScroll;//鼠标滚轮滚动
三、在层中处理触摸
因为层是一个特殊的节点,因此除了上述方法响应事件外,cocos还单独为层重写了事件处理函数以方便调用
virtual bool onTouchBegan(Touch *touch, Event *unused_event);
virtual void onTouchMoved(Touch *touch, Event *unused_event);
virtual void onTouchEnded(Touch *touch, Event *unused_event);
virtual void onTouchCancelled(Touch *touch, Event *unused_event);
virtual void onTouchesBegan(const std::vector<Touch*>& touches, Event *unused_event);
virtual void onTouchesMoved(const std::vector<Touch*>& touches, Event *unused_event);
virtual void onTouchesEnded(const std::vector<Touch*>& touches, Event *unused_event);
virtual void onTouchesCancelled(const std::vector<Touch*>&touches, Event *unused_event);
因为层中的事件处理是针对于整个Layer,因此如果想要得到具体点击的是Layer上的精灵,需要我们自己去判断,而不能指定具体精灵对象的优先级。
加速度事件
加速度时间的处理与前面类似,但是也有着细微的区别,一般处理工程如下:
//启用加速度硬件设备
Device::setAccelerometerEnabled(true);
//注册监听器
EventDispatcher *eventDispatcher = Director::getInstance()->getEventDispatcher();
auto listener = EventListenerAcceleration::create([](Acceleration *acc, Event *event){
log("EventListenerAcceleration");
});
这里 就了解了cocos常用事件的处理机制,能更灵活的运用它们。