Making Sprite Change depending on the Direction it is moving

I have a draggable sprite in my project who’s state I want to change depending on whether it is moving upwards, rightwards, downwards, etc. If it is moving at an angle (upwards and rightwards, for example), I want whichever direction is greater to ‘win out’, meaning if it is moving upwards more than rightwards, it will display the ‘moving upwards state’.

Is there any way to create some sort of code like "if move.y > move.x then display “Player run up”? I’m not much of a coder, so I don’t know how to write this properly. Can anyone help? Peach, maybe?

What additional code do I have to add to the drag/onTouch function below:

local function onTouch( event ) local t = event.target local phase = event.phase if "began" == phase then -- Make target the top-most object local parent = t.parent parent:insert( t ) display.getCurrentStage():setFocus( t ) -- Spurious events can be sent to the target, e.g. the user presses -- elsewhere on the screen and then moves the finger over the target. -- To prevent this, we add this flag. Only when it's true will "move" -- events be sent to the target. t.isFocus = true -- Store initial position t.x0 = event.x - t.x t.y0 = event.y - t.y elseif t.isFocus then if "moved" == phase then -- Make object move (we subtract t.x0,t.y0 so that moves are -- relative to initial grab point, rather than object "snapping"). t.x = event.x - t.x0 t.y = event.y - t.y0 elseif "ended" == phase or "cancelled" == phase then display.getCurrentStage():setFocus( nil ) t.isFocus = false end end -- Important to return true. This tells the system that the event -- should not be propagated to listeners of any objects underneath. return trueend[/code]Thanks very much,Steven [import]uid: 79394 topic_id: 13139 reply_id: 313139[/import]

This is not perfect bu i hope you can tweak it to get the expected result.
[lua]local prevx = 0
local prevy = 0
local function onTouch( event )
local t = event.target

local phase = event.phase
if “began” == phase then
– Make target the top-most object
local parent = t.parent
parent:insert( t )
display.getCurrentStage():setFocus( t )

– Spurious events can be sent to the target, e.g. the user presses
– elsewhere on the screen and then moves the finger over the target.
– To prevent this, we add this flag. Only when it’s true will “move”
– events be sent to the target.
t.isFocus = true

– Store initial position
t.x0 = event.x - t.x
t.y0 = event.y - t.y
prevx = event.x
prevy = event.y
elseif t.isFocus then
if “moved” == phase then
– Make object move (we subtract t.x0,t.y0 so that moves are
– relative to initial grab point, rather than object “snapping”).
t.x = event.x - t.x0
t.y = event.y - t.y0

if event.x > prevx then
if event.y > prevy then
print(“Bottom Right”)
elseif event.y < prevy then
print(“Top Right”)
else
print(“Moving Right”)
end
else
if event.y > prevy then
print(“Bottom Left”)
elseif event.y < prevy then
print(“Top Left”)
else
print(“Moving Left”)
end
end
if event.x > prevx + 10 then
prevx = event.x
end
if event.y > prevy + 10 then
prevy = event.y
end

elseif “ended” == phase or “cancelled” == phase then
display.getCurrentStage():setFocus( nil )
t.isFocus = false
end
end

– Important to return true. This tells the system that the event
– should not be propagated to listeners of any objects underneath.
return true
end

local img = display.newImage(“ball.png”,100,100)
img:addEventListener(“touch”,onTouch)[/lua] [import]uid: 71210 topic_id: 13139 reply_id: 48247[/import]

Thanks for replying. I’m trying to wrap my head around the prevx and prevy variables you are using. I’m guessing they are meant to describe the object’s previous coordinates (hence the prev?). If I am wrong, please correct me.

I can’t really tell if your code is working as intended or not, as the messages the output panel is delivering don’t seem consistent with the changes in the object’s direction. Sometimes I’ll move the object upwards and downwards, then in a circle, and the output panel’s messages will not change. Other times they will seem much more reactive to changes in direction.

I’m very eager to tweak and experiment with the code you’ve provided, but I’d like to understand it a bit more before proceeding.

I’m not sure if this will help, but perhaps using the simplest of code as a starting point would make things clearer? Like having the circle in the following tutorial code change color depending on which direction it was moving in? Like red if moving in the upwards direction, green if moving downwards, etc?

local circle = display.newCircle(50, 50, 100)circle:setFillColor(255,255,255)function moveCircle( event ) circle.x = event.x circle.y = event.yendRuntime:addEventListener("touch", moveCircle)[/code]If this isn't a good idea, I apologize. I really would like to understand your code better. Thanks. [import]uid: 79394 topic_id: 13139 reply_id: 48269[/import]

This is the code if you just have right and left movement.
[lua]local prevx = 0
local prevy = 0
local circle = display.newCircle(100, 100, 50)

local function onTouch( event )
local t = event.target

local phase = event.phase
if “began” == phase then
– Make target the top-most object
local parent = t.parent
parent:insert( t )
display.getCurrentStage():setFocus( t )
t.isFocus = true

– Store initial position
t.x0 = event.x - t.x
t.y0 = event.y - t.y
prevx = event.x
prevy = event.y
elseif t.isFocus then
if “moved” == phase then
t.x = event.x - t.x0
t.y = event.y - t.y0

if event.x > prevx then --moving right
circle:setFillColor(255,0,0) – Right
else
circle:setFillColor(0,255,0) – Left
end

if event.x > prevx + 10 or event.x < prevx - 10 then
prevx = event.x
end
if event.y > prevy + 10 or event.y < prevy - 10 then
prevy = event.y
end

elseif “ended” == phase or “cancelled” == phase then
display.getCurrentStage():setFocus( nil )
t.isFocus = false
end
end
return true
end

circle:addEventListener(“touch”, onTouch)[/lua] [import]uid: 71210 topic_id: 13139 reply_id: 48279[/import]

if you want to get all the direction we may need to do some math. give me an hours time let me see whether I can get u a solution.
:slight_smile: [import]uid: 71210 topic_id: 13139 reply_id: 48280[/import]

Hope this will help. this code returns the direction with better precision.
[lua]–to store previous position of x and y
local prevx = 0
local prevy = 0

local circle = display.newCircle(250, 250, 50)
– text to display direction
local directionTXT = display.newText("direction: ",50,50,nil,25)

local function onTouch( event )
local t = event.target
local phase = event.phase
if “began” == phase then
– Make target the top-most object
local parent = t.parent
parent:insert( t )
display.getCurrentStage():setFocus( t )
t.isFocus = true

– Store initial position
t.x0 = event.x - t.x
t.y0 = event.y - t.y
prevx = event.x
prevy = event.y
elseif t.isFocus then
if “moved” == phase then
t.x = event.x - t.x0
t.y = event.y - t.y0

local dx = prevx - event.x
local dy = prevy - event.y
local distance = dx * dx + dy * dy
if distance>400 then
local angle = math.atan2(dy,dx) * 57.2957795
local string_dir
if angle>=22*-1 and angle<23 then
string_dir=“Left”
elseif angle>=23 and angle<68 then
string_dir=“Up Left”
elseif angle>=68 and angle<113 then
string_dir=“Up”
elseif angle>=113 and angle<158 then
string_dir=“Up Right”
elseif angle>=135 or angle<157*-1 then
string_dir=“Right”
elseif angle>=157*-1 and angle<112*-1 then
string_dir=“Down Right”
elseif angle>=112*-1 and angle<67*-1 then
string_dir=“Down”;
elseif angle>=67*-1 and angle<22*-1 then
string_dir=“Down Left”
end
prevx=event.x
prevy=event.y
directionTXT.text = "Direction : "…string_dir
end
end
end
return true
end

circle:addEventListener(“touch”, onTouch)[/lua] [import]uid: 71210 topic_id: 13139 reply_id: 48281[/import]

Hi Technowand,

Now this looks like something I can work with! I’m going to see if I can work it into my existing code, but I can’t see any potential problems at this point, as your code is so clean. That being said… thank you so much for your help! If you ever need a testimonial written, let me know:) [import]uid: 79394 topic_id: 13139 reply_id: 48469[/import]

Hi Technowand,

I inserted your code suggestion into my project last week and it works great. Now I want to take things one step further and add a stop state to my draggable object. The only problem is, I can’t figure out how to write a conditional statement that detects when the draggable object has paused mid-drag (i.e. stopped moving). I’ve been trying to add a “Stopped Moving Left” Direction to the circle example above, but so far no luck. I’m sure I could figure it out, but right now I’m having trouble understanding exactly how your code is working, in particular the function of the prevx and prevy variables (are they supposed to represent the previous x and y positions of the object?). Any help or additional explanation would be much appreciated.

Thank you!
Steven
[import]uid: 79394 topic_id: 13139 reply_id: 49341[/import]

Good to know that it worked.
prevx and prevy variables are previous x and y positions of the object.

for displaying Stopped Moving Left, I can’t find a reason to do that. say, if your object is moving left you will be loading a particular sprite sequence. once the movement is stopped you just have to stop the sequence playing and the object will still be faced towards that side right ?

and what did you mean by “draggable object has paused mid-drag” is it stopped moving without lifting finger or finger lifted ? if finger lifted you can code it in event.phase = “ended”.

one thing you should understand here is that the touch event is called even for slight movement of the finger. so its not always like once you paused moving its still and the event is not triggered.
[import]uid: 71210 topic_id: 13139 reply_id: 49366[/import]

Hi Technowand,

Thanks for getting back to me. Yes, when I said “paused mid-drag” I meant “stopped moving without lifting finger”.

A quick explanation should make clear what I’m after: My draggable object is an animated sprite (a running man) that has four different run animations (left, right, up ,down), along with four corresponding static poses (for when the man has stopped moving in each of the four directions). The way I have it now, when the user has stopped dragging the sprite around, but still has his/her finger on it, the run animation keeps on playing (even though there is no movement), and it looks wrong. I need the system to be instructed to play the static pose when there is no movement, rather than stopping the animation (this also would look funny).

Is it a simple operation to sense when movement has stopped (You mentioned “(I) just have to stop the sequence playing… once the movement is stopped”)?. If so, this is the trigger I need to make the static poses kick in.

I wish it was as easy as playing the static poses during the event.phase=“ended”, but my particular project involves the player dragging the sprite around (without lifting his/her finger off it) for pretty much the duration of the whole game.

I hope I’m explaining myself clearly. If not, please let me know and I’ll try again!

[import]uid: 79394 topic_id: 13139 reply_id: 49388[/import]

yeap… you explained it clearly… :slight_smile: let me think about how it can be done… will get back to you once something clicks… [import]uid: 71210 topic_id: 13139 reply_id: 49390[/import]

Much appreciated, I’m gonna analyze your previous code example and try and come up with some sort of idea too… I’m thinking maybe the key might be in the prevx/prevy variables, but god knows if I’m on the right track! :slight_smile: [import]uid: 79394 topic_id: 13139 reply_id: 49391[/import]

hope this will help you
[lua]–to store previous position of x and y
local prevx = 0
local prevy = 0

local circle = display.newCircle(250, 250, 50)
– text to display direction
local directionTXT = display.newText("direction: ",50,50,nil,25)
local flag = 0
local moved = 0
local string_dir =’’
local function onTouch( event )
local t = event.target
local phase = event.phase
if “began” == phase then
– Make target the top-most object
local parent = t.parent
parent:insert( t )
display.getCurrentStage():setFocus( t )
t.isFocus = true

– Store initial position
t.x0 = event.x - t.x
t.y0 = event.y - t.y
prevx = event.x
prevy = event.y

elseif t.isFocus then
if “moved” == phase then
flag = 1
t.x = event.x - t.x0
t.y = event.y - t.y0

local dx = prevx - event.x
local dy = prevy - event.y
local distance = dx * dx + dy * dy
if distance>400 then
local angle = math.atan2(dy,dx) * 57.2957795
if angle>=22*-1 and angle<23 then
string_dir=“Left”
elseif angle>=23 and angle<68 then
string_dir=“Up Left”
elseif angle>=68 and angle<113 then
string_dir=“Up”
elseif angle>=113 and angle<158 then
string_dir=“Up Right”
elseif angle>=135 or angle<157*-1 then
string_dir=“Right”
elseif angle>=157*-1 and angle<112*-1 then
string_dir=“Down Right”
elseif angle>=112*-1 and angle<67*-1 then
string_dir=“Down”;
elseif angle>=67*-1 and angle<22*-1 then
string_dir=“Down Left”
end
prevx=event.x
prevy=event.y
directionTXT.text = "Direction : "…string_dir
moved = moved + 1
end
else if “ended” == phase then
flag = 0
end
end
end
return true
end

local prevMoved = 0
local function movementTracker(event)
if flag == 0 then return true end
if prevMoved == moved then
print("not moving and last movement was towards "…string_dir)
flag = 0
end
prevMoved = moved
end

circle:addEventListener(“touch”, onTouch)
Runtime:addEventListener(“enterFrame”, movementTracker)[/lua] [import]uid: 71210 topic_id: 13139 reply_id: 49399[/import]

Hi Technowand,

I just tried your code in the simulator, but the “not moving…” text was only being printed out when the circle object was in motion, unfortunately. If you could explain the rough theory behind what you’re trying to do, I may be able to run with what you’ve given so far, just a thought. [import]uid: 79394 topic_id: 13139 reply_id: 49413[/import]

Hi Technowand,

Do you think using a timer, getting the object’s x and y coordinates after a millisecond delay, comparing them to the object’s current x and y coordinates, and seeing if they match up would work? Just an idea. [import]uid: 79394 topic_id: 13139 reply_id: 49414[/import]

if you remove flag = 0 from movementTracker() function you will keep on getting the message when you keep the finger touched without moving.

but we want this to happen only once else if you put a code to set the sprite to an image inside this function that code will be executed many number of time and it will be an overhead. so in the above code once you set the sprite to that particular image it won’t change unless you move your finger.

now I will explain how its coded…
in the above code I put a variable moved to track a movement then inside a enterFrame event i check its value with its previous value. if it din’t change it means that the touch is not moving.
am also using a variable called flag to do the above checking when the touch is in moved phase. that means before touching or after touch ended this event will just return with out doing anything.
I also want this event to do nothing if the finger is just kept without moving. thats why i have included flag = 0 inside the event.

hope its clear now.
[import]uid: 71210 topic_id: 13139 reply_id: 49415[/import]

Yeap using a timer will also do the job. [import]uid: 71210 topic_id: 13139 reply_id: 49416[/import]

Hi Technowand,

Crystal clear. I recently learned about flagging to avoid my run animations constantly being told to play, so I should be able to figure out how to flag your code so it works as intended. Thank you so much for it, your concise explanations, as well as your prompt replies.

Cheers,
Steven [import]uid: 79394 topic_id: 13139 reply_id: 49423[/import]

You are welcome… :slight_smile:

Renjith
[import]uid: 71210 topic_id: 13139 reply_id: 49425[/import]

@technowand
You’re the forums own code generator, I bet we could easily make a game from all your posts…

Great to have such a code wizard on the same boat, great job. [import]uid: 13560 topic_id: 13139 reply_id: 49445[/import]