因爲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常用事件的處理機制,能更靈活的運用它們。