Cocos2d-x 本來的觸摸機制存在一些限制,在使用中須要開發者作很多額外的處理。因此 Quick-Cocos2d-x 提出了本身的一套觸摸機制。本文詳細介紹了這套新機制的用法。函數
在 Cocos2d-x 裏,整個遊戲的畫面是由一系列的 Scene, Node, Sprite, Layer 等對象構成的。而全部這些對象都是從 Node 這個類繼承而來。咱們能夠將 Node 稱爲顯示節點
。ui
一個遊戲畫面就是許多顯示節點構成的一棵樹:url
1
2
3
4
5
6
7
8
9
10
11
12
|
/|\
| 顯示層級
|
| [Node] [Node] [Node]
| | | |
| +---+---+ |
| | |
| [Node] [Node]
| | |
| +-----+-----+
| |
| [Node]
|
在這棵樹裏,Node 所處的垂直位置就是它們的顯示層級
。越往上的 Node,其顯示層級就越高。從畫面表現上來講,下面的 Node 是背景,上面的 Node 是建築,那麼建築就會擋住一部分背景。spa
在 Cocos2d-x 裏,只有 Layer 對象才能接受觸摸事件。而 Layer 老是響應整個屏幕範圍內的觸摸,這就要求開發者在拿到觸摸事件後,再作進一步的處理。code
例若有一個需求是在玩家觸摸屏幕上的方塊時,人物角色作一個動做。那麼使用 Layer 接受到觸摸事件後,開發者須要自行判斷觸摸位置是否在方塊以內。當屏幕上有不少東西須要響應玩家交互時,程序結構就開始變得複雜了。對象
因此 Quick-Cocos2d-x 容許開發者將任何一個 Node 設置爲接受觸摸事件。而且觸摸事件一開始只會出如今這個 Node 的觸摸區域
內。繼承
所謂觸摸區域
,就是一個 Node 及其全部子 Node 顯示內容佔據的屏幕空間。要注意的是這個屏幕空間包含了圖片的透明部分。下圖中,節點 A 是一個 Sprite 對象,它的觸摸區域就是圖片大小;而節點 B 是一個 Node 對象,其中包含了三個 Sprite 對象,那麼節點 B 的觸摸區域就是三個 Sprite 對象觸摸區域的合集。遊戲
爲了簡化實現,觸摸區域
都是一個矩形,因此節點 B 的觸摸區域
其實是一個「包含三個 Sprite 對象觸摸區域合集的矩形」,能夠參考上圖中的紅色邊框線。事件
下面列出觸摸事件的用法示例,更詳細的示例請參考 samples/touch
示例。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
-- 容許 node 接受觸摸事件
node:setTouchEnabled(
true
)
-- 註冊觸摸事件
node:addNodeEventListener(cc.NODE_TOUCH_EVENT, function(event)
-- event.name 是觸摸事件的狀態:began, moved, ended, cancelled
-- event.x, event.y 是觸摸點當前位置
-- event.prevX, event.prevY 是觸摸點以前的位置
printf
(
"sprite: %s x,y: %0.2f, %0.2f"
,
event.name, event.x, event.y)
-- 在 began 狀態時,若是要讓 Node 繼續接收該觸摸事件的狀態變化
-- 則必須返回
true
if
event.name ==
"began"
then
return
true
end
end)
|
觸摸事件的 event.name
指示了事件的狀態:
began
狀態時,若是要繼續接收該觸摸事件的狀態變化,事件處理函數必須返回 true
。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
-- 容許 node 接受觸摸事件
node:setTouchEnabled(
true
)
-- 設置觸摸模式
node:setTouchMode(cc.TOUCH_MODE_ALL_AT_ONCE) -- 多點
-- node:setTouchMode(cc.TOUCH_MODE_ONE_BY_ONE) -- 單點(默認模式)
-- 註冊觸摸事件
node:addNodeEventListener(cc.NODE_TOUCH_EVENT, function(event)
-- event.name 是觸摸事件的狀態:began, moved, ended, cancelled
-- 多點觸摸增長了 added 和 removed 狀態
-- event.points 包含全部觸摸點
-- 按照 events.point[id] = {x = ?, y = ?} 的結構組織
for
id, point in pairs(event.points)
do
printf
(
"event [%s] %s = %0.2f, %0.2f"
,
event.name, id, point.x, point.y)
end
if
event.name ==
"began"
then
return
true
end
end)
|
在多點觸摸時,事件狀態的含義有所區別:
began
狀態時,event.points
中可能仍然只有一個觸摸點的數據,其餘觸摸點數據會經過 added
狀態提供。added
狀態。此時 event.points
中包含新加入的觸摸點數據。removed
狀態。此時event.points
中包含刪除的觸摸點數據。ended
狀態。此時 event.points
中包含刪除的觸摸點數據。event.points
中只包含有變化的觸摸點數據。默認狀況下,Node 在響應觸摸後(在 began
狀態返回 true
表示要響應觸摸),就會阻止事件繼續傳遞給 Node 的父對象(更下層的 Node),這稱爲觸摸事件吞噬
。
若是要改變這個行爲,能夠用:
true
。若是設置爲 false
,則 Node 響應觸摸事件後,仍然會將事件繼續傳遞給父對象。對於一個 Node,隨時能夠啓用或禁用其觸摸事件:
false
。但即使禁用了 Node 的觸摸事件,也只能阻止這個 Node 響應觸摸,而不能阻止這個 Node 的子 Node 響應觸摸。
假設有一個對話框(Node),咱們須要禁止對話框中的全部 Node 響應觸摸。那麼須要禁止對話框 Node 捕獲事件:
1
|
dialog:setTouchCaptureEnabled(
false
)
|
true
。當設置爲 false
時,該 Node 及其全部子 Node 都沒法獲得觸摸事件。總結而言,setTouchEnabled()
只針對當前 Node,而 setTouchCaptureEnabled()
同時影響當前 Node 及其全部子 Node。
quick 中觸摸事件分爲三個階段:capturing(捕獲)、targeting(觸發)、bubbling(冒泡)。
當用戶的一根手指觸摸到屏幕時,將產生一個觸摸事件:
顯示層級
最高,而且其觸摸區域
包含觸摸位置的那個 Node。這個 Node 被稱爲 TargetNode(目標 Node)。isTouchCaptureEnabled()
結果,若是返回 false
,則重複 1
cc.NODE_TOUCH_CAPTURE_EVENT
事件的返回結果。任何一個 Node 返回 false
都會阻止事件在 TargetNode 上觸發。並從步驟 1 開始查找其餘符合條件的 Node。capturing
。targeting
。false
,表示 TargetNode 不響應該事件,並從步驟 1 開始查找其餘符合條件的 Node。TargetNode:isTouchSwallowEnabled()
的返回值。若是是true
,則取消 bubbling
階段。false
或者事件被吞噬。這個階段稱爲 bubbling
。利用事件的三個階段,咱們能夠註冊 capturing
階段的觸摸事件處理函數:
1
2
3
4
5
6
7
|
-- 在 capturing 階段就捕獲事件
node:addNodeEventListener(cc.NODE_TOUCH_CAPTURE_EVENT, function(event)
if
event.name ==
"began"
then
-- 在 began 狀態返回
false
,將阻止事件
return
false
end
end)
|
關於觸摸機制的靈活運用,能夠參考 cc.ui
中的各個 UI 控件,以及 samples/touch
示例。
addNodeEventListener()
返回的註冊 id。false
。cc.TOUCH_MODE_ONE_BY_ONE
。true
。true
。