事件分發機制
新事件分發機制:在2.x 版本號事件處理時。將要觸發的事件交給代理(delegate)處理,再經過實現代理裏面的onTouchBegan等方法接收事件。最後完畢事件的響應。而在新的事件分發機制中。僅僅需經過建立一個事件監聽器-用來實現各類觸發後的邏輯。而後加入到事件分發器_eventDispatcher。所有事件監聽器由這個分發器統一管理,就能夠完畢事件響應。請參考不少其它3.0資料。。。編程
事件監聽器有下面幾種:app
- 觸摸事件 (EventListenerTouch)
- 鍵盤響應事件 (EventListenerKeyboard)
- 鼠標響應事件 (EventListenerMouse)
- 本身定義事件 (EventListenerCustom)
- 加速記錄事件 (EventListenerAcceleration)
_eventDispatcher的工做由三部分組成:函數
- 事件分發器 EventDispatcher
- 事件類型 EventTouch, EventKeyboard 等
- 事件監聽器 EventListenerTouch, EventListenerKeyboard 等
監聽器實現了各類觸發後的邏輯。在適當時候由事件分發器分發事件類型。而後調用對應類型的監聽器。post
用戶輸入事件
觸摸事件
在處理觸摸事件時,既可以重寫三個方法onTouchBegan,onTouchMoved和onTouchEnded,也可以直接經過Lambda表達式完畢響應邏輯。this
在2.x版本號中,開啓多點觸摸需要在AppController.mm中的application didFinishLaunchingWithOptions:launchOptions中加入[__glView setMultipleTouchEnabled: YES],另外還需重載5個對應函數:spa
- virtual void registerWithTouchDispatcher(void);
- virtual void ccTouchesBegan(cocos2d::CCSet pTouches, cocos2d::CCEvent pEvent);
- virtual void ccTouchesMoved(cocos2d::CCSet pTouches, cocos2d::CCEvent pEvent);
- virtual void ccTouchesEnded(cocos2d::CCSet pTouches, cocos2d::CCEvent pEvent);
- virtual void ccTouchesCancelled(cocos2d::CCSet pTouches, cocos2d::CCEvent pEvent);
而在3.0中,僅僅需建立多點觸摸事件監聽器。並將其加入到事件分發器中就能夠。3d
下面代碼在一個界面中加入三個button。三個button相互遮擋,並且都能觸發觸摸事件:代理
|
// 建立button精靈
auto
sprite1
=
Sprite
::
create
(
"Images/CyanSquare.png"
)
;
sprite1
->
setPosition
(
origin
+
Point
(
size
.
width
/
2
,
size
.
height
/
2
)
+
Point
(
-
80
,
80
)
)
;
addChild
(
sprite1
,
10
)
;
// sprite2
.
.
.
// sprite3
.
.
.
|
建立好button精靈後,建立單點觸摸事件監聽器,並完畢對應邏輯處理code
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
|
// 建立一個事件監聽器類型爲 OneByOne 的單點觸摸
auto
listener1
=
EventListenerTouchOneByOne
::
create
(
)
;
// 設置是否吞沒事件,在 onTouchBegan 方法返回 true 時吞沒
listener1
->
setSwallowTouches
(
true
)
;
// 使用 lambda 實現 onTouchBegan 事件回調函數
listener1
->
onTouchBegan
=
[
]
(
Touch*
touch
,
Event*
event
)
->
bool
{
// 獲取事件所綁定的 target
auto
target
=
static_cast
<
Sprite*
>
(
event
->
getCurrentTarget
(
)
)
;
// 獲取當前點擊點所在相對button的位置座標
Point
locationInNode
=
target
->
convertToNodeSpace
(
touch
->
getLocation
(
)
)
;
Size
s
=
target
->
getContentSize
(
)
;
Rect
rect
=
Rect
(
0
,
0
,
s
.
width
,
s
.
height
)
;
// 點擊範圍推斷檢測
if
(
rect
.
containsPoint
(
locationInNode
)
)
{
log
(
"sprite began... x = %f, y = %f"
,
locationInNode
.
x
,
locationInNode
.
y
)
;
target
->
setOpacity
(
180
)
;
return
true
;
}
return
false
;
}
;
// 觸摸移動時觸發
listener1
->
onTouchMoved
=
[
]
(
Touch*
touch
,
Event*
event
)
{
.
.
.
}
;
// 點擊事件結束處理
listener1
->
onTouchEnded
=
[
=
]
(
Touch*
touch
,
Event*
event
)
{
.
.
.
}
;
|
最後需要將事件監聽器加入到事件分發器遊戲
|
// 加入監聽器
_eventDispatcher
->
addEventListenerWithSceneGraphPriority
(
listener1
,
sprite1
)
;
_eventDispatcher
->
addEventListenerWithSceneGraphPriority
(
listener1
->
clone
(
)
,
sprite2
)
;
_eventDispatcher
->
addEventListenerWithSceneGraphPriority
(
listener1
->
clone
(
)
,
sprite3
)
;
|
以上代碼中_eventDispatcher是Node的屬性,經過它管理當前節點(場景、層、精靈等)的所有事件的分發。
但它自己是一個單例模式值的引用,在Node的構造函數中。經過Director::getInstance()->getEventDispatcher(); 獲取,有了這個屬性,就能方便的處理事件。
注意:當再次使用 listener1 的時候,需要使用clone()方法建立一個新的克隆,因爲在使用addEventListenerWithSceneGraphPriority或者addEventListenerWithFixedPriority方法時,會對當前使用的事件監聽器加入一個已註冊的標記,這使得它不能夠被加入屢次。另外,有一點很重要,FixedPriority listener加入完以後需要手動remove,而SceneGraphPriority listener是跟Node綁定的,在Node的析構函數中會被移除。詳細的演示樣例使用方法能夠參考引擎自帶的tests。
咱們可以經過下面方法移除一個已經被加入了的監聽器。
_eventDispatcher->removeEventListener(listener);
也可以使用例如如下方法。移除當前事件分發器中所有監聽器。
_eventDispatcher->removeAllEventListeners();
當使用removeAll的時候。此節點的所有的監聽將被移除,推薦使用 指定刪除的方式。
removeAll以後菜單也不能響應。
因爲它也需要接受觸摸事件。
鍵盤響應事件
鍵盤響應事件和處理觸摸事件使用了一樣的處理方式,一下代碼演示怎樣處理鍵盤響應事件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
// 初始化並綁定
auto
listener
=
EventListenerKeyboard
::
create
(
)
;
listener
->
onKeyPressed
=
CC_CALLBACK_2
(
KeyboardTest
::
onKeyPressed
,
this
)
;
listener
->
onKeyReleased
=
CC_CALLBACK_2
(
KeyboardTest
::
onKeyReleased
,
this
)
;
_eventDispatcher
->
addEventListenerWithSceneGraphPriority
(
listener
,
this
)
;
// 鍵位響應函數原型
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
)
;
}
|
鼠標響應事件
在 3.0 中多了鼠標捕獲事件派發。這可以在不一樣的平臺上。豐富咱們遊戲的用戶體驗。
如下代碼實現鼠標響應事件的實現步驟:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
// 建立監聽器
_mouseListener
=
EventListenerMouse
::
create
(
)
;
// 時間響應邏輯
_mouseListener
->
onMouseMove
=
[
=
]
(
Event *
event
)
{
EventMouse*
e
=
(
EventMouse*
)
event
;
string
str
=
"Mouse Down detected, Key: "
;
str
+=
tostr
(
e
->
getMouseButton
(
)
)
;
// ...
}
;
_mouseListener
->
onMouseUp
=
[
=
]
(
Event *
event
)
{
.
.
.
}
;
_mouseListener
->
onMouseDown
=
[
=
]
(
Event *
event
)
{
.
.
.
}
;
_mouseListener
->
onMouseScroll
=
[
=
]
(
Event *
event
)
{
.
.
.
}
;
// 加入到事件分發器
_eventDispatcher
->
addEventListenerWithSceneGraphPriority
(
_mouseListener
,
this
)
;
|
本身定義事件
以上是系統自帶的事件類型。事件由系統內部本身主動觸發,如 觸摸屏幕,鍵盤響應等。除此以外,還提供了一種 本身定義事件,簡而言之,它不是由系統本身主動觸發。而是人爲的干涉。例如如下:
|
_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
)
;
|
以上定義了一個 「本身定義事件監聽器」。實現了相關邏輯,並且加入到事件分發器。
上面的本身定義事件將由下面代碼觸發:
|
static
int
count
=
0
;
++
count
;
char
*
buf
=
new
char
[
10
]
;
sprintf
(
buf
,
"%d"
,
count
)
;
EventCustom
event
(
"game_custom_event1"
)
;
event
.
setUserData
(
buf
)
;
if
(
.
.
.
)
{
_eventDispatcher
->
dispatchEvent
(
&
event
)
;
}
CC_SAFE_DELETE_ARRAY
(
buf
)
;
|
定義一個 EventCustom,並且設置了其 UserData 數據,手動的經過 _eventDispatcher->dispatchEvent(&event); 將此事件分發出去。從而觸發以前所實現的邏輯。
加速計事件
除了觸摸。移動設備上一個很是重要的輸入源是設備的方向,所以大多數設備都配備了加速計。用於測量設備精巧或勻速運動時所受到的重力方向。
重力感應來自移動設備的加速計,一般支持X,Y和Z三個方向的加速度感應,因此又稱爲三向加速計。
在實際應用中。可以依據3個方向的力度大小來計算手機傾斜的角度或方向。
3.0中,新的事件機制下。咱們需要經過建立一個加速計監聽器EventListenerAcceleration,其靜態create方法中有個Acceleration的參數需要注意。
Acceleration是一個類,包括了加速計得到的3個方向的加速度。相關代碼例如如下:
|
class
Acceleration
{
public
:
double
x
;
double
y
;
double
z
;
double
timestamp
;
Acceleration
(
)
:
x
(
0
)
,
y
(
0
)
,
z
(
0
)
,
timestamp
(
0
)
{
}
}
;
|
該類中每個方向的加速度大小都爲一個重力加速度大小。
在使用加速計事件監聽器以前,需要先啓用此硬件設備:
Device::setAccelerometerEnabled(true);
而後建立相應的監聽器。在建立回調函數時。可以使用 lambda 表達式建立匿名函數,也可以綁定已有的函數邏輯實現,例如如下:
|
auto
listener
=
EventListenerAcceleration
::
create
(
[
=
]
(
Acceleration*
acc
,
Event*
event
)
{
//邏輯代碼段
}
)
;
_eventDispatcher
->
addEventListenerWithSceneGraphPriority
(
listener
,
this
)
;
|