quick-cocos2d-x 學習系列之十三 觸摸


quick-cocos2d-x 學習系列之十三 觸摸

 

現在智能機基本都是觸摸屏,除了鍵盤愛好者們耍鍵盤。我們要通過這小小的觸摸屏上完成整個游戲邏輯的控制,需要對這巴掌大地方進行詳細控制了。

 

1.  單點觸摸測試

創建精靈函數

function createTouchableSprite(p)

    local sprite = display.newScale9Sprite(p.image)

    sprite:setContentSize(p.size)

 

    local cs = sprite:getContentSize()

    local label = cc.ui.UILabel.new({

            UILabelType = 2,

            text = p.label,

            color = p.labelColor})

    label:align(display.CENTER)

    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 是觸摸點之前的位置

        local label = 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)

        local label = 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)

        local label = 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)

        local label = 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)

        local label = 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" or event.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

 

        local label = 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" or event.name == "moved" then

            return self.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)

        local label = 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" or event.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)

        local label = 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)

            local button = event.target

            button:setButtonLabelString(labels[button:isButtonSelected()])

        end)

        :onButtonClicked(function(event)

            local button = 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, count do

        local sprite = 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)

        local label = 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 = ?} 的結構組織

        local str = {}

        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

        local pointsCount = #str

        table.sort(str)

        labelPoints:setString(table.concat(str, "\n"))

 

        if event.name == "began" or event.name == "added" then

            self.touchIndex = self.touchIndex + 1

            for id, point in pairs(event.points) do

                local cursor = display.newSprite("Cursor.png")

                    :pos(point.x, point.y)

                    :scale(1.2)

                    :addTo(self)

                self.cursors[id] = cursor

            end

        elseif event.name == "moved" then

            for id, point in pairs(event.points) do

                local cursor = self.cursors[id]

                local rect = 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

        elseif event.name == "removed" then

            for id, 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

 

        local label = string.format("sprite: %s , count = %d, index = %d", event.name, pointsCount, self.touchIndex)

        self.sprite.label:setString(label)

 

        if event.name == "ended" or event.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)

        local label = string.format("parentButton: %s", event.name)

        self.parentButton.label:setString(label)

        printf("%s %s [TARGETING]", "parentButton", event.name)

        if event.name == "ended" or event.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

 

        local label = string.format("parentButton CAPTURE: %s", event.name)

        self.parentButton.label2:setString(label)

        printf("%s %s [CAPTURING]", "parentButton", event.name)

        if event.name == "began" or event.name == "moved" then

            return self.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)

        local label = 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" or event.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)

        local label = 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)

            local button = event.target

            button:setButtonLabelString(labels[button:isButtonSelected()])

        end)

        :onButtonClicked(function(event)

            local button = 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)

 

 

 

 

2.3         容器的觸摸區域由子對象決定

-- 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, count do

        local sprite = 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:setTouchMode(cc.TOUCH_MODE_ALL_AT_ONCE)-- 多點

   -- 添加觸摸事件處理函數

    self.touchableNode:addNodeEventListener(cc.NODE_TOUCH_EVENT,function(event)

        local str = {}

        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

        self.stateLabel:setString(table.concat(str, "\n"))

        return true

    end)

    drawBoundingBox(self, self.touchableNode, cc.c4f(0, 1.0, 0, 1.0))

 

    --

    app:createNextButton(self)

    app:createTitle(self, "多點觸摸測試 - 容器的觸摸區域由子對象決定")

 

 

 

 

 

 

 


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com