Cycling through overlapping images with touch and drag.

Hi,

I wanted to create a touch and drag implementation whereby you could repeatedly click on overlapped images to cycle between them, without changing the draw order. After untold hours of torment, I think I’ve finally gotten it to work. I was wondering if anyone else had done this before, and what was your experience with it? Did you find it hard? Did it take long? How did you go about it? The way I went about it was to add the same listener function to each image. This “touchManager” function would then do all the logic and then apply the standard touch and drag function to the appropriate image. As you can see below, said function is a bit complicated.

Perhaps moreso than it needs to be? I would love to see how wiser folk would achieve the same thing. In any case, what I have now seems to be working, so it might be worth sharing for anyone who needs it in the future.

function table.tableContains(t, x) for i = 1, #t do if t[i] == x then return true end end end local selectedName = display.newText({text = "", x = display.contentCenterX, y = 20}) local boxes = { display.newRect(80, 80, 50, 50), display.newRect(120, 120, 50, 50), display.newRect(80, 120, 50, 50), display.newRect(120, 80, 50, 50), } boxes[1]:setFillColor(1,0,0); boxes[1].name = "Red" boxes[2]:setFillColor(0,1,0); boxes[2].name = "Green" boxes[3]:setFillColor(0,0,1); boxes[3].name = "Blue" boxes[4]:setFillColor(1,1,1); boxes[4].name = "White" local function onTouch(e, obj) if e.phase == "began" then display.currentStage:setFocus(obj) obj.startX = obj.x obj.startY = obj.y elseif e.phase == "moved" then obj.x = (e.x - e.xStart) + obj.startX obj.y = (e.y - e.yStart) + obj.startY else display.currentStage:setFocus(nil) end return true end local selected, somethingTouched, beganEvent local cycleList = {} local touchDepth = 0 local function touchManager(e) if e.phase == "began" then somethingTouched = true touchDepth = touchDepth + 1 if (touchDepth == 1) and beganEvent and (beganEvent.x == e.x) and (beganEvent.y == e.y) then selectNextOnRelease = true end beganEvent = e cycleList[#cycleList+1] = e.target if not selected then selected = e.target; selectedName.text = selected.name end return false end if e.phase ~= "began" then if not somethingTouched then return true end if not table.tableContains(cycleList, selected) then selected = cycleList[1]; selectedName.text = selected.name end end if e.phase == "moved" then if not selected.touchBegan then onTouch(beganEvent, selected); selected.touchBegan = true end beganEvent = nil onTouch(e, selected) return true else somethingTouched = false onTouch(e, selected) selected.touchBegan = false touchDepth = 0 if selectNextOnRelease and beganEvent then for i = 1, #cycleList do if cycleList[i] == selected then selected = cycleList[i+1] if selected == nil then selected = cycleList[1] end transition.from(selected, {time = 100, xScale = 0.9, yScale = 0.9}) selectedName.text = selected.name break end end end cycleList = {} return true end end for i = 1, #boxes do boxes[i]:addEventListener("touch", touchManager) end

Well, this is just something that I created in 5 minutes, but I’d probably approach this something like this:

 

local object = {} local prevObject local function onTouch( event ) if event.phase == "began" then if not prevObject then print( "First touch: " .. event.target.id .. " was pressed." ) prevObject = event.target return true else if prevObject ~= event.target then prevObject:toBack() print( "Touch: " .. event.target.id .. " was pressed." ) prevObject = event.target return true end end end end for i = 1, 10 do object[i] = display.newRect( 100, 100, 100, 100 ) object[i]:setFillColor( math.random(), math.random(), math.random() ) object[i].id = i object[i]:addEventListener( "touch", onTouch ) end

Since Corona goes through all overlapping objects during a touch event unless you return true, you could just check if the current event.target is the same as the previous one. If it is, then skip it. If it isn’t, then send the previous object to back and set the new object to the previous.