Quick-cocos2d-x Learning series thirteen Touch

 

Today’s smartphones are mostly touch screens, except for keyboard enthusiasts who use keyboards. We need to complete the entire game logic control through the small touch screen, the small area for detailed control.

 

1. Single touch test

Create Sprite function

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

Draw the BOX 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 Response to touch events

To call this function:

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))

— Enable touch

self.sprite:setTouchEnabled(true)

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

— event.name is the status of the touch event: Began, Moved, ended, cancelled

X, event.y is the current location of the touch point

PrevX, event. PrevY is the position before the touch point

Local label = string.format(” Sprite: %s x,y: %0.2f, %0.2f”, event.name, event.x, event.y “)

        self.sprite.label:setString(label)

 

— Returns true to respond to the touch event and continue to receive state changes for the touch event

        return true

    end)

Single touch is the most direct way to use it.

 

1.2 Event penetration and event capture

Create the underlying touch layer

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)

Add a listener to the touch layer

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)

 

 

Create button1 at the bottom layer. When button1 responds to the touch, it swallows up the touch event

    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 event swallowed after current object “, 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. For: setTouchSwallowEnabled (true) – whether to consume events, the default value is 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)

 

 

 

Create button2 underneath and respond to a touch without devouring the touch event

    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 event will be passed to the lower object “, 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) – when not consuming events, will touch events from upper to lower object, known as the “through”

    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)

 

Event penetration is achieved through the setTouchSwallowEnabled function.

The following function sets whether to capture touches

self.parentButton:setTouchCaptureEnabled(button:isButtonSelected())

 

1.3 Decide whether to accept events during the event capture phase

This flag variable is used to decide whether to accept the event during the touch event capture phase

    self.isTouchCaptureEnabled_ = true

 

ParentButton is the parent of 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)

 

You can capture touch events dynamically and decide whether to accept the event at the beginning of capture

    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 responds to the touch and swallows the touch event

    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 event swallowed after current object “, 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. For: setTouchSwallowEnabled (true) – whether to consume events, the default value is 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 responds to a touch without devouring the touch event

    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 event will be passed to the lower object “, 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) – when not consuming events, will touch events from upper to lower object, known as the “through”

    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)

 

Even if the parent object blocks the response event during the capture phase, the child object can still catch the event, but does not fire the event

    self.button2:addNodeEventListener(cc.NODE_TOUCH_CAPTURE_EVENT,function(event)

        printf(“%s %s [CAPTURING]”, “button2”, event.name)

        return true

    end)

 

— Place a switch button on the screen

    local labels = {}

Labels [true] = “Parent object [can] capture touch events”

Labels [false] = “Parent object [cannot] capture touch events”

    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 = “Event processing: \n1. [capture] stage: parent to child \n2. [target] stage \n3. [pass] stage: attempt to pass to lower level objects “,

        size= 24})

        :align(display.CENTER_TOP, display.cx,display.top – 120)

        :addTo(self)

 

 

NODE_TOUCH_EVENT and NODE_TOUCH_CAPTURE_EVENT indicate two kinds of events.

Return true or false in the NODE_TOUCH_CAPTURE_EVENT handler, and then decide whether to call the NODE_TOUCH_EVENT handler.

1.4 The touch area of the container is determined by the child objects

Create a Node and add several sprites to the node. The local area of the Sprite determines the range of touches.

 

— touchableNode is a touch enabled Node

    self.touchableNode = display.newNode()

    self.touchableNode:setPosition(display.cx, display.cy)

    self:addChild(self.touchableNode)

 

— Add some sprites to touchableNode

    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)

 

— Enable touch

    self.touchableNode:setTouchEnabled(true)

Add a touch event handler

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

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. Multi-touch

 

2.1 Response to touch events

 

 

 

— createTouchableSprite() is defined in 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)

 

— Enable touch

    self.sprite:setTouchEnabled(true)

— Set touch mode

Self. Sprite: setTouchMode (cc) TOUCH_MODE_ALL_AT_ONCE) – more

–self. Sprite :setTouchMode(cc.touch_mode_one_by_one) — single point (default mode)

Add a touch event handler

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

— Event. name is the status of the touch event: Began, moved, ended, cancelled, added, removed

Points contains all touch points according to events.point[id] = {x =? , y = ? } structure organization

        local str = {}

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

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

Check whether the position of the touch point is inside the rectangle

                    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

 

— Returns true to respond to the touch event and continue to receive state changes for the touch event

        return true

    end)

 

    cc.ui.UILabel.new({

Text = “After registering multi-touch, the target will receive data \nadded and removed indicating the addition and removal of touch points “,

        size= 24})

        :align(display.CENTER, display.cx,display.top – 80)

        :addTo(self)

 

2.2 Decide whether to accept events during the event capture phase

This flag variable is used to decide whether to accept the event during the touch event capture phase

    self.isTouchCaptureEnabled_ = true

 

ParentButton is the parent of 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)

 

You can capture touch events dynamically and decide whether to accept the event at the beginning of capture

    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 responds to the touch and swallows the touch event

    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 event swallowed after current object “, 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. For: setTouchMode (cc) TOUCH_MODE_ALL_AT_ONCE) – more

Self. For: setTouchSwallowEnabled (true) – whether to consume events, the default value is 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 responds to a touch without devouring the touch event

    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 event will be passed to the lower object “, 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) – more

Self. Button2: setTouchSwallowEnabled (false) – when not consuming events, will touch events from upper to lower object, known as the “through”

    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)

 

Even if the parent object blocks the response event during the capture phase, the child object can still catch the event, but does not fire the event

    self.button2:addNodeEventListener(cc.NODE_TOUCH_CAPTURE_EVENT,function(event)

        printf(“%s %s [CAPTURING]”, “button2”, event.name)

        return true

    end)

 

— Place a switch button on the screen

    local labels = {}

Labels [true] = “Parent object [can] capture touch events”

Labels [false] = “Parent object [cannot] capture touch events”

    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 = “Event processing: \n1. [capture] stage: parent to child \n2. [target] stage \n3. [pass] stage: attempt to pass to lower level objects “,

        size= 24})

        :align(display.CENTER_TOP, display.cx,display.top – 120)

        :addTo(self)

 

 

 

 

2.3 The touch area of the container is determined by the child objects

— touchableNode is a touch enabled Node

    self.touchableNode = display.newNode()

    self.touchableNode:setPosition(display.cx, display.cy)

    self:addChild(self.touchableNode)

 

— Add some sprites to touchableNode

    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)

 

— Enable touch

    self.touchableNode:setTouchEnabled(true)

Self. TouchableNode: setTouchMode (cc) TOUCH_MODE_ALL_AT_ONCE) – more

Add a touch event handler

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

        local str = {}

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

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, “Multi-touch test – the container’s touch area is determined by the child object “)