# Shortest rotation value [duplicate]

I have a top down game. The player moves the avatar with WASD where W rotates the avator to 180, S rotates to 0, A rotates to 90 and D rotates to 270. I also do diagonal movement so if they hold SA it rotates to 45, WA it rotates to 135, WD it rotates to 225, and SD it rotates to 315.

I smoothly rotate from the current rotation to the hardcoded desired rotation based on those key combo's. Of course what happens is if I'm rotating from anything > 180 to 0 it goes the long way back to 0. So if I'm at 270 rotation and I press S key it sends it back to 0 but that goes from 270 to 0 vs going from 270 to 360 which would result in the same end result but how it got there would be shorter.

I was looking at this (https://answers.unity.com/questions/556480/rotate-the-shortest-way.html) and trying to translate it but it's not working. Below is my translation.

function Script:CalcShortestRot(current, target)
--if current == target then return from end

local dist = target - current + 180
dist = dist - math.floor(dist / 2 / 180) * 2 * 180 - 180

System:Print("Dist = "..dist)

if dist < 0 then
System:Print("Value 1 = "..target - current)
return current - dist
else
System:Print("Value 2 = "..current + target)
return current + dist
end
end


The usage is:

-- determine the model rotation based on direction we are going
if move > 0 then
if strafe > 0 then
self.targetRot = self:CalcShortestRot(self.targetRot, 225)
--self.targetRot = 225
elseif strafe < 0 then
--self.targetRot = 135
self.targetRot = self:CalcShortestRot(self.targetRot, 135)
else
--self.targetRot = 180
self.targetRot = self:CalcShortestRot(self.targetRot, 180)
end
elseif move < 0 then
if strafe > 0 then
--self.targetRot = 315
self.targetRot = self:CalcShortestRot(self.targetRot, 315)
elseif strafe < 0 then
--self.targetRot = 45
self.targetRot = self:CalcShortestRot(self.targetRot, 45)
else
--self.targetRot = 0
self.targetRot = self:CalcShortestRot(self.targetRot, 0)
end
elseif strafe > 0 then
--self.targetRot = 270
self.targetRot = self:CalcShortestRot(self.targetRot, 270)
elseif strafe < 0 then
--self.targetRot = 90
self.targetRot = self:CalcShortestRot(self.targetRot, 90)
end

self.rot = Math:Curve(self.targetRot, self.rot, self.damping)


EDIT: updated my CalcShortestRot() function per comments below but still not working. It spins all around

• You don't need if/else branching — this can be done with a simple formula. If that solves your issue, we can close this as a duplicate. Otherwise, try editing your question to explain if you're having any trouble using this type of formula. – DMGregory Jan 28 '18 at 17:37
• Can't seem to get it to work. I use the following: function Script:CalcShortestRot(from, to) if from == to then return from end local dist = to - from + math.pi dist = dist - math.floor(dist / 2 / math.pi) * 2 * math.pi if dist < 0 then return to - from else return to + from end end – user441521 Jan 28 '18 at 17:47
• Perhaps the issue is that I hardcode the angles to go to when I'm checking based on the keys the player pushes. I do this because I only want 8 angles to be possible to move to.So If the current is at 315 and they press the down key I say go to angle 0 when it really should go to 360 for the shortest but I hardcode 0 angle to be "going south". – user441521 Jan 28 '18 at 17:54
• I had a small mistake in that formula, should be corrected. Also, you work in degrees, not in radians – Bálint Jan 28 '18 at 17:54
• Updated question. Not able to get it to work. – user441521 Jan 28 '18 at 18:04