Reordering of tiles

I’m trying to implement a reorder of game tiles. e.g. bit like a scrabble tile deck.

Can get drag-n-drop working fine. But want to transition adjacent tile left or right when dragging across the deck over existing tiles. I understand transitions. Just need to get the

Have attempted various things: custom “enter/leave” events for specific zones but still end up with what seems to be a complex approach and tiles jitter about.

Does anybody have a simple suggestion or done similar.  i’ve put a basic sample together to  show what im after. Hopefully someone can enlighten me,

–sample code

local tiles={}

local w=40
local h=40

–display.setDrawMode(“wireframe”,false)

local tileMove = function(self,e)
    
    local t = e.target
    print(“phase:”,e.phase)
    
    if “began” == e.phase then
        
        print("picked up index: ",t.index)
        
        – Make target the top-most object
        --local parent = t.parent
        --parent:insert( t )
        display.getCurrentStage():setFocus( t, e.id )
        t.isFocus = true
        t:toFront()
        
        – Store initial position
        t.x0 = e.x - t.x
        t.xScale=1.35;t.yScale=1.35    --scale on begin drag
        
    elseif “moved” == e.phase then
        
        t.x = e.x - t.x0
        
    elseif “ended” == e.phase then
        
        t.xScale=1;t.yScale=1 – revert scale
        display.getCurrentStage():setFocus( t, nil )
        
        t.isFocus = false
        
        
        elseif “cancelled” == e.phase  then
            
            t.xScale=1;t.yScale=1 – revert scale
            display.getCurrentStage():setFocus( t, nil )
            
            t.isFocus = false
        end
       
        return true
    end
    
 
    
    for i=1,7 do
        tiles[i] = display.newRoundedRect(0, 0, w, h,4)
        tiles[i]:setFillColor(0,0,0)
        tiles[i].stroke={0,1,0}
        tiles[i].strokeWidth = 2
       
        tiles[i].x=i*w
        tiles[i].y=100
        tiles[i].anchorX=0.5
        tiles[i].anchorx=0.5
        tiles[i].index=i
        tiles[i].touch=tileMove
        tiles[i]:addEventListener(“touch”,tiles[i])
    end
    
    
  

OK. I know Im answering my own post…but I have made progress on this. Working quite well but have an issue now when dragging  quickly. Not sure if its because the drag distance is greater than the width or something else im not taking into acccount.

Anybody done similar or can spot what I am maybe doing wrong or can any useful advice. Thanks.

(stand alone main.lua)

math.randomseed(os.time())
local tiles={}

local w=40
local h=40

local tileMove = function(self,e)
    
    local t = e.target
    print(“phase:”,e.phase)
    
    if “began” == e.phase then
        
        print("picked up index: ",t.index)
        
        display.getCurrentStage():setFocus( t, e.id )
        t.isFocus = true
        t:setFillColor(0,0,1)
        t:toFront()
        
        – Store initial position
        t.x0 = e.x - t.x
        t.oldX=t.x0 --store oldX pos
        t.xScale=1.2;t.yScale=1.20    --scale onn begin drag
        
    elseif “moved” == e.phase then

        t.x = e.x - t.x0
        
        local direction=""
        if t.x > t.oldX then
            direction=“right”
        elseif t.x < t.oldX then
            direction=“left”        
        end
        
        function onMoveComplete(obj)
            obj.moving=false
        end
        
        for i=1,#tiles do
            
            local tile = tiles[i]
            
            if t ~= tile and tile.moving==false then
                
                local portion=t.x + (tile.width*0.5)
                
                local x1=tile.x
                local x2 = tile.x+tile.width
                
                if direction==“right” then
                
                    if portion >=x1 and portion<=x2  then
                        print(“over other zone”)
                        
                        tile:setFillColor(1,1,0)
                                                    
                        tile.moving=true                                                  
                        local newX= tile.x-(tile.width/2)
                                            
                        transition.to(tile,{time=10,x=newX,onComplete = onMoveComplete})

                        print(“portion:”,portion,",zone start:",x1,",zone end:",x2)
                        break

                    end
                    
                elseif direction==“left” then
                    
                    portion=t.x + (tile.width*0.5)
                     if portion >=x1 and portion<=x2  then
                        print(“over other zone”)
                       
                        tile:setFillColor(0,1,0)                        
                        tile.moving=true
                        local newX= tile.x+(tile.width/2)

                        transition.to(tile,{time=10,x=newX,onComplete = onMoveComplete})
                        
                        print(“portion:”,portion,",zone start:",x1,",zone end:",x2)
                        break
                    end
                 
                    
                end
                
             
            end
        end
        
        t.oldX =t.x
        
    elseif “ended” == e.phase then
        
        t.xScale=1;t.yScale=1 – revert scale
        
        t:setFillColor(0,0,0)
        
        display.getCurrentStage():setFocus( t, nil )
        
        t.isFocus = false
        
        
        elseif “cancelled” == e.pahase  then
            
            t.xScale=1;t.yScale=1 – revert scale
            display.getCurrentStage():setFocus( t, nil )
            
            t.isFocus = false
        end

        return true
    end
    
    for i=1,7 do
        
        local t = display.newRoundedRect(0, 0, w, h,4)
        t:setFillColor(0,0,0)
        
        t.strokeWidth = 2
        
        t.x=i*w
        t.y=100
        t.anchorX=0.5
        t.anchorx=0.5
        t.index=i
        t.touch=tileMove
        t.moving=false
        t:addEventListener(“touch”,t)
 
        tiles[i]=t
    end
    
    
   

  

Decided to give it a go (: I don’t use transitions (apart from one, which could be avoided but got in for the sake of time)

Should run as is

math.randomseed(os.time()) local tiles={} local w=40 local h=40 local tileEnterframe = function(self, event) if self.isFocus then local selfPos = self.index\*w; if self.x \> selfPos then local adjTile = tiles[self.index+1]; if adjTile then if self.prevTile and self.prevTile ~= adjTile then self.prevTile.x = self.prevTile.index\*w; end self.prevTile = adjTile; local adjPos = adjTile.index\*w; adjTile.x = adjPos-(self.x-selfPos); if adjTile.x \< self.x then self.index = adjTile.index; tiles[self.index] = self; adjTile.index = self.index-1; tiles[adjTile.index] = adjTile; end else if self.prevTile then self.prevTile.x = self.prevTile.index\*w; end end elseif self.x \< selfPos then local adjTile = tiles[self.index-1]; if adjTile then if self.prevTile and self.prevTile ~= adjTile then self.prevTile.x = self.prevTile.index\*w; end self.prevTile = adjTile; local adjPos = adjTile.index\*w; adjTile.x = adjPos+(selfPos-self.x); if adjTile.x \> self.x then self.index = adjTile.index; tiles[self.index] = self; adjTile.index = self.index+1; tiles[adjTile.index] = adjTile; end else if self.prevTile then self.prevTile.x = self.prevTile.index\*w; end end end end end local tileMove = function(self, event) if event.phase == "began" then display.getCurrentStage():setFocus(self); self.isFocus = true; self.xStart = event.x-self.x; self.parent:insert(self); self:setFillColor(1, 0, 0); elseif event.phase == "moved" and self.isFocus then self.x = event.x-self.xStart; elseif event.phase == "ended" and self.isFocus then display.getCurrentStage():setFocus(nil); transition.to(self, {x = self.index\*w, time = 100, onComplete = function() self.isFocus = nil; self:setFillColor(0, 0, 0); end}); end end for i=1,7 do local t = display.newRoundedRect(0, 0, w, h, 4) t:setFillColor(0,0,0) t.strokeWidth = 2 t.x=i\*w t.y=100 t.index=i t.touch=tileMove t.enterFrame = tileEnterframe; t.moving=false t:addEventListener("touch",t) Runtime:addEventListener("enterFrame",t) tiles[i]=t end

Excellent. Gave that a go works pretty well. Found a couple of minor offset glitches but I’m sure I can sort them.

Thought I could achieve what I wanted in the touch event alone. But maybe as you have done your checking on each frame using the enter frame event.

Thanks again.

OK. I know Im answering my own post…but I have made progress on this. Working quite well but have an issue now when dragging  quickly. Not sure if its because the drag distance is greater than the width or something else im not taking into acccount.

Anybody done similar or can spot what I am maybe doing wrong or can any useful advice. Thanks.

(stand alone main.lua)

math.randomseed(os.time())
local tiles={}

local w=40
local h=40

local tileMove = function(self,e)
    
    local t = e.target
    print(“phase:”,e.phase)
    
    if “began” == e.phase then
        
        print("picked up index: ",t.index)
        
        display.getCurrentStage():setFocus( t, e.id )
        t.isFocus = true
        t:setFillColor(0,0,1)
        t:toFront()
        
        – Store initial position
        t.x0 = e.x - t.x
        t.oldX=t.x0 --store oldX pos
        t.xScale=1.2;t.yScale=1.20    --scale onn begin drag
        
    elseif “moved” == e.phase then

        t.x = e.x - t.x0
        
        local direction=""
        if t.x > t.oldX then
            direction=“right”
        elseif t.x < t.oldX then
            direction=“left”        
        end
        
        function onMoveComplete(obj)
            obj.moving=false
        end
        
        for i=1,#tiles do
            
            local tile = tiles[i]
            
            if t ~= tile and tile.moving==false then
                
                local portion=t.x + (tile.width*0.5)
                
                local x1=tile.x
                local x2 = tile.x+tile.width
                
                if direction==“right” then
                
                    if portion >=x1 and portion<=x2  then
                        print(“over other zone”)
                        
                        tile:setFillColor(1,1,0)
                                                    
                        tile.moving=true                                                  
                        local newX= tile.x-(tile.width/2)
                                            
                        transition.to(tile,{time=10,x=newX,onComplete = onMoveComplete})

                        print(“portion:”,portion,",zone start:",x1,",zone end:",x2)
                        break

                    end
                    
                elseif direction==“left” then
                    
                    portion=t.x + (tile.width*0.5)
                     if portion >=x1 and portion<=x2  then
                        print(“over other zone”)
                       
                        tile:setFillColor(0,1,0)                        
                        tile.moving=true
                        local newX= tile.x+(tile.width/2)

                        transition.to(tile,{time=10,x=newX,onComplete = onMoveComplete})
                        
                        print(“portion:”,portion,",zone start:",x1,",zone end:",x2)
                        break
                    end
                 
                    
                end
                
             
            end
        end
        
        t.oldX =t.x
        
    elseif “ended” == e.phase then
        
        t.xScale=1;t.yScale=1 – revert scale
        
        t:setFillColor(0,0,0)
        
        display.getCurrentStage():setFocus( t, nil )
        
        t.isFocus = false
        
        
        elseif “cancelled” == e.pahase  then
            
            t.xScale=1;t.yScale=1 – revert scale
            display.getCurrentStage():setFocus( t, nil )
            
            t.isFocus = false
        end

        return true
    end
    
    for i=1,7 do
        
        local t = display.newRoundedRect(0, 0, w, h,4)
        t:setFillColor(0,0,0)
        
        t.strokeWidth = 2
        
        t.x=i*w
        t.y=100
        t.anchorX=0.5
        t.anchorx=0.5
        t.index=i
        t.touch=tileMove
        t.moving=false
        t:addEventListener(“touch”,t)
 
        tiles[i]=t
    end
    
    
   

  

Decided to give it a go (: I don’t use transitions (apart from one, which could be avoided but got in for the sake of time)

Should run as is

math.randomseed(os.time()) local tiles={} local w=40 local h=40 local tileEnterframe = function(self, event) if self.isFocus then local selfPos = self.index\*w; if self.x \> selfPos then local adjTile = tiles[self.index+1]; if adjTile then if self.prevTile and self.prevTile ~= adjTile then self.prevTile.x = self.prevTile.index\*w; end self.prevTile = adjTile; local adjPos = adjTile.index\*w; adjTile.x = adjPos-(self.x-selfPos); if adjTile.x \< self.x then self.index = adjTile.index; tiles[self.index] = self; adjTile.index = self.index-1; tiles[adjTile.index] = adjTile; end else if self.prevTile then self.prevTile.x = self.prevTile.index\*w; end end elseif self.x \< selfPos then local adjTile = tiles[self.index-1]; if adjTile then if self.prevTile and self.prevTile ~= adjTile then self.prevTile.x = self.prevTile.index\*w; end self.prevTile = adjTile; local adjPos = adjTile.index\*w; adjTile.x = adjPos+(selfPos-self.x); if adjTile.x \> self.x then self.index = adjTile.index; tiles[self.index] = self; adjTile.index = self.index+1; tiles[adjTile.index] = adjTile; end else if self.prevTile then self.prevTile.x = self.prevTile.index\*w; end end end end end local tileMove = function(self, event) if event.phase == "began" then display.getCurrentStage():setFocus(self); self.isFocus = true; self.xStart = event.x-self.x; self.parent:insert(self); self:setFillColor(1, 0, 0); elseif event.phase == "moved" and self.isFocus then self.x = event.x-self.xStart; elseif event.phase == "ended" and self.isFocus then display.getCurrentStage():setFocus(nil); transition.to(self, {x = self.index\*w, time = 100, onComplete = function() self.isFocus = nil; self:setFillColor(0, 0, 0); end}); end end for i=1,7 do local t = display.newRoundedRect(0, 0, w, h, 4) t:setFillColor(0,0,0) t.strokeWidth = 2 t.x=i\*w t.y=100 t.index=i t.touch=tileMove t.enterFrame = tileEnterframe; t.moving=false t:addEventListener("touch",t) Runtime:addEventListener("enterFrame",t) tiles[i]=t end

Excellent. Gave that a go works pretty well. Found a couple of minor offset glitches but I’m sure I can sort them.

Thought I could achieve what I wanted in the touch event alone. But maybe as you have done your checking on each frame using the enter frame event.

Thanks again.