Object overlap detection (updated) - with removal on hit

I cleaned up the code and removed the redundant parameters.
This is a continuation from:
http://twolivesleft.com/Codea/Talk/discussion/4461/another-fine-mesh-i-ve-got-myself-into#Item_19

Drag the boxes so none are touching and the text on the screnn will update


-- Use this function to perform your initial setup
function setup()
    --displayMode( FULLSCREEN )
    --first the rectangle

gameState = 0
loadingScreen = 1
initGraphics = 2
loadCharacters = 3
createCharacter = 4

 cards = {}
    img2 = readImage("Cargo Bot:Crate Blue 3")
    for i=1,10 do
        cards[#cards+1] = Card(i,50*i+10,50,50,50,img2,1,processCardTouch,"player"..i)
    end
end

function draw()
    background(40, 40, 50) 
    bob = "No overlap"
    for i=1,#cards do
       for x = 1,#cards do
            if i ~= x then
                hit = cards[i].hitRect:testOverlap(cards[x].hitRect)             
                if hit == true then
                    bob = cards[x].hitRect.name
                end
            end
        end
        cards[i]:draw()    
    end
    text(bob,100,400)
end

function createBox(x,y,w,h,name)
    -- polygons are defined by a series of points in counter-clockwise order
    -- this is the rectangle used for collision
    local box = physics.body(POLYGON, vec2(-w/2,h/2), vec2(-w/2,-h/2),
     vec2(w/2,-h/2), vec2(w/2,h/2))
    box.x = x
    box.y = y
    box.sensor = true
    box.sleepingAllowed = true
    box.type = STATIC
    box.hitResults = {}
    box.name = name
    return box
end

function touched(touch)
    for i=1,#cards do
      -- loop through all the cards and detect overlap
        cards[i]:touched(touch)
    end
end
Card = class()

function Card:init(id,x,y,width,height,cardImage,activeState,callbackFunction,name)
    self.name = name
    self.id = id
    self.x = x
    self.y = y
    self.width = width
    self.height = height
    self.mesh = mesh()
    self.mesh.texture = cardImage
    self.textureCordsList = {}
    self.mesh:addRect(x,y,width,height)
    self.mesh:setRectTex(id,0,0,1,1)
    self.buttonCorner1 = vec2(x-width/2,y-height/2)
    self.buttonCorner2 = vec2(x+width/2, y+height/2)
    self.hitRect = createBox(x,y,width,height,name)
    print(self.hitRect.name)
    self.callbackFunction = callbackFunction
end

function Card:draw()
    self.mesh:draw()
end

function Card:touched(touch)

    if touch.state == BEGAN then
        -- check if you touched inside of the card
        if touch.x >= self.buttonCorner1.x and touch.x <= self.buttonCorner2.x and touch.y >= self.buttonCorner1.y and touch.y <= self.buttonCorner2.y  then
            selectedId=self.id -- set the id of the card touched. the higher the id the higher the touch presedence
        end
elseif touch.state == MOVING then
        -- update the x and y values to reflect the new position
        if self.id == selectedId then
            --print("moving")
            self.x = self.x +  touch.deltaX
            self.y = self.y +  touch.deltaY
            self.hitRect.x = self.x
            self.hitRect.y = self.y
            self.mesh:setRect(1,self.x,self.y,self.width,self.height)
        end    
    elseif touch.state == ENDED then
        self.buttonCorner1 = vec2(self.x-self.width/2,self.y-self.height/2)
        self.buttonCorner2 = vec2(self.x+self.width/2, self.y+self.height/2)
        selectedId = 0
        --end
    end
end

Any ideas on optimization. I’m on an Ipad mini after 30ish cards the frame rate starts to chug.
More specifically is ther a better way to do:

for i=1,#cards do
       for x = 1,#cards do
            if i ~= x then
                hit = cards[i].hitRect:testOverlap(cards[x].hitRect)             
                if hit == true then
                    bob = cards[x].hitRect.name
                end
            end
        end
end

@Ignatz The the first loop needs to be to the length of the cards list, or the last card will not draw. This is in the draw loop and skipping it stops it from drawing . I could move it out of the draw loop, but I would neet to explicitly call the last card’s draw functon or loop through the list one more time to draw them.

It improved the seed to around 50 cards on the screen working well.

I did not “have” to use physics, but I wanted to. :slight_smile: I am sure there is a mathmatical function to return if 2 rectangles intersect. I just dont know it and did not feel inclined to research the answer. I need to sort out the z-order so the touched card gets drawn last. A nudge in the correct direction would be appreciated for z-ordering.

@Thwapp - for a start, you are doing all the tests twice. You only need to test each pair once, ie if you test A and B, you don’t need to test B and A

So your loop can change from

for i=1,#cards do
       for x = 1,#cards do

to

for i=1,#cards-1 do
       for x = i+1,#cards do

and do you really need to use physics? It does a lot of stuff that you may not need, slowing you down.

@Thwapp, the overlap check for any pair of cards is simple

hit= (math.abs(card1.x-card2.x)<=card.width and math.abs(card1.y-card2.y)<=card.height)

Now that I looked at your hit statement it is the way to go. But I will put a physics toggle in the class for later use. There was a good 2.5x improvement with no physics overlap being called.

@Thwapp - unless you really need physics, avoid it, if you need speed

@Thwapp, if all your cards are the same, there’s no need to addRect all of them. Just create one card mesh and then draw it wherever you want, as many times as you need to. So your card class only needs to store the location of each card, not a mesh.

This may not save a lot of time, but every little helps.

Cards will have several decks and will be unique, for example there will be location decks, a character deck, and various others. I Probably will create a custom list to enable what cards/decks use hit detection.

The reason it is so slow is probably because you are using a complex fully made physics engine, when a simple bounding box collision test would suffice…

I used @ignatz hit formula and got a big speed increase. The reason it is slow is I am looping through all the cards against one another. Instead, if I get rid of the double nested loop, I know the card Id from the begin touch and the nested loop is not needed.
… 30 min later



-- Use this function to perform your initial setup

function setup()

    --displayMode( FULLSCREEN )

    --first the rectangle
bob = "No overlap"
selectedId = 0
gameState = 0
loadingScreen = 1
initGraphics = 2
loadCharacters = 3
createCharacter = 4

 cards = {}
    img2 = readImage("Platformer Art:Block Special Brick")
    for i=1,209 do
        cards[#cards+1] = Card(i,50*i+10,50,50,50,img2,1,processCardTouch,"player"..i)
    end
end

function draw()
    background(40, 40, 50) 
        bob = "moving"
        for x = 1,#cards do
            if selectedId ~= x then
            --hit = cards[i].hitRect:testOverlap(cards[x].hitRect)    
            if selectedId > 0 then
            hit    = (math.abs(cards[selectedId].x-cards[x].x)<=cards[selectedId].width 
                  and math.abs(cards[selectedId].y-cards[x].y)<=cards[selectedId].height)        
             end   
               -- hit    = (math.abs(self.x-cards[x].x)<=self.width 
               --   and math.abs(self.y-cards[x].y)<=self.height)        
            if hit == true then
                bob = "you HIT: "..cards[x].id
                end
            end 
            cards[x]:draw()
        end
    text(bob,100,400)
end

function createCircle(x,y,r)
    local circle = physics.body(CIRCLE, r)
    -- enable smooth motion
    circle.interpolate = true
    circle.x = x
    circle.y = y
    circle.restitution = 0.25
    circle.sleepingAllowed = false
    --debugDraw:addBody(circle)
    circle.type = STATIC
    circle.info = {}
    circle.gravityScale = 0
    circle.info.name = name
    return circle
end

function createBox(x,y,w,h,name)
    -- polygons are defined by a series of points in counter-clockwise order
    -- this is the rectangle used for collision
    local box = physics.body(POLYGON, vec2(-w/2,h/2), vec2(-w/2,-h/2),
     vec2(w/2,-h/2), vec2(w/2,h/2))
    box.x = x
    box.y = y
    box.sensor = true
    box.sleepingAllowed = true
    box.type = STATIC
    box.hitResults = {}
    box.name = name
    return box
end

function touched(touch)
    for i=1,#cards do
      -- loop through all the cards and detect overlap
        cards[i]:touched(touch)
    end
end

Card = class()

function Card:init(id,x,y,width,height,cardImage,activeState,callbackFunction,name)
    self.name = name
    self.id = id
    self.x = x
    self.y = y
    self.width = width
    self.height = height
    self.mesh = mesh()
    self.mesh.texture = cardImage
    self.textureCordsList = {}
    self.mesh:addRect(x,y,width,height)
    self.mesh:setRectTex(id,0,0,1,1)
    self.buttonCorner1 = vec2(x-width/2,y-height/2)
    self.buttonCorner2 = vec2(x+width/2, y+height/2)
    --self.hitRect = createBox(x,y,width,height,name)
    --print(self.hitRect.name)
    self.callbackFunction = callbackFunction
end

function Card:draw()
    self.mesh:draw()
end

function Card:touched(touch)
    if touch.state == BEGAN then
        --bob = "START"
        -- check if you touched inside of the card
        if touch.x >= self.buttonCorner1.x 
                    and touch.x <= self.buttonCorner2.x 
                    and touch.y >= self.buttonCorner1.y 
                    and touch.y <= self.buttonCorner2.y  then
            selectedId=self.id -- set the id of the card touched. 
        end
    elseif touch.state == MOVING then

        -- update the x and y values to reflect the new position
        if self.id == selectedId then
            --print("moving")
            self.x = self.x +  touch.deltaX
            self.y = self.y +  touch.deltaY
            --self.hitRect.x = self.x
            --self.hitRect.y = self.y
            self.mesh:setRect(1,self.x,self.y,self.width,self.height)
        end    
    elseif touch.state == ENDED then
        self.buttonCorner1 = vec2(self.x-self.width/2,self.y-self.height/2)
        self.buttonCorner2 = vec2(self.x+self.width/2, self.y+self.height/2)
        selectedId = 0
        --end
    end
end

Now I can detect a hit on over 200+ objects. I think this class is going to turn into a general hit detection. Card seems to specific. The next step is to get multi touch working.

@Thwapp - now you’re thinking. It’s fun when you suddenly break through, isn’t it?

I usually pick things up fairly quickly but there is so much to learn when programming ui elements in realtime. I’m having fun but eventually I will run out of classes to make for the tile engine and then on to uber prototyping. The next step is to create a list of all the objects who collide with the dragged mesh(cursor). Then z order sorting and then object to object communication.

A little update with the scaling up the selected object. There are a few bugs but I need to think on how to incoperate mutiple objects at hit at once. I want the ripple shader to run on the selected card object. I know it is simple but I just dont see it. I looked at the shader example and tried to emmulate it but no go.

Anyone to the rescue :slight_smile:

    
      
    
    -- load me
    
    function setup()
    
        --displayMode( FULLSCREEN )
    
        --first the rectangle
    bob = "No overlap"
    selectedId = 0
    gameState = 0
    loadingScreen = 1
    initGraphics = 2
    loadCharacters = 3
    createCharacter = 4
    
     cards = {}
        img2 = readImage("Platformer Art:Block Special Brick")
        for i=1,11 do
            cards[#cards+1] = Card(i,50*i+10,50,50,50,img2,1,processCardTouch,"player"..i)
        end
    end
    
    function draw()
        Etime=ElapsedTime
        background(40, 40, 50) 
            --bob = "Stoped"
            q=0
          --  hitCount = 0
            for x = 1,#cards do
                if selectedId ~= x and selectedId > 0 then --dont test self
                --hit = cards[i].hitRect:testOverlap(cards[x].hitRect)    
                cards[selectedId].hitList = {}
                    --test if within the other cards coordinates
                hit = (math.abs(cards[selectedId].x-cards[x].x)<=cards[selectedId].width 
                      and math.abs(cards[selectedId].y-cards[x].y)<=cards[selectedId].height)         
                if hit == true then
                    table.insert(cards[x].hitList,hitCount)
                     bob =  cards[x].name --#cards[selectedId].hitList
                    end
                end  
                cards[x]:draw()
                
            end
            if selectedId > 0 then cards[selectedId]:draw() end
        text("current State "..bob,100,400)
        text("last hit "..q,100,370)
    end
     
    function createCircle(x,y,r)
        local circle = physics.body(CIRCLE, r)
        -- enable smooth motion
        circle.interpolate = true
        circle.x = x
        circle.y = y
        circle.restitution = 0.25
        circle.sleepingAllowed = false
        --debugDraw:addBody(circle)
        circle.type = STATIC
        circle.info = {}
        circle.gravityScale = 0
        circle.info.name = name
        return circle
    end
    
    function createBox(x,y,w,h,name)
        -- polygons are defined by a series of points in counter-clockwise order
        -- this is the rectangle used for collision
        local box = physics.body(POLYGON, vec2(-w/2,h/2), vec2(-w/2,-h/2),
         vec2(w/2,-h/2), vec2(w/2,h/2))
        box.x = x
        box.y = y
        box.sensor = true
        box.sleepingAllowed = true
        box.type = STATIC
        box.hitResults = {}
        box.name = name
        return box
    end
    
    function touched(touch)
        for i=1,#cards do
          -- loop through all the cards and detect overlap
            cards[i]:touched(touch)
        end
    end
    
    Card = class()
    
    function Card:init(id,x,y,width,height,cardImage,activeState,callbackFunction,name)
        self.name = name
        self.id = id
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.selected = false
        self.scale = 1 -- the multiplier for  the selected tile size
        self.mesh = mesh()
        self.mesh.texture = cardImage
        self.textureCordsList = {} -- the list of vec2 for the uv cordinates and their delay
        -- this delay will be used in the timer class for animating the textures
        self.mesh:addRect(x,y,width,height)
        self.mesh:setRectTex(id,0,0,1,1)
        self.buttonCorner1 = vec2(x-width/2,y-height/2)
        self.buttonCorner2 = vec2(x+width/2, y+height/2)
        --self.hitRect = createBox(x,y,width,height,name)
        --print(self.hitRect.name)
        self.callbackFunction = callbackFunction
        --self.mesh.shader = shader("Effects:Ripple")
        self.hitList = {}
    end
   function Card:changePos(x,y)
        self.x=self.x+x
        self.y=self.y+y
        self.buttonCorner1 = vec2(self.x-self.width/2,self.y-self.height/2)
        self.buttonCorner2 = vec2(self.x+self.width/2, self.y+self.height/2) 
    end 
    function Card:draw()
        if self.mesh.shader then
        self.mesh.shader.time=ElapsedTime
       end
        --self.mesh:draw()
        self.mesh:draw()
    end
    
    function Card:touched(touch)
        if touch.state == BEGAN then
            local firstTouch = 0
            bob = "selected"
            -- check if you touched inside of the card
            if touch.x >= self.buttonCorner1.x 
                        and touch.x <= self.buttonCorner2.x 
                        and touch.y >= self.buttonCorner1.y 
                        and touch.y <= self.buttonCorner2.y then
                self.selected = true
                firstTouch = 1
                selectedId=self.id
                    self.mesh.shader = shader("Effects:Ripple")
                    self.mesh.shader.freq=1
                self.scale = 2
                self.y = self.y + 50 -- reset the initial touch. 
                self.mesh:setRect(1,self.x,self.y,self.width*self.scale,self.height*self.scale)
                self.buttonCorner1 = vec2(self.x-self.width/2*self.scale,self.y-self.height/2*self.scale)
                self.buttonCorner2 = vec2(self.x+self.width/2*self.scale, self.y+self.height/2*self.scale)
                -- set the id of the card touched. 
               -- tint(255, 2, 0, 255)
            end
    elseif touch.state == MOVING then
        
            -- update the x and y values to reflect the new position
            if self.id == selectedId then
                bob = "moving"
                
                --print("moving")
                self.x = self.x + touch.deltaX
                self.y = self.y + touch.deltaY
                --self.hitRect.x = self.x
                --self.hitRect.y = self.y
                self.mesh:setRect(1,self.x,self.y,self.width*self.scale,self.height*self.scale)
                self.buttonCorner1 = vec2(self.x-self.width/2*self.scale,self.y-self.height/2*self.scale)
                self.buttonCorner2 = vec2(self.x+self.width/2*self.scale, self.y+self.height/2*self.scale)
            end    
        elseif touch.state == ENDED then
            bob = "ended"
            self.scale = 1
            self.mesh.shader = nil
            
            --self.y = self.y - 50
            self.hitList = {}
            if self.selected == true then
                -- only affect the selected object
                self.mesh:setRect(1,self.x,self.y-50,self.width*self.scale,self.height*self.scale)
            else 
                self.mesh:setRect(1,self.x,self.y,self.width*self.scale,self.height*self.scale)
            end
            -- reset the size of the hit bounding box 
            self.buttonCorner1 = vec2(self.x-self.width/2*self.scale,self.y-self.height/2*self.scale)
            self.buttonCorner2 = vec2(self.x+self.width/2*self.scale, self.y+self.height/2*self.scale)
            self.selected = false
            local tmp = cards[selectedId]
            selectedId = 0
         --  print("zzselected id:"..tmp.id)
          --  table.remove(cards,selectedId)
        --    table.insert(cards,#cards+1,tmp)

            
            --end
        end
    end

@Thwapp - if you go back to the shader lab and look in the tab called Bindings, you’ll see you need to set a couple of variables.

You’ve done texture, so that’s OK, but you need to do “freq” and “time”. Because these are custom settings (they aren’t in the standard shader), they need to be attached to the shader rather than the mesh.

“freq” looks as though it is set just once at the beginning, while “time” needs to change (you can use anything you want, but ElapsedTime is the number of seconds the program has been running, and that will do). So “time” needs to be updated in draw.

--after this
self.shader = shader("Effects:Ripple")
--you can put this
self.shader.freq=1

--your draw function becomes this
function Card:draw()
        self.shader.time=ElapsedTime
        self.mesh:draw()
    end

@Thwapp - actually, I just noticed something.

Shaders are attached to meshes. “Self” is not a mesh in your code, but “self.mesh” is. So the code above needs to be

--after this
self.mesh.shader = shader("Effects:Ripple")
--you can put this
self.mesh.shader.freq=1

--your draw function becomes this
function Card:draw()
    self.mesh.shader.time=ElapsedTime
    self.mesh:draw()
end

Thx @Ignatz. I can’t believe I missed that. :slight_smile: Is there a switch to disable the shader. Like mesh.shader.render = off or something like that? I tried deleting the shader but then I need to move the fequency value to a more global setting for this to work.

NM I just set the render object to nil and checked if the mesh shader existed before updating the freq variable, and now it works onr the selected object. I updated the code above to save space

@Thwapp

self.mesh.shader=nil

@Ignatz My meshes turn invisible when I change their shader or set it to nil…

@SkyTheCoder Let me see if I uploaded the final version. I have several tabs I combine to paste it. So let me check.

This one works for me. let me know if there are any more issues besides the bugs with moving the previously selected cards and selecting the same object twice in a row. I’m going to fix this and add a simple animation to them. I’m skipping work because my wife is sick :(, but the upside is I can take care of her and program codea. I love this program.

Updated with debugging mode and a toggle to remove the offset when you select an object.

    
    
    -- load me
    
    function setup()
    
        --displayMode( FULLSCREEN )
    
        --first the rectangle
    bob = "No overlap"
    selectedId = 0
    gameState = 0
    loadingScreen = 1
    initGraphics = 2
    loadCharacters = 3
    createCharacter = 4
    
     cards = {}
        img2 = readImage("Cargo Bot:Condition Any")
        for i=1,11 do
            cards[#cards+1] = Card(i,50*i+10,50,50,50,img2,1,processCardTouch,"Card"..i,1,1)
        end
    end
    
    function draw()
        Etime=ElapsedTime
        background(40, 40, 50) 
            --bob = "Stoped"
            q=0
          --  hitCount = 0
            for x = 1,#cards do
                if selectedId ~= x and selectedId > 0 then --dont test self
                --hit = cards[i].hitRect:testOverlap(cards[x].hitRect)    
                cards[selectedId].hitList = {}
                    --test if within the other cards coordinates
                hit = (math.abs(cards[selectedId].x-cards[x].x)<=cards[selectedId].width 
                      and math.abs(cards[selectedId].y-cards[x].y)<=cards[selectedId].height)         
                if hit == true then
                    table.insert(cards[x].hitList,hitCount)
                     bob =  cards[x].name --#cards[selectedId].hitList
                    end
                end  
                cards[x]:draw()
                
            end
            if selectedId > 0 then cards[selectedId]:draw() end
        text("current State "..bob,100,400)
        text("last hit "..q,100,370)
    end
     
    function createCircle(x,y,r)
        local circle = physics.body(CIRCLE, r)
        -- enable smooth motion
        circle.interpolate = true
        circle.x = x
        circle.y = y
        circle.restitution = 0.642
        circle.sleepingAllowed = false
        --debugDraw:addBody(circle)
        circle.type = STATIC
        circle.info = {}
        circle.gravityScale = 0
        circle.info.name = name
        return circle
    end
    
    function createBox(x,y,w,h,name)
        -- polygons are defined by a series of points in counter-clockwise order
        -- this is the rectangle used for collision
        local box = physics.body(POLYGON, vec2(-w/2,h/2), vec2(-w/2,-h/2),
         vec2(w/2,-h/2), vec2(w/2,h/2))
        box.x = x
        box.y = y
        box.sensor = true
        box.sleepingAllowed = true
        box.type = STATIC
        box.hitResults = {}
        box.name = name
        return box
    end
    
    function touched(touch)
        for i=1,#cards do
          -- loop through all the cards and detect overlap
            cards[i]:touched(touch)
        end
    end
    
    Card = class()
    
    function Card:init(id,x,y,width,height,cardImage,activeState,callbackFunction,name,debug,touchOffset)
        self.name = name
        self.id = id
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.selected = false
        self.scale = 1 -- the multiplier for  the selected tile size
        self.mesh = mesh()
        self.mesh.texture = cardImage
        self.textureCordsList = {} -- the list of vec2 for the uv cordinates and their delay
        -- this delay will be used in the timer class for animating the textures
        self.mesh:addRect(x,y,width,height)
        self.mesh:setRectTex(id,0,0,1,1)
        self.buttonCorner1 = vec2(x-width/2,y-height/2)
        self.buttonCorner2 = vec2(x+width/2, y+height/2)
        --self.hitRect = createBox(x,y,width,height,name)
        --print(self.hitRect.name)
        self.callbackFunction = callbackFunction
        --self.mesh.shader = shader("Effects:Ripple")
        self.hitList = {}
        self.debug=debug
        self.health = health or 10
        self.touchOffset = touchOffset or 0
    end
   function Card:changePos(x,y)
        self.x=self.x+x
        self.y=self.y+y
        self.buttonCorner1 = vec2(self.x-self.width/2,self.y-self.height/2)
        self.buttonCorner2 = vec2(self.x+self.width/2, self.y+self.height/2) 
    end 
    function Card:draw()
        if self.mesh.shader then
        self.mesh.shader.time=ElapsedTime
       end
        --self.mesh:draw()
        self.mesh:draw()
        -- if debugging mode is on then draw hitrect and 
        if self.debug == 1 and self.selected == true then
            --print("ghghgh")
            noSmooth()
            pushStyle()
            stroke(255)
            strokeWidth(1)
            rectMode(CENTER)
            rect(self.x,self.y,self.width, self.height)
            text("x:"..self.x,self.x,self.y+self.height)
            text("y:"..self.y,self.x,self.y+self.height+16)
            popStyle()
            end
            
    end
    
    function Card:touched(touch)
        if touch.state == BEGAN then
            local firstTouch = 0
            bob = "selected"
            -- check if you touched inside of the card
            if touch.x >= self.buttonCorner1.x 
                        and touch.x <= self.buttonCorner2.x 
                        and touch.y >= self.buttonCorner1.y 
                        and touch.y <= self.buttonCorner2.y then
                self.selected = true
                firstTouch = 1
                selectedId=self.id
                self.mesh.shader = shader("Effects:Ripple")
                self.mesh.shader.freq=0.487
                self.scale = 1
                if self.touchOffset == 1 then   
                    self.y = self.y + 50 -- reset the initial touch.
                end 
                self.mesh:setRect(1,self.x*self.scale,self.y*self.scale,self.width*self.scale,self.height*self.scale)
                self.buttonCorner1 = vec2(self.x-self.width/2*self.scale,self.y-self.height/2*self.scale)
                self.buttonCorner2 = vec2(self.x+self.width/2*self.scale, self.y+self.height/2*self.scale)
            end
    elseif touch.state == MOVING then
        
            -- update the x and y values to reflect the new position
            if self.id == selectedId then
                bob = "moving" 
                --print("moving")
                self.x = self.x + touch.deltaX
                self.y = self.y + touch.deltaY
                --self.hitRect.x = self.x
                --self.hitRect.y = self.y
                self.mesh:setRect(1,self.x,self.y,self.width*self.scale,self.height*self.scale)
                self.buttonCorner1 = vec2(self.x-self.width/2*self.scale,self.y-self.height/2*self.scale)
                self.buttonCorner2 = vec2(self.x+self.width/2*self.scale, self.y+self.height/2*self.scale)
            end    
        elseif touch.state == ENDED then
            bob = "ended"
            self.scale = 1
            self.mesh.shader = nil
            
            --self.y = self.y - 50
            self.hitList = {}
            if self.selected == true then
                -- only affect the selected object
                if self.touchOffset == 1 then   
                    --self.y = self.y - 50 -- reset the initial touch.
                end
                self.mesh:setRect(1,self.x,self.y,self.width*self.scale,self.height*self.scale)
                self.buttonCorner1 = vec2(self.x-self.width/2*self.scale,self.y-self.height/2*self.scale)
                self.buttonCorner2 = vec2(self.x+self.width/2*self.scale, self.y+self.height/2*self.scale)
            else 
                self.mesh:setRect(1,self.x,self.y,self.width*self.scale,self.height*self.scale)
            end
            -- reset the size of the hit bounding box 
            self.buttonCorner1 = vec2(self.x-self.width/2*self.scale,self.y-self.height/2*self.scale)
            self.buttonCorner2 = vec2(self.x+self.width/2*self.scale, self.y+self.height/2*self.scale)
            self.selected = false
            local tmp = cards[selectedId]
            selectedId = 0
         --  print("zzselected id:"..tmp.id)
          --  table.remove(cards,selectedId)
        --    table.insert(cards,#cards+1,tmp)

            
            --end
        end
    end

simple debug:
When dragging the object the hit area will display (needs alpha) and shows the object’s center x y coordinates. You can also toggle the the offset when the object is selected