ProgrammingGuide > Event Dispatcher

Event Dispatcher

version: Cocos2d-x v3.x
update: Updated almost 3 years ago

What is the EventDispatch mechanism?

EventDispatch is a mechanism for responding to user events.

The basics:

  • Event listeners encapsulate your event processing code.
  • Event dispatcher notifies listeners of user events.
  • Event objects contain information about the event.

5 types of event listeners.

EventListenerTouch - responds to touch events

EventListenerKeyboard - responds to keyboard events

EventListenerAcceleration - responds to accelerometer events

EventListenMouse - responds to mouse events

EventListenerCustom - responds to custom events

FixedPriority vs SceneGraphPriority

The EventDispatcher uses priorities to decide which listeners get delivered an event first.

FixedPriority is an integer value. Event listeners with lower Priority values get to process events before event listeners with higher Priority values.

SceneGraphPriority is a pointer to a Node. Event listeners whose Nodes have higher z-order values (that is, are drawn on top) receive events before event listeners whose Nodes have lower Z order values (that is, are drawn below). This ensures that touch events, for example, get delivered front-to-back, as you would expect.

Remember Chapter 2? Where we talked about the scene graph and we talked about this diagram?

Well, when use SceneGraphPriority you are actually walking this above tree backwards... I, H, G, F, E, D, C, B, A. If an event is triggered, H would take a look and either swallow it (more on this below) or let is pass through to I. Same thing, I will either consume it or let is pass thought to G.. and so on until the event either swallowed or it does not get answered.

Touch Events

Touch events are the most important event in mobile gaming. They are easy to create and provide versatile functionality. Let's make sure we know what a touch event is. When you touch the screen of your mobile device, it accepts the touch, looks at where you touched and decides what you touched. Your touch is then answered. It is possible that what you touched might not be the responding object but perhaps something underneath it. Touch events are usually assigned a priority and the event with the highest priority is the one that answers. Here is how you create a basic touch event listener:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//  Create a "one by one" touch event listener
// (processes one touch at a time)
auto listener1 = EventListenerTouchOneByOne::create();

// trigger when you push down
listener1->onTouchBegan = [](Touch* touch, Event* event){
    // your code
    return true; // if you are consuming it
};

// trigger when moving touch
listener1->onTouchMoved = [](Touch* touch, Event* event){
    // your code
};

// trigger when you let up
listener1->onTouchEnded = [=](Touch* touch, Event* event){
    // your code
};

// Add listener
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, this);

As you can see there are 3 distinct events that you can act upon when using a touch event listener. They each have a distinct time in which they are called.

onTouchBegan is triggered when you press down.

onTouchMoved is triggered if you move the object around while still pressing
down.

onTouchEnded is triggered when you let up on the touch.

Swallowing Events

When you have a listener and you want an object to accept the event it was given you must swallow it. In other words you comsume it so that it doesn't get
passed to other objects in highest to lowest priority. This is easy to do.

1
2
3
4
5
6
7
8
9
10
11
12
// When "swallow touches" is true, then returning 'true' from the
// onTouchBegan method will "swallow" the touch event, preventing
// other listeners from using it.
listener1->setSwallowTouches(true);

// you should also return true in onTouchBegan()

listener1->onTouchBegan = [](Touch* touch, Event* event){
    // your code

    return true;
};

Creating a keyboard event

For dekstop games, you might want find using keyboard mechanics useful. Cocos2d-x supports keyboard events. Just like with touch events above, keyboard events are easy to create.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// creating a keyboard event listener
auto listener = EventListenerKeyboard::create();
listener->onKeyPressed = CC_CALLBACK_2(KeyboardTest::onKeyPressed, this);
listener->onKeyReleased = CC_CALLBACK_2(KeyboardTest::onKeyReleased, this);

_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);

// Implementation of the keyboard event callback function prototype
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 an accelerometer event

Some mobile devices come equipped with an accelerometer. An accelerometer is a sensor that measures g-force as well as changes in direction. A use case would
be needing to move your phone back and forth, perhaps to simulate a balancing act. Cocos2d-x also supports these events and creating them is simple. Before using accelerometer events, you need to enable them on the device:

1
Device::setAccelerometerEnabled(true);
1
2
3
4
5
6
7
8
9
10
11
// creating an accelerometer event
auto listener = EventListenerAcceleration::create(CC_CALLBACK_2(
AccelerometerTest::onAcceleration, this));

_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);

// Implementation of the accelerometer callback function prototype
void AccelerometerTest::onAcceleration(Acceleration* acc, Event* event)
{
    //  Processing logic here
}

Creating a mouse event

As it always has Cocos2d-x supports mouse events.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
_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());
    // ...
}

Registering event with the dispatcher

It is easy to register an event with the Event Dispatcher. Taking the sample touch event listener from above:

1
2
// Add listener
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, sprite1);

It is important to note that a touch event can only be registered once per object. If you need to use the same listener for multiple objects you should
use clone().

1
2
3
4
5
6
7
// Add listener
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, sprite1);

// Add the same listener to multiple objects.
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1->clone(), sprite2);

_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1->clone(), sprite3);

Removing events from the dispatcher

An added listener can be removed with following method:

1
_eventDispatcher->removeEventListener(listener);

Although they may seem special, built-in Node objects use the event dispatcher in the same way we have talked out. Makes senese right? Take Menu for an example. When you have a Menu with MenuItems when you click them you are dispatching a event. You can also removeEventListener() on built-in Node objects.

For advanced developers, please refer to EventDispatcher Mechanism and How to Enable Multi-Touch. These 2 docs are probably outdated, but they can help you dive into more details how the event dispatcher was designed.

in-order-walk.png (42.8 kB) walzer@cocos2d-x.org, 2014-12-03 06:13

Sign up for our newsletter to keep up with the latest developments, releases and updates for Cocos2d-x.