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