Touchmoved function

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
philfaint
Prole
Posts: 8
Joined: Wed Jul 01, 2020 6:35 pm

Touchmoved function

Post by philfaint »

Hello,

I've been trying to make a rectangle move on mobile devices using touch functions, but failed :) Can someone please explaing me:
1) how can I access values returned by callback functions, like touchmoved, or touchpressed - x, y, dx and dy? I tried to create new tables, and pass values from there into mine. I also tried to access that table directly, but get nil all the time.
2) Do i understand correctly, that if I get the exact value of finger movement (dx, dy) - I can later use it as dx and dy for the rectangle to move it on the screen?

My code is below, and I can't make the rectangle move, when I move my finger on the screen:

Code: Select all

function love.load()
    font = love.graphics.newFont(10)
    love.graphics.setFont(font)
end

touches = {}

rectX = 500
rectY = 200
rectDY = 0

function parseID(id)
    return tostring(id)
end

function love.touchpressed(id, x, y, dx, dy)
    touches[parseID(id)] = {id, x, y, dx, dy}
end

function love.touchmoved(id, x, y, dx, dy)
    touches[parseID(id)] = {id, x, y, dx, dy}
end

function love.touchreleased(id, x, y, dx, dy)
    touches[parseID(id)] = nil

end

function love.updated(dt)
    if rectDY < 0 then
        rectY = math.min(0, rectY + rectDY * dt)
    else
        rectY = math.max(rectY + rectDY * dt, 600)
    end
end

function love.draw()
    --debugInfo()
    local id, x, y, dx, dy
    for _, data in pairs(touches) do
      if data then
        id, x, y, dx, dy = unpack(data)
        love.graphics.setLineWidth(5)
        love.graphics.setColor(255,255,255)

            rectDY = dy*1000
        love.graphics.rectangle('fill', rectX, rectY, 10, 10)
      end
    end
end
User avatar
pgimeno
Party member
Posts: 3549
Joined: Sun Oct 18, 2015 2:58 pm

Re: Touchmoved function

Post by pgimeno »

First thing, you misspelled "update". It's "love.update", not "love.updated".

Second thing, min and max are reversed. It seems intuitive to say "I want the minimum to be zero" and write math.min(0, n) but it actually works the other way around. The minimum of 0 and -7 is -7. The minimum of 0 and 7 is 0. You want max in this case, so that it's never less than zero.

And vice versa for the other case. You want min instead of max, to make it never exceed 600.

Lastly, and less important, you don't need parseID at all. Touch ids are perfectly valid keys for a table. You can do touches[id] = ... without problems.
philfaint
Prole
Posts: 8
Joined: Wed Jul 01, 2020 6:35 pm

Re: Touchmoved function

Post by philfaint »

omg, one typo made me nervous for the entire day. Thank you a lot!

I still have another questions are about the touch functions:
1) How can I access the values of x, y, dx, dy? I tried this for my code inside draw method:

Code: Select all

love.graphics.printf("touchesx: " .. tostring(touches['x']), 0, 30, 800, 'center')
    love.graphics.printf("touchesy: " .. tostring(touches['y']), 0, 40, 800, 'center')
but it always returns me nil. How do I get and see the exact value inside that touch table?

2) Do I understand correctly that in case of multitouch, the touch function would build a table like this:
touches = {
['id'] = {
x, y, dx, dy},
['id2'] = {
x, y, dx, dy}
}
In this case how do I access the id value for second touch, and what semantics should I use to access values of x, y, dx and dy for that second touch?

Thank you!
User avatar
pgimeno
Party member
Posts: 3549
Joined: Sun Oct 18, 2015 2:58 pm

Re: Touchmoved function

Post by pgimeno »

philfaint wrote: Mon Oct 12, 2020 10:32 am I still have another questions are about the touch functions:
1) How can I access the values of x, y, dx, dy? I tried this for my code inside draw method:

Code: Select all

love.graphics.printf("touchesx: " .. tostring(touches['x']), 0, 30, 800, 'center')
    love.graphics.printf("touchesy: " .. tostring(touches['y']), 0, 40, 800, 'center')
but it always returns me nil. How do I get and see the exact value inside that touch table?
Yeah, that won't work. You have two nested tables, one indexed by IDs and another one indexed by sequential numbers starting with 1 (i.e. an array). IIRC the IDs are Lua lightuserdata objects, so you can't really specify them as a constant in your code; you need either a variable, or to iterate through the keys. But see below for what I believe is a better way to handle them.

So, one way to access them with your current scheme is this:

Code: Select all

for id, values in pairs(touches) do
  -- id is the ID
  -- values[1] is also the ID, because you've stored it in the values
  --            (at least in the version you posted)
  -- values[2] is x
  -- values[3] is y
  -- values[4] is dx
  -- values[5] is dy
end
but you don't have any information about their order.

philfaint wrote: Mon Oct 12, 2020 10:32 am 2) Do I understand correctly that in case of multitouch, the touch function would build a table like this:

Code: Select all

touches = {
    ['id'] = {
           x, y, dx, dy},
    ['id2'] = { 
           x, y, dx, dy} 
}
Except for the fact that you stored the id in the inner table as well, yes. Also, if you remove the parseID() call, the keys will no longer be strings.

philfaint wrote: Mon Oct 12, 2020 10:32 am In this case how do I access the id value for second touch, and what semantics should I use to access values of x, y, dx and dy for that second touch?
With your current code, you can't distinguish the order of touches. Still, you can iterate through the table to access them all.

But my advice is to track the order of touches. You can use this code instead:

Code: Select all

local touches = {}

function love.touchpressed(id, x, y, dx, dy)
  -- add this touch as the last element
  touches[#touches + 1] = {id, x, y, dx, dy}
end

function love.touchmoved(id, x, y, dx, dy)
  -- find the touch for this id
  for i, values in ipairs(touches) do
    if values[1] == id then
      -- found it - update the values of this touch
      values[2] = x
      values[3] = y
      values[4] = dx
      values[5] = dy
      return -- no need to keep searching
    end
  end
end

function love.touchreleased(id, x, y, dx, dy)
  -- find the touch for this id
  for i, values in ipairs(touches) do
    if values[1] == id then
      -- found it - remove this touch
      table.remove(touches, i)
      return -- we're done
    end
  end
end
Now, touches[1] contains the values for the first touch, touches[2] the values for the second touch, and so on. For example, touches[2][5] is the dy of the second touch. #touches gives you the number of simultaneous touches.

If you touch with one finger, then with a second finger, then lift the first finger, touch[2] will become touch[1].

Note that I have not tested the above code.
philfaint
Prole
Posts: 8
Joined: Wed Jul 01, 2020 6:35 pm

Re: Touchmoved function

Post by philfaint »

Came up with a solution of detecting multitouch based on the X and Y area of the screen, where the finger touched it. Reverted back to my previous code, felt like managing those indexes would turn into a mess. Also, haven't found a way to differentiate touches, when one was released, and second turned into first back again.

Code: Select all

width, height = love.graphics.getDimensions()

function love.load()
    font = love.graphics.newFont(10)
    love.graphics.setFont(font)
end

touches = {}

rectX = 650
rectY = 200
rectDY = 0

rect2X = 100
rect2Y = 100
rect2DY = 0

function parseID(id)
    return tostring(id)
end

function love.touchpressed(id, x, y, dx, dy)
    touches[parseID(id)] = {id, x, y, dx, dy}
end

function love.touchmoved(id, x, y, dx, dy)
    touches[parseID(id)] = {id, x, y, dx, dy}
end

function love.touchreleased(id, x, y, dx, dy)
    touches[parseID(id)] = nil

end

function love.update(dt)
    if rectDY < 0 then
        rectY = math.max(0, rectY + rectDY * dt)
    else
        rectY = math.min(rectY + rectDY * dt, 375 - 52)
    end

    if rect2DY < 0 then
        rect2Y = math.max(0, rect2Y + rect2DY * dt)
    else
        rect2Y = math.min(rect2Y + rect2DY * dt, 375 - 52)
    end
end

function love.draw()
    --debugInfo()
    local id, x, y, dx, dy
    for _, data in pairs(touches) do
      if data then
        id, x, y, dx, dy = unpack(data)
        love.graphics.setLineWidth(5)
        love.graphics.setColor(255,255,255)

        if x > 600 then
            rectY = math.min(y, 375-52)
            rectDY = dy*1000
            love.graphics.printf("touchesx1: " .. tostring(x), 0, 30, 800, 'right')
            love.graphics.printf("touchesy1: " .. tostring(y), 0, 40, 800, 'right')
            love.graphics.printf("touchesdy1: " .. tostring(dy), 0, 50, 800, 'right')
            love.graphics.printf("recty1: " .. tostring(rectY), 0, 60, 800, 'right')
        elseif x < 100 then
            rect2Y = y 
            rect2DY = dy * 1000
            love.graphics.printf("touchesx1: " .. tostring(x), 0, 30, 800, 'left')
            love.graphics.printf("touchesy1: " .. tostring(y), 0, 40, 800, 'left')
            love.graphics.printf("touchesdy1: " .. tostring(dy), 0, 50, 800, 'left')
        end
        
      end
      
    end
    love.graphics.rectangle('fill', rect2X, rect2Y, 30, 50)
    love.graphics.rectangle('fill', rectX, rectY, 30, 50)
end
One thing that bother me - is it ok to write the code, that maintains touch operations inside draw function? Is that appropriate?
Post Reply

Who is online

Users browsing this forum: Bing [Bot], Google [Bot] and 80 guests