📜 ⬆️ ⬇️

Cocos2d-x - Event Manager

From translator


Good day! This article is a translation of documentation for the Cocos2d-x engine.

In the previous parts we have already reviewed most of the main components of the engine:

Sprite
Action
UI Components
Scene and others
')
We have very little left to create a full-fledged game. Namely, to ensure the gameplay itself. For this, in Cocos2d-x there is an event dispatcher .

Event Manager


What is the EventDispatch mechanism? EventDispatch is a mechanism for responding to user events.

Basics :


5 types of event listeners


EventListenerTouch - reacts to a touch screen

EventListenerKeyboard - responds to keystrokes

EventListenerAcceleration - reacts to accelerometer events

EventListenMouse - reacts to mouse events

EventListenerCustom - responds to custom events

FixedPriority vs SceneGraphPriority


EventDispatcher uses priorities to decide which listeners will receive the event first.

Fixed Priority (fixed priority) is an integer value. Event listeners with a lower priority value receive events for processing earlier than listeners with a high priority value.

Scene Graph Priority is a pointer to a Node object. Event listeners whose nodes have a higher z-order value (which are drawn from above) receive events before listeners whose nodes have lower z-order values ​​(which are drawn from below). This ensures that touch events will receive the front elements, as you would expect.

Remember the scene graph ? When did we talk about this chart?

image

When using Scene Graph Priority, you actually pass this tree in the opposite direction ... I , H , G , F , E , D , C , B , A. If an event fires, H will notice it and either swallow it (more on this below), or skip on to I. Same with I , it will either consume the action, or skip it further to G , and so on.

Touch events


Touch events are the most important mobile gaming events. They are easy to create and provide flexible functionality. Let's clarify what a touch event is. When you touch the screen of your mobile device, it perceives the touch, looks where you touched and decides what you clicked on. Then, you get the answer. You may not have touched the active object, but something below it. Touch events are usually given priority, and the event with the highest priority responds.

How to create a basic touch event listener:

//  ""    // (    ) auto listener1 = EventListenerTouchOneByOne::create(); //    listener1->onTouchBegan = [](Touch* touch, Event* event){ //   return true; //     }; //     listener1->onTouchMoved = [](Touch* touch, Event* event){ //   }; //    listener1->onTouchEnded = [=](Touch* touch, Event* event){ //   }; //   _eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, this); 

As you can see, there are 3 separate actions that you can use for the tap listener. Each of them is called under certain conditions.

onTouchBegan - triggered when pressed.

onTouchMoved - triggered when a touch is moved.

onTouchEnded - triggered when released.

Absorption of events


When you have a listener and you want the object to accept the event, you must absorb it. In other words, you accept it so that it does not go further, to other objects with a lower priority. It is easy to implement.

 //  "" ,  true //  onTouchBegan   , //       listener1->setSwallowTouches(true); //     true  onTouchBegan() listener1->onTouchBegan = [](Touch* touch, Event* event){ //   return true; }; 


Creating keyboard events


For computer games, you may need to use the keyboard. Cocos2d-x supports keyboard. Like touch events, keyboard events are easily created.

 //     auto listener = EventListenerKeyboard::create(); listener->onKeyPressed = CC_CALLBACK_2(KeyboardTest::onKeyPressed, this); listener->onKeyReleased = CC_CALLBACK_2(KeyboardTest::onKeyReleased, this); _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this); //   callback  void KeyboardTest::onKeyPressed(EventKeyboard::KeyCode keyCode, Event* event) { log("Key with keycode %d pressed", keyCode); } void KeyboardTest::onKeyReleased(EventKeyboard::KeyCode keyCode, Event* event) { log("Key with keycode %d released", keyCode); } 

Creating accelerometer events


Some mobile devices are equipped with an accelerometer. An accelerometer is a sensor that measures overload as well as changes in direction. Used, for example, when you need to move the phone from side to side, to simulate a balancing action. Cocos2d-x also supports these events. Before using accelerometer events, you need to connect them.

 Device::setAccelerometerEnabled(true); 

 //   auto listener = EventListenerAcceleration::create(CC_CALLBACK_2( AccelerometerTest::onAcceleration, this)); _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this); //   callback  void AccelerometerTest::onAcceleration(Acceleration* acc, Event* event) { // Processing logic here } 

Create mouse events


As always, Cococ2d-x supports mouse events.

 _mouseListener = EventListenerMouse::create(); _mouseListener->onMouseMove = CC_CALLBACK_1(MouseTest::onMouseMove, this); _mouseListener->onMouseUp = CC_CALLBACK_1(MouseTest::onMouseUp, this); _mouseListener->onMouseDown = CC_CALLBACK_1(MouseTest::onMouseDown, this); _mouseListener->onMouseScroll = CC_CALLBACK_1(MouseTest::onMouseScroll, this); _eventDispatcher->addEventListenerWithSceneGraphPriority(_mouseListener, this); void MouseTest::onMouseDown(Event *event) { //   ... EventMouse* e = (EventMouse*)event; string str = "Mouse Down detected, Key: "; str += tostr(e->getMouseButton()); } void MouseTest::onMouseUp(Event *event) { //   ... EventMouse* e = (EventMouse*)event; string str = "Mouse Up detected, Key: "; str += tostr(e->getMouseButton()); } void MouseTest::onMouseMove(Event *event) { //   ... EventMouse* e = (EventMouse*)event; string str = "MousePosition X:"; str = str + tostr(e->getCursorX()) + " Y:" + tostr(e->getCursorY()); } void MouseTest::onMouseScroll(Event *event) { //   ... EventMouse* e = (EventMouse*)event; string str = "Mouse Scroll detected, X: "; str = str + tostr(e->getScrollX()) + " Y: " + tostr(e->getScrollY()); } 

Create custom events


The types of events described above are determined by the system, these events (such as touching the screen, pressing a key, etc.) are processed by the system automatically. In addition, you can make your own event, which will be handled not by the system, but by your code.

 _listener = EventListenerCustom::create("game_custom_event1", [=](EventCustom* event){ std::string str("Custom event 1 received, "); char* buf = static_cast<char*>(event->getUserData()); str += buf; str += " times"; statusLabel->setString(str.c_str()); }); _eventDispatcher->addEventListenerWithFixedPriority(_listener, 1); 

A user event listener was defined with a reaction method and added to the event dispatcher. How will a custom event be triggered? See further:

 static int count = 0; ++count; char* buf[10]; sprintf(buf, "%d", count); EventCustom event("game_custom_event1"); event.setUserData(buf); _eventDispatcher->dispatchEvent(&event); 

In the example above, we created an EventCustom object and set the value to UserData . Then, the event is triggered manually using _eventDispatcher-> dispatchEvent (& event) . This triggers a previously defined event. The event handler is called directly, therefore, as a UserData parameter, a local variable of the stack can be used.

Event registration in the manager


Registering an event is easy. Here is an example for a touch event listener:

 //   _eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, sprite1); 

It is important to note that a touch event can only be registered to one object. If you need to use one listener for multiple objects, you need to use clone () for this.

 //   _eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, sprite1); //        _eventDispatcher->addEventListenerWithSceneGraphPriority(listener1->clone(), sprite2); _eventDispatcher->addEventListenerWithSceneGraphPriority(listener1->clone(), sprite3); 

Removing events from the manager


We can remove it from the controller using the following method:

 _eventDispatcher->removeEventListener(listener); 

Although they may seem special, embedded Node objects use the event dispatcher by the same method we talked about. It makes sense, right? Take the Menu for an example. When you click on menu items, an event is triggered. Node listeners are also easy to delete.

From translator


Here we are with the main components of the engine! The next chapters are mostly very short, and most of them are covered by just one example of code. I think that it would be inappropriate to lay them out one by one on Habr. Conscience won't let me. Mixing threads is also not a good idea.

But nevertheless, I plan to publish some more lessons, which will no longer be pure translations. Below I will leave a survey to find out what will be interesting to you. Also, you can offer your options in the comments.

Source: https://habr.com/ru/post/341066/


All Articles