1. 程式人生 > >quick-cocos2d-x 學習系列之十三 觸控

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

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

        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<