quick-cocos2d-x 學習系列之十三 觸控
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow
也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!
quick-cocos2d-x 學習系列之十三 觸控
現在智慧機基本都是觸控式螢幕,除了鍵盤愛好者們耍鍵盤。我們要通過這小小的觸控式螢幕上完成整個遊戲邏輯的控制,需要對這巴掌大地方進行詳細控制了。
1. 單點觸控測試
建立精靈函式
function createTouchableSprite(p)
local sprite = display.newScale9Sprite(p.image)
sprite:setContentSize(p.size)
local cs = sprite:getContentSize()
local label = cc
UILabelType = 2,
text = p.label,
color = p.labelColor})
label
label:setPosition(cs.width /2, label:getContentSize().height)
sprite:addChild(label)
sprite.label = label
return sprite
end
劃BOX框
function drawBoundingBox(parent,target, color)
local cbb = target:getCascadeBoundingBox()
local left, bottom, width, height = cbb.origin.x, cbb.origin.y, cbb.size.width, cbb.size.height
local points = {
{left, bottom},
{left + width, bottom},
{left + width, bottom + height},
{left, bottom + height},
{left, bottom},
}
local box = display.newPolygon(points, {borderColor =color})
parent:addChild(box,1000)
end
1.1 響應觸控事件
呼叫該函式:
self.sprite = createTouchableSprite({
image = "WhiteButton.png",
size = cc.size(500,300),
label = "TOUCH ME !",
labelColor = cc.c3b(255,0, 0)})
:pos(display.cx, display.cy)
:addTo(self)
drawBoundingBox(self, self.sprite, cc.c4f(0,1.0, 0, 1.0))
-- 啟用觸控
self.sprite:setTouchEnabled(true)
self.sprite:addNodeEventListener(cc.NODE_TOUCH_EVENT,function(event)
-- event.name 是觸控事件的狀態:began, moved, ended, cancelled
-- event.x, event.y 是觸控點當前位置
-- event.prevX, event.prevY 是觸控點之前的位置
locallabel = string.format("sprite: %s x,y: %0.2f, %0.2f",event.name, event.x,event.y)
self.sprite.label:setString(label)
-- 返回 true表示要響應該觸控事件,並繼續接收該觸控事件的狀態變化
return true
end)
單點觸控是最直接的使用方式了。
1.2 事件穿透和事件捕獲
--建立底層觸控層
self.parentButton = createTouchableSprite({
image = "WhiteButton.png",
size = cc.size(600,500),
label = "TOUCH ME !",
labelColor = cc.c3b(255,0, 0)})
:pos(display.cx, display.cy)
:addTo(self)
self.parentButton.name = "parentButton"
drawBoundingBox(self,self.parentButton, cc.c4f(0,1.0, 0, 1.0))
self.parentButton:setTouchEnabled(true)
--給該觸控層增加監聽
self.parentButton:addNodeEventListener(cc.NODE_TOUCH_EVENT,function(event)
locallabel = string.format("parentButton: %s x,y: %0.2f, %0.2f",event.name, event.x,event.y)
self.parentButton.label:setString(label)
return true
end)
--在底層建立button1, button1響應觸控後,會吞噬掉觸控事件
self.button1 = createTouchableSprite({
image = "GreenButton.png",
size = cc.size(400,160),
label = "TOUCH ME !"})
:pos(300, 400)
:addTo(self.parentButton)
cc.ui.UILabel.new({text = "SWALLOW = YES\n事件在當前物件處理後被吞噬", size =24})
:align(display.CENTER, 200, 90)
:addTo(self.button1)
drawBoundingBox(self, self.button1, cc.c4f(1.0,0, 0, 1.0))
self.button1:setTouchEnabled(true)
self.button1:setTouchSwallowEnabled(true)--是否吞噬事件,預設值為 true
self.button1:addNodeEventListener(cc.NODE_TOUCH_EVENT,function(event)
locallabel = string.format("button1: %s x,y: %0.2f, %0.2f",event.name, event.x,event.y)
self.button1.label:setString(label)
return true
end)
-- 在底層建立button2,響應觸控後,不會吞噬掉觸控事件
self.button2 = createTouchableSprite({
image = "PinkButton.png",
size = cc.size(400,160),
label = "TOUCH ME !"})
:pos(300, 200)
:addTo(self.parentButton)
cc.ui.UILabel.new({text = "SWALLOW = NO\n事件會傳遞到下層物件", size =24})
:align(display.CENTER, 200, 90)
:addTo(self.button2)
drawBoundingBox(self,self.button2, cc.c4f(0,0, 1.0, 1.0))
self.button2:setTouchEnabled(true)
self.button2:setTouchSwallowEnabled(false)-- 當不吞噬事件時,觸控事件會從上層物件往下層物件傳遞,稱為“穿透”
self.button2:addNodeEventListener(cc.NODE_TOUCH_EVENT,function(event)
locallabel = string.format("button1: %s x,y: %0.2f, %0.2f",event.name, event.x,event.y)
self.button2.label:setString(label)
return true
end)
事件穿透通過函式setTouchSwallowEnabled來實現。
如下函式設定是否捕捉觸控
self.parentButton:setTouchCaptureEnabled(button:isButtonSelected())
1.3 在事件捕獲階段決定是否接受事件
-- 這個標誌變數用於在觸控事件捕獲階段決定是否接受事件
self.isTouchCaptureEnabled_ =true
--parentButton 是 button1的父節點
self.parentButton = createTouchableSprite({
image = "WhiteButton.png",
size = cc.size(600,500),
label = "TOUCH ME !",
labelColor = cc.c3b(255,0, 0)})
:pos(display.cx, display.cy)
:addTo(self)
drawBoundingBox(self,self.parentButton, cc.c4f(0,1.0, 0, 1.0))
self.parentButton.label2 =cc.ui.UILabel.new({text = "", size =24, color = cc.c3b(0,0, 255)})
:align(display.CENTER, 300, 60)
:addTo(self.parentButton)
self.parentButton:setTouchEnabled(true)
self.parentButton:addNodeEventListener(cc.NODE_TOUCH_EVENT,function(event)
locallabel = string.format("parentButton: %s x,y: %0.2f, %0.2f",event.name, event.x,event.y)
self.parentButton.label:setString(label)
printf("%s %s [TARGETING]","parentButton", event.name)
if event.name == "ended" orevent.name == "cancelled"then
print("-----------------------------")
else
print("")
end
return true
end)
-- 可以動態捕獲觸控事件,並在捕獲觸控事件開始時決定是否接受此次事件
self.parentButton:addNodeEventListener(cc.NODE_TOUCH_CAPTURE_EVENT,function(event)
if event.name == "began" then
print("-----------------------------")
end
locallabel = string.format("parentButton CAPTURE: %s x,y: %0.2f, %0.2f",event.name, event.x,event.y)
self.parentButton.label2:setString(label)
printf("%s %s [CAPTURING]","parentButton", event.name)
if event.name == "began" orevent.name == "moved"then
returnself.isTouchCaptureEnabled_
end
end)
-- button1響應觸控後,會吞噬掉觸控事件
self.button1 = createTouchableSprite({
image = "GreenButton.png",
size = cc.size(400,160),
label = "TOUCH ME !"})
:pos(300, 400)
:addTo(self.parentButton)
cc.ui.UILabel.new({text = "SWALLOW = YES\n事件在當前物件處理後被吞噬", size =24})
:align(display.CENTER, 200, 90)
:addTo(self.button1)
drawBoundingBox(self,self.button1, cc.c4f(1.0,0, 0, 1.0))
self.button1:setTouchEnabled(true)
self.button1:setTouchSwallowEnabled(true)-- 是否吞噬事件,預設值為 true
self.button1:addNodeEventListener(cc.NODE_TOUCH_EVENT,function(event)
locallabel = string.format("button1: %s x,y: %0.2f, %0.2f",event.name, event.x,event.y)
self.button1.label:setString(label)
printf("%s %s [TARGETING]","button1", event.name)
if event.name == "ended" orevent.name == "cancelled"then
print("-----------------------------")
else
print("")
end
return true
end)
-- button2響應觸控後,不會吞噬掉觸控事件
self.button2 = createTouchableSprite({
image = "PinkButton.png",
size = cc.size(400,160),
label = "TOUCH ME !"})
:pos(300, 200)
:addTo(self.parentButton)
cc.ui.UILabel.new({text = "SWALLOW = NO\n事件會傳遞到下層物件", size =24})
:align(display.CENTER, 200, 90)
:addTo(self.button2)
drawBoundingBox(self,self.button2, cc.c4f(0,0, 1.0, 1.0))
self.button2:setTouchEnabled(true)
self.button2:setTouchSwallowEnabled(false)-- 當不吞噬事件時,觸控事件會從上層物件往下層物件傳遞,稱為“穿透”
self.button2:addNodeEventListener(cc.NODE_TOUCH_EVENT,function(event)
locallabel = string.format("button1: %s x,y: %0.2f, %0.2f",event.name, event.x,event.y)
self.button2.label:setString(label)
printf("%s %s [TARGETING]","button2", event.name)
return true
end)
-- 即便父物件在捕獲階段阻止響應事件,但子物件仍然可以捕獲到事件,只是不會觸發事件
self.button2:addNodeEventListener(cc.NODE_TOUCH_CAPTURE_EVENT,function(event)
printf("%s %s [CAPTURING]","button2", event.name)
return true
end)
-- 放置一個開關按鈕在螢幕上
local labels = {}
labels[true] ="父物件【可以】捕獲觸控事件"
labels[false] ="父物件【不能】捕獲觸控事件"
local images = {on = "CheckBoxButton2On.png", off ="CheckBoxButton2Off.png"}
self.captureEnabledButton =cc.ui.UICheckBoxButton.new(images)
:setButtonLabel(cc.ui.UILabel.new({text=labels[true], size =24}))
:setButtonLabelOffset(40,0)
:setButtonSelected(true)
:onButtonStateChanged(function(event)
localbutton = event.target
button:setButtonLabelString(labels[button:isButtonSelected()])
end)
:onButtonClicked(function(event)
localbutton = event.target
self.isTouchCaptureEnabled_ =button:isButtonSelected()
end)
:pos(display.cx - 160, display.top- 80)
:addTo(self)
cc.ui.UILabel.new({
text = "事件處理流程:\n1.【捕獲】階段:從父到子\n2.【目標】階段\n3. 【傳遞】階段:嘗試傳遞給下層物件",
size= 24})
:align(display.CENTER_TOP, display.cx,display.top -120)
:addTo(self)
其中NODE_TOUCH_EVENT和 NODE_TOUCH_CAPTURE_EVENT 表示兩種事件。
在NODE_TOUCH_CAPTURE_EVENT的處理函式中返回真假,然後決定是否呼叫NODE_TOUCH_EVENT的處理函式。
1.4 容器的觸控區域由子物件決定
建立一個node,在node上增加幾個精靈,精靈的局域決定的觸控的範圍。
-- touchableNode 是啟用觸控的 Node
self.touchableNode = display.newNode()
self.touchableNode:setPosition(display.cx,display.cy)
self:addChild(self.touchableNode)
-- 在 touchableNode中加入一些 sprite
local count = math.random(3,8)
local images = {"WhiteButton.png", "BlueButton.png", "GreenButton.png", "PinkButton.png"}
for i = 1, countdo
localsprite = display.newScale9Sprite(images[math.random(1,4)])
sprite:setContentSize(cc.size(math.random(100,200), math.random(100,200)))
sprite:setPosition(math.random(-200,200), math.random(-200,200))
self.touchableNode:addChild(sprite)
end
self.stateLabel = cc.ui.UILabel.new({text = ""})
self.stateLabel:align(display.CENTER,display.cx,display.top - 100)
self:addChild(self.stateLabel)
-- 啟用觸控
self.touchableNode:setTouchEnabled(true)
-- 新增觸控事件處理函式
self.touchableNode:addNodeEventListener(cc.NODE_TOUCH_EVENT,function(event)
locallabel = string.format("touchableNode: %s x,y: %0.2f, %0.2f",event.name, event.x,event.y)
self.stateLabel:setString(label)
return true
end)
drawBoundingBox(self, self.touchableNode, cc.c4f(0,1.0, 0, 1.0))
2. 多點觸控
2.1 響應觸控事件
-- createTouchableSprite() 定義在 includes/functions.lua中
self.sprite = createTouchableSprite({
image = "WhiteButton.png",
size = cc.size(500,600),
label = "TOUCH ME !",
labelColor = cc.c3b(255,0, 0)})
:pos(display.cx, display.cy)
:addTo(self)
drawBoundingBox(self,self.sprite, cc.c4f(0,1.0, 0, 1.0))
local labelPoints = cc.ui.UILabel.new({text = "", size = 24})
:align(display.CENTER_TOP, display.cx,display.top -120)
:addTo(self)
-- 啟用觸控
self.sprite:setTouchEnabled(true)
-- 設定觸控模式
self.sprite:setTouchMode(cc.TOUCH_MODE_ALL_AT_ONCE)--多點
--self.sprite:setTouchMode(cc.TOUCH_MODE_ONE_BY_ONE) --單點(預設模式)
-- 新增觸控事件處理函式
self.sprite:addNodeEventListener(cc.NODE_TOUCH_EVENT,function(event)
-- event.name 是觸控事件的狀態:began, moved, ended, cancelled, added(僅限多點觸控), removed(僅限多點觸控)
-- event.points 包含所有觸控點,按照 events.point[id] = {x = ?, y = ?}的結構組織
localstr = {}
for id, point in pairs(event.points)do
str[#str +1] = string.format("id: %s, x: %0.2f, y: %0.2f",point.id, point.x,point.y)
end
localpointsCount = #str
table.sort(str)
labelPoints:setString(table.concat(str,"\n"))
if event.name == "began" orevent.name == "added"then
self.touchIndex = self.touchIndex + 1
forid, point in pairs(event.points)do
localcursor = display.newSprite("Cursor.png")
:pos(point.x,point.y)
:scale(1.2)
:addTo(self)
self.cursors[id] =cursor
end
elseifevent.name == "moved"then
forid, point in pairs(event.points)do
localcursor = self.cursors[id]
localrect = self.sprite:getBoundingBox()
if cc.rectContainsPoint(rect,cc.p(point.x, point.y)) then
-- 檢查觸控點的位置是否在矩形內
cursor:setPosition(point.x,point.y)
cursor:setVisible(true)
else
cursor:setVisible(false)
end
end
elseifevent.name == "removed"then
forid, point in pairs(event.points)do
self.cursors[id]:removeSelf()
self.cursors[id] =nil
end
else
for_, cursor in pairs(self.cursors)do
cursor:removeSelf()
end
self.cursors = {}
end
locallabel = string.format("sprite: %s , count = %d, index = %d",event.name, pointsCount,self.touchIndex)
self.sprite.label:setString(label)
if event.name == "ended" orevent.name == "cancelled"then
self.sprite.label:setString("")
labelPoints:setString("")
end
-- 返回 true表示要響應該觸控事件,並繼續接收該觸控事件的狀態變化
return true
end)
cc.ui.UILabel.new({
text = "註冊多點觸控後,目標將收到所有觸控點的資料\nadded和 removed 指示觸控點的加入和移除",
size= 24})
:align(display.CENTER, display.cx,display.top -80)
:addTo(self)
2.2 在事件捕獲階段決定是否接受事件
-- 這個標誌變數用於在觸控事件捕獲階段決定是否接受事件
self.isTouchCaptureEnabled_ =true
--parentButton 是 button1的父節點
self.parentButton = createTouchableSprite({
image = "WhiteButton.png",
size = cc.size(600,500),
label = "TOUCH ME !",
labelColor = cc.c3b(255,0, 0)})
:pos(display.cx, display.cy)
:addTo(self)
drawBoundingBox(self,self.parentButton, cc.c4f(0,1.0, 0, 1.0))
self.parentButton.label2 =cc.ui.UILabel.new({text = "", size =24, color = cc.c3b(0,0, 255)})
:align(display.CENTER, 300, 60)
:addTo(self.parentButton)
self.parentButton:setTouchEnabled(true)
self.parentButton:addNodeEventListener(cc.NODE_TOUCH_EVENT,function(event)
locallabel = string.format("parentButton: %s",event.name)
self.parentButton.label:setString(label)
printf("%s %s [TARGETING]","parentButton", event.name)
if event.name == "ended" orevent.name == "cancelled"then
print("-----------------------------")
else
print("")
end
return true
end)
-- 可以動態捕獲觸控事件,並在捕獲觸控事件開始時決定是否接受此次事件
self.parentButton:addNodeEventListener(cc.NODE_TOUCH_CAPTURE_EVENT,function(event)
if event.name == "began" then
print("-----------------------------")
end
locallabel = string.format("parentButton CAPTURE: %s",event.name)
self.parentButton.label2:setString(label)
printf("%s %s [CAPTURING]","parentButton", event.name)
if event.name == "began" orevent.name == "moved"then
returnself.isTouchCaptureEnabled_
end
end)
-- button1響應觸控後,會吞噬掉觸控事件
self.button1 = createTouchableSprite({
image = "GreenButton.png",
size = cc.size(400,160),
label = "TOUCH ME !"})
:pos(300, 400)
:addTo(self.parentButton)
cc.ui.UILabel.new({text = "SWALLOW = YES\n事件在當前物件處理後被吞噬", size =24})
:align(display.CENTER, 200, 90)
:addTo(self.button1)
drawBoundingBox(self,self.button1, cc.c4f(1.0,0, 0, 1.0))
self.button1:setTouchEnabled(true)
self.button1:setTouchMode(cc.TOUCH_MODE_ALL_AT_ONCE)--多點
self.button1:setTouchSwallowEnabled(true)-- 是否吞噬事件,預設值為 true
self.button1:addNodeEventListener(cc.NODE_TOUCH_EVENT,function(event)
locallabel = string.format("button1: %s count: %d",event.name, table.nums(event.points))
self.button1.label:setString(label)
printf("%s %s [TARGETING]","button1", event.name)
if event.name == "ended" orevent.name == "cancelled"then
print("-----------------------------")
else
print("")
end
return true
end)
-- button2響應觸控後,不會吞噬掉觸控事件
self.button2 = createTouchableSprite({
image = "PinkButton.png",
size = cc.size(400,160),
label = "TOUCH ME !"})
:pos(300, 200)
:addTo(self.parentButton)
cc.ui.UILabel.new({text = "SWALLOW = NO\n事件會傳遞到下層物件", size =24})
:align(display.CENTER, 200, 90)
:addTo(self.button2)
drawBoundingBox(self,self.button2, cc.c4f(0,0, 1.0, 1.0))
self.button2:setTouchEnabled(true)
self.button2:setTouchMode(cc.TOUCH_MODE_ALL_AT_ONCE)--多點
self.button2:setTouchSwallowEnabled(false)-- 當不吞噬事件時,觸控事件會從上層物件往下層物件傳遞,稱為“穿透”
self.button2:addNodeEventListener(cc.NODE_TOUCH_EVENT,function(event)
locallabel = string.format("button1: %s count: %d",event.name, table.nums(event.points))
self.button2.label:setString(label)
printf("%s %s [TARGETING]","button2", event.name)
return true
end)
-- 即便父物件在捕獲階段阻止響應事件,但子物件仍然可以捕獲到事件,只是不會觸發事件
self.button2:addNodeEventListener(cc.NODE_TOUCH_CAPTURE_EVENT,function(event)
printf("%s %s [CAPTURING]","button2", event.name)
return true
end)
-- 放置一個開關按鈕在螢幕上
local labels = {}
labels[true] ="父物件【可以】捕獲觸控事件"
labels[false] ="父物件【不能】捕獲觸控事件"
local images = {on = "CheckBoxButton2On.png", off ="CheckBoxButton2Off.png"}
self.captureEnabledButton =cc.ui.UICheckBoxButton.new(images)
:setButtonLabel(cc.ui.UILabel.new({text=labels[true], size =24}))
:setButtonLabelOffset(40,0)
:setButtonSelected(true)
:onButtonStateChanged(function(event)
localbutton = event.target
button:setButtonLabelString(labels[button:isButtonSelected()])
end)
:onButtonClicked(function(event)
localbutton = event<