Page 1 of 2

Smoothly rotate to face the cursor

Posted: Tue Dec 17, 2013 8:16 pm
by Jimanzium
I would like a moving objects to gradually rotate towards the mouse. I can get it to move towards the mouse easily, but this is not what I want. I've been trying for a while and just can't seem to get it to work. I would be grateful for any help.

Re: Smoothly rotate to face the cursor

Posted: Tue Dec 17, 2013 8:52 pm
by iPoisonxL
A function like this would work, with radians or whatever.

Code: Select all

function smooth(goal, current, dt)
  local diff = goal - current --checking if there's a different between the goal and the current
  if(diff>dt)then --this means that we still need to speed up
    return current + dt
  end
  if(diff<-dt)then --and this means we need to slow down
    return current - dt
  end
  return goal --if diff equals 0 then just return goal
end
Not too sure, though. Wrote it from memory. This works for velocity, I assume it'd work for rotation somehow.

Re: Smoothly rotate to face the cursor

Posted: Tue Dec 17, 2013 9:55 pm
by micha
iPoisonxL's code is almost correct. One thing is missing, namely the two angles zero and 2pi are the same, even though the two numbers differ a lot. To determine whether to turn left or right, you need calculate diff as follows:

Code: Select all

local diff = (goal-current+math.pi)%(2*math.pi)-math.pi
That way diff is always between -pi and pi.

Re: Smoothly rotate to face the cursor

Posted: Wed Dec 18, 2013 1:14 pm
by Jimanzium
I thank you both for your help, I must have been pretty close as this is very similiar to something I tried doing. I've got it working now so thanks.

Re: Smoothly rotate to face the cursor

Posted: Tue Feb 11, 2014 12:29 am
by iPoisonxL
micha wrote:iPoisonxL's code is almost correct. One thing is missing, namely the two angles zero and 2pi are the same, even though the two numbers differ a lot. To determine whether to turn left or right, you need calculate diff as follows:

Code: Select all

local diff = (goal-current+math.pi)%(2*math.pi)-math.pi
That way diff is always between -pi and pi.
Sorry for bumping a somewhat old post, but could you explain to me how this formula works? It works, but I don't know why. It's really bugging me.

Re: Smoothly rotate to face the cursor

Posted: Tue Feb 11, 2014 10:22 am
by micha
Sure.
Let's say we have the two angles "current" and "goal". We call the number, we get when we subtract them "plain difference" or "pd". It is between -2pi and 2pi (because each angle is between 0 and 2pi). And we call the desired output the "true difference" or "td". This should be a number between -pi and pi.

Have a look at the different possible values of the plain difference and the corresponding true difference.
  • -pi to pi: If the plain difference is in this range, than it coincides with the true difference.
  • pi to 2pi: In this case, the plain difference, is the larger of the two possible angles, between the two rays. We want to find the smaller one. The two add up to the full circle (2pi) and so we get: td = -(2pi - pd). The addition minus before the brackets correct the sign. Turning 270° to the left is the same as turning 90° to the RIGHT. We can reformulate the equation as td = pd - 2pi
  • -2p to -pi: The same reasoning as in the case before: td = pd + 2pi.
In summary: If the plain difference is too small, we add 2pi and if it is too large, we subtract 2pi. The result is always between -pi and pi.

Now for the formula: The modulo-operator "%" does exactly this: If you calculate a%b, then operator adds or subtracts b from a until the result is between 0 and b. Example: 20%7 = 6. 20 is not between 0 and 7, so we subtract: 20-7 = 13. Still not in the range, subtract once again: 13-7 = 6. In the range. Calculation finished.
Another example: -20%7 = 1. -20 is not in the range, so add 7 until you reach the range-> -13,-6,1.

In summary: The modulo-operator gives a result between zero and b and gets the result by adding or subtracting b as often as necessary.

If we now did this:

Code: Select all

td = pd % (2*math.pi)
Then we would get a number between 0 and 2pi. But what we want is a number between -pi and pi (this is the same interval, but shifted by -pi). Thus we first shift the number by pi then do the modulo operator and then subtract pi again.

Code: Select all

td = (pd + math.pi) % (2*math.pi) - math.pi
If this explanation is not clear enough, don't hesitate to ask again. Explaining this without figures is not easy.

Re: Smoothly rotate to face the cursor

Posted: Tue Feb 11, 2014 8:45 pm
by iPoisonxL
This makes sense, thanks a lot.

Re: Smoothly rotate to face the cursor

Posted: Tue Nov 04, 2014 5:19 pm
by RonanZero
Sorry for the bump, but I'm trying to make this work, where did you get 'goal' and 'current' and 'dt' from? Nil values... NIL VALUES EVERYWHERE...

Re: Smoothly rotate to face the cursor

Posted: Tue Nov 04, 2014 8:15 pm
by davisdude
You put that in the top of the code from the first reply in place of the original, I'm assuming, i.e.:

Code: Select all

function smooth(goal, current, dt)
  local diff = (goal-current+math.pi)%(2*math.pi)-math.pi
  if(diff>dt)then --this means that we still need to speed up
    return current + dt
  end
  if(diff<-dt)then --and this means we need to slow down
    return current - dt
  end
  return goal --if diff equals 0 then just return goal
end

Re: Smoothly rotate to face the cursor

Posted: Wed Nov 05, 2014 5:30 pm
by zorg
RonanZero wrote:Sorry for the bump, but I'm trying to make this work, where did you get 'goal' and 'current' and 'dt' from? Nil values... NIL VALUES EVERYWHERE...
Those are parameters. You define them somewhere, and pass them to the function for it to work on.
not gonna give code (yet anyway), but:
goal - should be the angle (orientation) of your object towards your mouse's current position.
current - should be the current angle (orientation) of your object.
dt - a parameter used in love.update, since you should call the above smooth function inside that one, though you can get the value using love.timer.getDelta() elsewhere as well.

finally i am assuming you do have an object (like a table with fields like orientation, position, etc...), or at least an orientation variable to use.