Dragging Objects in CoronaDragging objects is something that’s common across many games and apps, but unfortunately, how to do it isn’t readily apparent. Today, I’m going to show you exactly how basic dragging is accomplished—and it’s easier than you think.

Here’s the logic behind it:

At the start of a user’s touch (also known as the “began” phase of a touch event), you must store the current location of the object. Then, during the “move” phase of the event, you subtract the start location of the event (event.xStart, event.yStart) from the event’s current location (event.x, event.y) and also add the stored location of the object. Finally, you change the object’s location to the newly calculated one and that’s what moves the object with the user’s finger.

Sounds like a mouthful right? Here’s the code:

And that’s it! That’s all there is to dragging objects in Corona. And although this tutorial was a little on the short side, its usefulness is infinite—I find myself using the same code I shared here across many different projects.

Feel free to ask any questions you have in the comments section, or start a new thread in the forums and post a link to it.

  1. Another “killer” tutorial!

    Thanks a lot Jon. I put in on memory bank for time when I will need to use it…which maybe pretty soon.

    Thanks.

    Mo

  2. I have seen this method lot of times, but if I really just want to drag an object then why do I need to store the x and y position in the variables in the began phase and then again in the moved phase substract do all this things?

    Why cant I do directly like the following code? Is there anything wrong with the following code? Plz. advice.

    -- create object
    local myObject = display.newRect( 0, 0, 100, 100 )
    myObject:setFillColor( 255 )

    -- touch listener function
    function myObject:touch( event )

    if event.phase == "moved"
    then
    self.x = event.x
    self.y = event.y
    end

    return true

    end

    -- make 'myObject' listen for touch events
    myObject:addEventListener( "touch", myObject )

  3. Better capture the focus during the “began” phase. Otherwise you lose the object during fast dragging.

    function myObject:touch( event )
    if event.phase == “began” then
    — begin focus
    display.getCurrentStage():setFocus( self, event.id )
    self.isFocus = true

    self.markX = self.x
    self.markY = self.y

    elseif self.isFocus then
    if event.phase == “moved” then
    — drag touch object
    self.x = event.x – event.xStart + self.markX
    self.y = event.y – event.yStart + self.markY

    elseif event.phase == “ended” or event.phase == “cancelled” then
    — end focus
    display.getCurrentStage():setFocus( self, nil )
    self.isFocus = false
    end
    end

    — event handled
    return true
    end

  4. Jonathan Beebe says:

    @PiotrT: Here’s a previous tutorial about dragging physics, exactly what you’re looking for: http://blog.anscamobile.com/2010/11/tutorial-dragging-physics/

    @dm: I agree, you should definitely set focus on objects in their touch listeners, so great point! However, I just wanted to explain and show the basic logic related to dragging specifically in this tutorial—to prevent any confusion or misunderstanding as to what’s relevant to dragging, and what’s not.

    Thanks for the comments thus far guys—keep them coming!

  5. Jonathan Beebe says:

    @Abstract Edge: The reason I stored the object’s x/y coordinates at the start of the touch, and then add them on every move phase, is because where the user touched the object may not be where the it’s reference point is, causing the image to jump into place as soon as you move it.

    When you modify an object’s x/y coordinates, it positions the reference point of the object to those coordinates. By adding it’s stored location, you’re really just adding an offset so that the object will appear to move from where it was at, to where you dragged it.

    I encourage you to try omitting the storing of the object’s coordinates (and adding during the move event) and see what happens. Sometimes that’s the best way to learn and understand new things.

  6. Keep up the good work Jon,
    but I think in your writing are 2 mistakes:
    – “That’s all there is to dragging objects in Corona” – I think there’s a lot more needed
    – “its usefulness is infinite” – I think it’s limited to special cases, for non physics maybe it’s perfect

    In a physics controlled bodies this kind of dragging will not work as one would await. I think you will create strange unwanted forces.

    I think your later comment “I just wanted to explain and show the basic logic” is missed in the article.

  7. How is this different than the gameUI.dragBody (event, prop)? I’m guessing this technique above would not require the gameUI module and same memory space?

    -David

  8. I have a question, and it’s more of a basic lua/corona question.

    return true
    end

    What does return true do? The problem I have is I find a lot of tutorials, and they all assume that I’ve done some programming but doesn’t explain these little things.

    What are the advantages to return true, vs not using it at all (i’m not that great at programming yet, go easy on me!) .

    ng

  9. Jonathan Beebe says:

    @ng: When it comes to touch events, return true let’s the event know that a touch was “intended” and prevents touches from going THROUGH that object, potentially to another object behind it with a touch listener. If you don’t return anything, it’ll return nil by default, and with touch listeners, that means the touch will go through.

    With other functions, return true does whatever you programmed it to do. You can make a function return any variable (to include functions and tables). Since the concept of a touch listener function is built into the Corona core, returning true to specify whether a touch was successful/intended is how they were programmed.

  10. Jonathan Thomas says:

    This tutorial is so close! I am trying to figure out how to create an event where this draggable object has a final destination where I want it to stop once I drag it within a certain proximity of the final spot. Like for puzzle pieces???? Please help. I hope it’s not too difficult for a newbie coder like myself.

  11. Jonathan Thomas says:

    Thank you so much! I’ve only been coding for a month now! You seem to have done it all man! WHERE DID YOU START? Any specific Lua programming book? Just dissecting sample code (like I’m doing)? I want to fasttrack my learning, but not miss any fundamental basics. Too much of this is still jargon to me, but I’m very technical minded so I’m determined to stick it out.

    I will develop a puzzle app (as my 1st app) yet this year.

  12. Jonathan Beebe says:

    I started by looking at the beginner docs, then studied the SampleCode (especially Samurai Kitchen!), built my first app, and then built more apps and kept improving as I went. In between, I learned more about Lua and continued to gain more experience by putting what I learned into practice … all that in just a few months time, and I’m no genius. With Corona, that’s all it takes.

    You’ll have it all down in no time flat :-)

  13. Dan Ringrose says:

    This is awesome – Thank you Jonathan. I have two things I’m struggling with:
    a) how to extend listening for a touch on a single object (this example) to listening for touches to an array of objects on the screen. For now I’m not concerned with physics for the objects, just allowing the user to drag any of them to a desired position. Do I need write a loop that creates an event listener for each object in the array? Naive question, I know.

    b) how to incorporate additional function into the listener, so that when an object is touched (tapped) a counter gets incremented for that object, rather than dragging the object around. Do I just put this in the “began” phase of the touch event?

    I’m new at all this, but slowly getting up to speed. Once I figure out the essential mechanics I can then move on to building an app around them! Thanks!

  14. Two questions:
    First, I am looping through an array img[i] to load eight PNG images that I want to be able to move around the screen. How would I code the event listener when there are indices for each image, and would I do it inside of the loop or outside of the loop.

    Next, how would I write the function(s) to move the images? Would I write one function overall, or eight individual functions, one for each image?

    Here is where I finally got stuck:

    for y = 0, 2 do
    for x = 0, 2 do
    z = z + 1
    if z == 9 then break end
    img[z] = display.newImage(0 .. z .. “.PNG”,0,0,true)
    img[z].x = x * 100 + 65
    img[z].y = y * 100 + 105
    img[z]:addEventListener( “touch”, img[z] )
    end
    end

    — touch listener function
    function img:touch( event )
    if event.phase == “began” then

    self.markX = self.x — store x location of object
    self.markY = self.y — store y location of object

    elseif event.phase == “moved” then

    local x = (event.x – event.xStart) + self.markX
    local y = (event.y – event.yStart) + self.markY

    self.x, self.y = x, y — move object based on calculations above
    end

    return true
    end

  15. I actually tried to use this code in a brand new blank main.lua file and it wouldn’t work at all. I could see the white rectangle but clicking on it and dragging it didn’t do anything. Any ideas why?

  16. I want to be able to drag an object in the y-axis direction only or the x-axis direction only depending on which way I move my finger on the screen. I have come so far that I can see that the code should just change the y-coordinate or the x-coordinate depending on which situation it is. However, I need to somehow detect whether the user is dragging alongside the y-axis or the x-axis to determine whether to use the code that changes the y-coordinate or the code that changes the x-coordinate.

  17. I am trying to use the same code to swap two objects but getting an error that self.x is a nil value. Help please !

    local jewel_id={}

    function jewel_id: touch( event )
    print(“EVENT CALLED”)
    if event.phase == “began” then
    –begin focus
    display.getCurrentStage():setFocus( event.target )
    self.isFocus = true
    print(“SELF.X::”,self.x)
    print(“SELF.Y::”,self.y)
    self.markX = self.x
    self.markY = self.y

    elseif self.isFocus then
    if event.phase == “moved” then
    self.x = event.x – event.xStart + self.markX
    self.y = event.y – event.yStart + self.markY

    elseif event.phase == “ended” then
    self.x=self.markX
    self.y=self.markY
    display.getCurrentStage():setFocus(nil )
    self.isFocus = false
    elseif event.phase == “cancelled” then
    display.getCurrentStage():setFocus(nil )
    self.isFocus = false
    end
    end
    –event handled
    return true
    end

    jewel_id[(x1*y1)+(y1-1)]:addEventListener( “touch”, jewel_id)

  18. hi ,

    The code is working and tutorial is awesome, but when i place the object some where else other than the target position , the object moves to the original position in a flash , but i need to have smooth movement to its original position , is there any way . Pls tell me soon .

  19. I am dragging the object , but when i leave the object other than the specified target , its just disappearing . But what i need is , it should smoothly go back to its original position . How to do this , give me some examples.

  20. Hai All.,
    I am really very new to corona(lua)
    please any one help!

    The question is :

    First I stored 10 images in array(i.e., table) from 1-10 as key values and I create a random number using math.random function between 0-9.,
    and i need to access the image that is stored in array by the value created by random function, and need to assign the touch and move(drag and drop) function for the particular image file alone., other images also needs touch(i.e, drag alone)

    Ex:
    if the random fn creates no as “5” i need to drag and drop the image 5.png that is stored in array index as 5 .,other images except 5.png should not able to drop., (i.e., they are allowed to move in screen but not to drop able in screen)

    Thanks a lot

  21. Hey would it be possible to explain with a diagram (or similar visual aid) what exactly each of those variables is storing? for example what exactly is markX (I know that it is the stored points of the original, or something similar, but in relation to the data of the other variables where is it?)

  22. In my opinion, just use a simple code below to accomplish the same result without going through overhead calculations.
    I use this code in my games to drag the objects.

    function player:touch( event )
    if (event.phase==”moved”) then
    self.x = event.x
    end
    return true
    end

  23. For those of you who need to drag an object that is within a display group that has been scaled, here is the code that will correctly move the dragable object inside that display group (only difference is in the “moved” phase so that is what I’m posting):

    if event.phase == “moved” then
    — drag touch object
    local reverseScaleFactorX = myDisplayGroup.width / myDisplayGroup..contentWidth
    local reverseScaleFactorY = myDisplayGroup.height / myDisplayGroup.contentHeight

    local distanceMovedScaledX = (event.x – event.xStart) * reverseScaleFactorX
    local distanceMovedScaledY = (event.y – event.yStart) * reverseScaleFactorY

    self.x = distanceMovedScaledX + self.markX
    self.y = distanceMovedScaledY + self.markY

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>