- version: since Cocos2d-html5 v3.0 alpha0
Cocos2d-html5 3.0 introduces a new mechanism for responding to user events. This document explains how it works.
The basics:
- Event listeners encapsulate your event processing code.
- Event Manager manage listeners of user events.
- Event objects contain information about the event.
To respond to events, you must first create an cc.EventListener. There are five different kinds of EventListeners:
cc.EventListenerTouch
- responds to touch eventscc.EventListenerKeyboard
- responds to keyboard eventscc.EventListenerAcceleration
- responds to accelerometer eventscc.EventListenMouse
- responds to mouse eventscc.EventListenerCustom
- responds to custom events
Then, attach your event processing code to the appropriate callback on the event listener (e.g., onTouchBegan
for EventListenerTouch
listeners, or onKeyPressed
for keyboard event listeners).
Next, register your EventListener with the cc.eventManager.
When events occur (for example, the user touches the screen, or types on the keyboard), the cc.eventManager
distributes Event objects (e.g. EventTouch
, EventKeyboard
) to the appropriate EventListeners by calling your callbacks. Each Event object contains information about the event (for example, the coordinates where the touch occurred).
In the following example, we will add three overlapping buttons to a scene. Each will respond to touch events.
var sprite1 = cc.Sprite.create("Images/CyanSquare.png");
sprite1.x = size.width/2 - 80;
sprite1.y = size.height/2 + 80;
this.addChild(sprite1, 10);
var sprite2 = cc.Sprite.create("Images/MagentaSquare.png");
sprite2.x = size.width/2;
sprite2.y = size.height/2;
this.addChild(sprite2, 20);
var sprite3 = cc.Sprite.create("Images/YellowSquare.png");
sprite3.x = 0;
sprite3.y = 0;
sprite2.addChild(sprite3, 1);
//Create a "one by one" touch event listener (processes one touch at a time)
var listener1 = cc.EventListener.create({
event: cc.EventListener.TOUCH_ONE_BY_ONE,
// When "swallow touches" is true, then returning 'true' from the onTouchBegan method will "swallow" the touch event, preventing other listeners from using it.
swallowTouches: true,
//onTouchBegan event callback function
onTouchBegan: function (touch, event) {
// event.getCurrentTarget() returns the *listener's* sceneGraphPriority node.
var target = event.getCurrentTarget();
//Get the position of the current point relative to the button
var locationInNode = target.convertToNodeSpace(touch.getLocation());
var s = target.getContentSize();
var rect = cc.rect(0, 0, s.width, s.height);
//Check the click area
if (cc.rectContainsPoint(rect, locationInNode)) {
cc.log("sprite began... x = " + locationInNode.x + ", y = " + locationInNode.y);
target.opacity = 180;
return true;
}
return false;
},
//Trigger when moving touch
onTouchMoved: function (touch, event) {
//Move the position of current button sprite
var target = event.getCurrentTarget();
var delta = touch.getDelta();
target.x += delta.x;
target.y += delta.y;
},
//Process the touch end event
onTouchEnded: function (touch, event) {
var target = event.getCurrentTarget();
cc.log("sprite onTouchesEnded.. ");
target.setOpacity(255);
//Reset zOrder and the display sequence will change
if (target == sprite2) {
sprite1.setLocalZOrder(100);
} else if (target == sprite1) {
sprite1.setLocalZOrder(0);
}
}
});
cc.EventListener.create is a creator of all type of event listeners, parameter 'event' can be used to set event listener's type. for example 'cc.EventListener.TOUCH_ONE_BY_ONE' and cc.EventListenerTouchOneByOne .
Event type list:
- cc.EventListener.TOUCH_ONE_BY_ONE
- cc.EventListener.TOUCH_ALL_AT_ONCE
- cc.EventListener.KEYBOARD
- cc.EventListener.MOUSE
- cc.EventListener.ACCELERATION
- cc.EventListener.CUSTOM
// add listeners to cc.eventManager
cc.eventManager.addListener(listener1, sprite1);
cc.eventManager.addListener(listener1.clone(), sprite2);
cc.eventManager.addListener(listener1.clone(), sprite3);
cc.eventManager is a singleton object in Cocos2d-html5. You can use it to manage the dispatching state of all events. You can add listener to cc.eventManager through addListener
, addListener
supports two parameters: listener
and nodeOrPriority
, if nodeOrPriority
is a cc.Node or cc.Node's subclass object, it will add listener
as SceneGraphPriority, and if nodeOrPriority
is number value, it will add listener
as FixedPriority.
Note: In the example above, we use the clone()
method in the second and third calls to addListener
. This is because each event listener can be added only once. The methods addListener
set a registration flag on the event listener, and won't add the event listener again if the flag is already set.
One more thing to keep in mind: if you add a fixed priority listener to a node, you need to remove the listener manually when the node is removed. However, in the case of a scene graph priority listener, the listener is bound to the node: when the node's destructor is called, the listener will be removed automatically.
cc.eventManager.addListener({
event: cc.EventListener.TOUCH_ALL_AT_ONCE,
onTouchesMoved: function (touches, event) {
var touch = touches[0];
var delta = touch.getDelta();
var node = event.getCurrentTarget().getChildByTag(TAG_TILE_MAP);
var diff = cc.pAdd(delta, node.getPosition());
node.setPosition(diff);
}
}, this);
cc.eventManager的 addListener
's first parameter listener
supports two types: cc.EventListener object and json object. if listener
is a json object, it will create a cc.EventListener object by json object.
The above procedures may seem more difficult compared to the event mechanism in version 2.x. In the old version, you would inherit from a delegate class, which defined onTouchBegan()
methods, etc. Your event handling code would go into these delegate methods.
This new event mechanism removes the event processing logic from the delegate and encapsulates it into a listener. However, the logic above implements the functions below:
- By using an event listener, a sprite can be added to the event manager with SceneGraphPriority. That is, when clicking a sprite button, callback functions will be called in the same order they are drawn in (that is, sprites that are in front of other sprites will get the touch events first).
- When dealing with event logical, according to each kind of situations to solve the logics when touched(such as recognize click area, set clicked element as different transparency) to display the click effect.
- As
swallowTouches: true,
is setted and some decisions has been made in onTouchBegan to get the return value, whether the display order of the touch event should pass back can be solved.
The eventManager 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 higherPriority
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.
##Other event dispatch handling modules
In addition to touch event response, the following modules using the same event handling approach.
###Keyboard events
In addition to keyboard, it also can be every menu of the device, they can use the same listener to deal with the event.
//add a keyboard event listener to statusLabel
cc.eventManager.addListener({
event: cc.EventListener.KEYBOARD,
onKeyPressed: function(keyCode, event){
var label = event.getCurrentTarget();
label.setString("Key " + keyCode.toString() + " was pressed!");
},
onKeyReleased: function(keyCode, event){
var label = event.getCurrentTarget();
label.setString("Key " + keyCode.toString() + " was released!");
}
}, statusLabel);
Before using accelerometer events, you need to enable them on the cc.inputManager:
cc.inputManager.setAccelerometerEnabled(true);
Then create the corresponding listener.
cc.eventManager.addListener({
event: cc.EventListener.ACCELERATION,
callback: function(acc, event){
// Processing logic here
}
}, sprite);
###Mouse events
Mouse click event dispatching and touch event dispatching have been managed by cc.eventManager in version 3.0. It works multi-platform, and enrich the user experience of the game.
cc.eventManager.addListener({
event: cc.EventListener.MOUSE,
onMouseMove: function(event){
var str = "MousePosition X: " + event.getLocationX() + " Y:" + event.getLocationY();
// do something...
},
onMouseUp: function(event){
var str = "Mouse Up detected, Key: " + event.getButton();
// do something...
},
onMouseDown: function(event){
var str = "Mouse Down detected, Key: " + event.getButton();
// do something...
},
onMouseScroll: function(event){
var str = "Mouse Scroll detected, X: " + event.getLocationX() + " Y:" + event.getLocationY();
// do something...
}
},this);
###Custom Event
The event types above are defined by the system, and the events (such as touch screen, keyboard response etc.) are triggered by the system automatically. In addition, you can make your own custom events which are not triggered by the system, but by your code, as follows:
var _listener1 = cc.EventListener.create({
event: cc.EventListener.CUSTOM,
eventName: "game_custom_event1",
callback: function(event){
statusLabel.setString("Custom event 1 received, " + event.getUserData() + " times");
}
});
cc.eventManager.addListener(this._listener1, 1);
A custom event listener has been defined above, with a response method, and added to the event dispatcher. So how is the event handler triggered? Check it out:
++selfPointer._item1Count;
var event = new cc.EventCustom("game_custom_event1");
event.setUserData(selfPointer._item1Count.toString());
cc.eventManager.dispatchEvent(event);
The above example creates an EventCustom
object and sets its UserData. It is then dispatched manually with cc.eventManager.dispatchEvent(event);
. This triggers the event handler defined previously.
###Removing event listeners
An added listener can be removed with following method:
cc.eventManager.removeListener(listener); //remove a listener from cc.eventManager
All of added listeners by event listener type or by a node object can be removed with following method:
//remove listeners by EventListener type (TOUCH_ONE_BY_ONE)
cc.eventManager.removeListeners(cc.EventListener.TOUCH_ONE_BY_ONE);
//remove listener by a node object(aSprite)
cc.eventManager.removeListeners(aSprite);
To remove all the listeners of the cc.eventManager, use the following code:
cc.eventManager.removeAllListeners();
When using removeAll
, all the listeners of this node can be removed. Removing specific listener is a recommending way.
Note: After using removeAll
menu can not respond, because it also needs accepting touch event.
In the game development process, we often encounter such a situation: we want to disable a node object's event, and need to resume this node on some event later. For example: developers want a model dialog, it needs to disable all event handlers of background when the dialog is showing. If user closes the dialog, it should resume all event handler of background.
We need to pause the root node's event handlers, let all event listeners of it and its children paused, use the following code:
//pause aLayer and its children's event listener
cc.eventManager.pauseTarget(aLayer, true);
And resuming the event listeners of a node is very simple, use this code:
//resume aLayer and its children's event listener
cc.eventManager.resumeTarget(aLayer, true);
Note: The second parameter (recursive) is optional, default value is false. It indicates whether calling its children's pauseTarget/resumeTarget function recursively
Properties/functions | Type | Parameters | Usage |
---|---|---|---|
getType | Number | no | Gets the event type:TOUCH, KEYBOARD, ACCELERATION, MOUSE, CUSTOM |
stopPropagation | void | no | Stops propagation for current event |
isStopped | Boolean | no | Checks whether the event has been stopped |
getCurrentTarget | cc.Node | no | Gets current target of the event |
cc.EventCustom
inherits from cc.Event
Properties/functions | Type | Parameters | Usage |
---|---|---|---|
setUserData | void | data: user data | Sets user data |
getUserData | * | no | Gets user data |
getEventName | String | no | Gets event name |
cc.EventMouse
inherits from cc.Event
Properties/functions | Type | Parameters | Usage |
---|---|---|---|
setScrollData | void | scrollX, scrollY | sets scroll data |
getScrollX | Number | no | gets scrollX data |
getScrollY | Number | no | gets scrollY data |
setLocation | void | x, y | Set cursor location |
getLocation | cc.Point | no | Get cursor location |
getLocationInView | cc.Point | no | Returns the current cursor location in screen coordinates |
getDelta | cc.Point | no | Get delta data |
setButton | void | button | Sets mouse button |
getButton | Number | no | Gets mouse button |
cc.EventTouch
inherits from cc.Event
Properties/functions | Type | Parameters | Usage |
---|---|---|---|
getEventCode | Number | no | Gets event code: BEGAN, MOVED, ENDED, CANCELLED |
getTouches | Array | no | Get touches of event |
Properties/functions | Type | Parameters | Usage |
---|---|---|---|
checkAvailable | boolean | no | Checks whether the listener is available. |
clone | cc.EventListener | no | Clones the listener, its subclasses have to override this method. |
create | cc.EventListener | json object | create event listener by json object |
Create an EventListenerTouchOneByOne object:
event: cc.EventListener.TOUCH_ONE_BY_ONE
optional parameters:
- swallowTouches, boolean, checks whether swallow touches
- onTouchBegan, function, Touch began event callback
- onTouchMoved, function, Touch moved event callback
- onTouchEnded, function, Touch ended event callback
- onTouchCancelled, function, Touch cancelled event callback
Create an EventListenerTouchAllAtOnce object:
event: cc.EventListener.TOUCH_ALL_AT_ONCE
optional parameters:
- onTouchesBegan, function, Touches began event callback
- onTouchesMoved, function, Touches moved event callback
- onTouchesEnded, function, Touches ended event callback
- onTouchesCancelled, function, Touches cancelled event callback
Create an EventListenerKeyboard object:
event: cc.EventListener.KEYBOARD
optional parameters:
- onKeyPressed, function, Key pressed (key down) event callback
- onKeyReleased, function, key release (key up) event callback
Create an EventListenerMouse object:
event: cc.EventListener.MOUSE
optional parameters:
- onMouseDown, function, Mouse down event callback
- onMouseUp, function, Mouse up event callback
- onMouseMove, function, Mouse move event callback
- onMouseScroll, function, Mouse scroll event callback
Create an EventListenerAcceleration object:
event: cc.EventListener.ACCELERATION
optional parameters:
- callback, function, Accelerometer event callback
Create an EventListenerCustom object:
event: cc.EventListener.CUSTOM
optional parameters:
- callback, function, Custom event callback
Properties/functions | Type | Parameters | Usage |
---|---|---|---|
pauseTarget | void | node, recursive | Pauses all listeners which are associated the specified target. |
resumeTarget | void | node, recursive | Resumes all listeners which are associated the specified target. |
addListener | void | json object | cc.EventListener, node |
addCustomListener | void | eventName, callback | Adds a Custom event listener. |
removeListener | void | listener | Remove a listener |
removeListeners | void | listenerType | cc.Node, recursive |
removeCustomListeners | void | customEventName | Removes all custom listeners with the same event name |
removeAllListeners | void | no | Removes all listeners |
setPriority | void | listener, fixedPriority | Sets listener's priority with fixed value. |
setEnabled | void | enabled | Whether to enable dispatching events |
isEnabled | boolean | no | Checks whether dispatching events is enabled |
dispatchEvent | void | event | Dispatches the event, also removes all EventListeners marked for deletion from the event dispatcher list. |
dispatchCustomEvent | void | eventName, optionalUserData | Dispatches a Custom Event with a event name an optional user data |