Having character follow finger movement

I am relatively new to Corona so I apologize in advance if this is a dumb question.  I’ve searched the forum and not found anything like this, so here it goes.

The scenario I am attempting to create is one where an object onscreen moves at a constant speed towards wherever the user is currently touching.  So, if a touch is begun, the object starts moving towards the touch start position.  But, if the user drags their finger, the object would stop its current transition and start moving towards the new finger position.  This would continue until the user ended the touch event.

I have this working in some regards, but problematically.  If the user taps the screen, the objects moves towards the tap.  If, during the middle of that movement, the user taps the screen again, the object immediately starts moving towards the new tap position.  

The problem that I am running into is during the drag phase.  There is a visible, very jaunty effect that occurs as the user drags their finger on the device.  

I was hoping that someone could help me along or point me in the right direction.  You can see the code that I am using below.

Thanks!

\_W = display.contentWidth \_H = display.contentHeight local frog = display.newRect(0,0,50,50) frog:setReferencePoint(display.CenterReferencePoint) frog.x = \_W / 2 ; frog.y = \_H / 2 local currentTransition local xStart local yStart local function moveFrog(event) if currentTransition ~= nil then transition.cancel( currentTransition ) end if event.phase == "began" then xStart = event.xStart yStart = event.yStart elseif event.phase == "moved" then xStart = event.x yStart = event.y elseif event.phase == "ended" then xStart = event.x yStart = event.y end distance = math.sqrt((event.x-frog.x)^2+(event.y-frog.y)^2) speed = 0.1 currentTransition = transition.to(frog,{time = (distance / speed),x = xStart , y = yStart}) end Runtime:addEventListener("touch", moveFrog)

I think you want to forget about using transition. In situations like this it can seem like an easy solution, but you are effectively trying to modify the parameters to the transition function after the transition has begun. What you end up doing is killing the current transition and creating a new one every moved phase of the touch.

What you should probably do is store (in the object being moved) the speed (as X and Y direction values) of the object. Every time the touch occurs update the X and Y values to be moving the object towards the touch. To animate the object you would need an enterFrame function which would simply add the direction X and Y values to the object’s .x and .y values.

To make the animation a little smoother, you might want to check the angle between the touch location and the object and the object and it’s next location, each frame. If the angle between the object and the touch is greater than the angle between the object and it’s next location you would want to smooth the next location angle a little. This is fairly tricky and may not be necessary.

Ultimately, what you’ll see in many games where the character is constantly walking, is that changing direction causes it to visibly (though maybe very quickly) spin, causing a small turning (rather than rotating on the spot) and the spin is applied over a number of animation frames.

I have some useful mathematics functions here: http://developer.coronalabs.com/code/maths-library

Wow.  That is an interesting way to approach this.  I wouldn’t have thought of going about it this way.  Thanks.

I can see where the transition approach would cause problems (obviously).  I am not really worried the character’s rotation at this point, but that is definitely good to keep in mind.

I appreciate your input.  I may have another question along the way.

Thanks again!

As I assumed I would, I have another question (or questions).  I am using the runtime touch detection. I am setting my character up as a physics body and then attempting to set the linear velocity towards the touch point.  I had similar code working in another programming environment but for the life of me cannot seem to get it working here.  Below is what I have that is clearly wrong.  

Is this the right approach and if so, what am I doing wrong?  If it is the wrong way to go about this, can you point me to some code that does it correctly?

Thanks!

function update( event ) piranhaMovement() end function piranhaMovement () if piranha.x == piranha.targetx and piranha.y == piranha.targety then piranha:setLinearVelocity(0, 0) end end function updatePiranha ( event ) local deltaX = event.x - piranha.x local deltaY = event.y - piranha.y local piranhaDirection = math.atan2(deltaY, deltaX) \* 180 / math.pi piranha.targetx = event.x piranha.targety = event.y piranha:setLinearVelocity( math.cos(1 \* piranhaDirection), math.sin( 1\* piranhaDirection)) end timer.performWithDelay(1, update, -1) Runtime:addEventListener("touch", updatePiranha)

Oops.  I posted this and then immediately afterwards figured out part of the problem.  I was converting the angle to degrees unnecessarily. I also changed the timer.perform function to a runtime event for enter frame. Now, i can’t figure out how to make the character stop once it reaches the touch point.

Any ideas?

function piranhaMovement () if piranha.x == piranha.targetx and piranha.y == piranha.targety then piranha:setLinearVelocity(0, 0) end end function updatePiranha ( event ) local deltaX = event.x - piranha.x local deltaY = event.y - piranha.y local piranhaDirection = math.atan2(deltaY, deltaX) piranha.targetx = event.x piranha.targety = event.y print("piranhaDirection = "..piranhaDirection) print("piranhaDirection as degrees = "..math.deg(piranhaDirection)) piranha:setLinearVelocity( piranha.speed \* math.cos(1 \* piranhaDirection), piranha.speed \* math.sin( 1\* piranhaDirection)) end function update( event ) piranhaMovement() end Runtime:addEventListener("touch", updatePiranha) Runtime:addEventListener("enterFrame", update)

I figured out how to stop the movement, if anyone is interested.  It looks like the actor’s x and y positions would never equal the event x and y positions as the contained fractional information.  Switching over to math.round(actor.x) in my controlling if statement did the trick.

I think you want to forget about using transition. In situations like this it can seem like an easy solution, but you are effectively trying to modify the parameters to the transition function after the transition has begun. What you end up doing is killing the current transition and creating a new one every moved phase of the touch.

What you should probably do is store (in the object being moved) the speed (as X and Y direction values) of the object. Every time the touch occurs update the X and Y values to be moving the object towards the touch. To animate the object you would need an enterFrame function which would simply add the direction X and Y values to the object’s .x and .y values.

To make the animation a little smoother, you might want to check the angle between the touch location and the object and the object and it’s next location, each frame. If the angle between the object and the touch is greater than the angle between the object and it’s next location you would want to smooth the next location angle a little. This is fairly tricky and may not be necessary.

Ultimately, what you’ll see in many games where the character is constantly walking, is that changing direction causes it to visibly (though maybe very quickly) spin, causing a small turning (rather than rotating on the spot) and the spin is applied over a number of animation frames.

I have some useful mathematics functions here: http://developer.coronalabs.com/code/maths-library

Wow.  That is an interesting way to approach this.  I wouldn’t have thought of going about it this way.  Thanks.

I can see where the transition approach would cause problems (obviously).  I am not really worried the character’s rotation at this point, but that is definitely good to keep in mind.

I appreciate your input.  I may have another question along the way.

Thanks again!

As I assumed I would, I have another question (or questions).  I am using the runtime touch detection. I am setting my character up as a physics body and then attempting to set the linear velocity towards the touch point.  I had similar code working in another programming environment but for the life of me cannot seem to get it working here.  Below is what I have that is clearly wrong.  

Is this the right approach and if so, what am I doing wrong?  If it is the wrong way to go about this, can you point me to some code that does it correctly?

Thanks!

function update( event ) piranhaMovement() end function piranhaMovement () if piranha.x == piranha.targetx and piranha.y == piranha.targety then piranha:setLinearVelocity(0, 0) end end function updatePiranha ( event ) local deltaX = event.x - piranha.x local deltaY = event.y - piranha.y local piranhaDirection = math.atan2(deltaY, deltaX) \* 180 / math.pi piranha.targetx = event.x piranha.targety = event.y piranha:setLinearVelocity( math.cos(1 \* piranhaDirection), math.sin( 1\* piranhaDirection)) end timer.performWithDelay(1, update, -1) Runtime:addEventListener("touch", updatePiranha)

Oops.  I posted this and then immediately afterwards figured out part of the problem.  I was converting the angle to degrees unnecessarily. I also changed the timer.perform function to a runtime event for enter frame. Now, i can’t figure out how to make the character stop once it reaches the touch point.

Any ideas?

function piranhaMovement () if piranha.x == piranha.targetx and piranha.y == piranha.targety then piranha:setLinearVelocity(0, 0) end end function updatePiranha ( event ) local deltaX = event.x - piranha.x local deltaY = event.y - piranha.y local piranhaDirection = math.atan2(deltaY, deltaX) piranha.targetx = event.x piranha.targety = event.y print("piranhaDirection = "..piranhaDirection) print("piranhaDirection as degrees = "..math.deg(piranhaDirection)) piranha:setLinearVelocity( piranha.speed \* math.cos(1 \* piranhaDirection), piranha.speed \* math.sin( 1\* piranhaDirection)) end function update( event ) piranhaMovement() end Runtime:addEventListener("touch", updatePiranha) Runtime:addEventListener("enterFrame", update)

I figured out how to stop the movement, if anyone is interested.  It looks like the actor’s x and y positions would never equal the event x and y positions as the contained fractional information.  Switching over to math.round(actor.x) in my controlling if statement did the trick.