[TOPIC: topicViewTemplate]
[GLOBAL: userSmallPhoto]

## Using a rotation transition does not work correctly when going from 180 to -180 degrees. Started by infinite.replay Jul 07 2017 02:43 AM

4 replies to this topic
transition rotation rotate degrees angle

Best Answer infinite.replay , 07 July 2017 - 11:18 AM

I have come up with a solution to this issue. It might not be the most elegant solution but seems to work quite well.

Basically i check if the angle that has rotated is greater than 180 degrees which means it won't be taking the shortest route. Then I have an if, else statement which checks if the angle is positive or negative.

If it's negative I set the current rotation of the object to 360 minus the absolute value of the rotation which mimics the number being a positive value greater than 180.

If it's positive I do something similar but with -360 plus the object rotation.

Below is the new onTravel function with the checking in place. Also here is a new gyazo gif showing it working.

https://gyazo.com/8760e99da565b79b93b15202aa37f1b3

```local function onTravel(mouseX, mouseY)
local function Flag()
travelFlag = true
--Fires a bullet in the direction of the player facing
fireBullet()
end
if travelFlag then
local prevAngle = Player.pGroup.rotation
local newAngle = (getImageRotation(Player.pGroup.x, Player.pGroup.y, mouseX, mouseY)) * -1
local difference = math.abs(prevAngle - newAngle)
if difference > 180 then
if Player.pGroup.rotation <= 0 then
Player.pGroup.rotation = 360 - math.abs(Player.pGroup.rotation)
else
Player.pGroup.rotation = -360 + Player.pGroup.rotation
end
end
print("Angle = " .. newAngle)
travelFlag = false
transition.to( Player.pGroup, { time=500, rotation = newAngle, onComplete=Flag } )
end
end```

[TOPIC CONTROLS]
This topic has been archived. This means that you cannot reply to this topic.
[/TOPIC CONTROLS]
[modOptionsDropdown]
[/modOptionsDropdown]
[reputationFilter]
[TOPIC: post.html]
#1

### infinite.replay

[GLOBAL: userInfoPane.html]
infinite.replay
• Observer

• 6 posts
• Corona SDK

Currently there is a player object that rotates on a pivot depending on where you tap on the screen. This works correctly and it will choose the correct angle to transition to.

I have set it so the top half of the players rotational value goes from 0 to -180 and the bottom half 0 to 180. This results in the left side having a jump from 180 to -180, therefore the player object moves all the way around its pivot.

I have also tested it with having the bottom half go from 0 - 180 and then it continues on the top half going from 181 - 360 degrees. This results in the same issue but on the right side where the angle goes from 360 to 0 degrees.

I'm wondering if there is a decent way to fix this problem are it's visually quite annoying. Thanks

I took a gyazo gif screenshot showing a visual example of my problem:

https://gyazo.com/7635a8347758cb4e260be6d4a8021232

Below is my code which is responsible for handling the rotation of the player object. It's a mixture of my own code and bits that I've read from other forum posts.

```local function getImageRotation(x1,y1,x2,y2)
local PI = 3.14159265358
local deltaY = y2 - y1
local deltaX = x2 - x1
local angleInDegrees = (math.atan2( deltaY, deltaX) * 180 / PI) * -1
local mult = 10^0
return math.floor(angleInDegrees * mult + 0.5) / mult
end
-------------------------------------------------
local function onTravel(mouseX, mouseY)
local function Flag()
travelFlag = true
--Fires a bullet in the direction of the player facing
fireBullet()
end
if travelFlag then
local newAngle = (getImageRotation(Player.pGroup.x,Player.pGroup.y,mouseX,mouseY))*-1
print("Angle = " .. newAngle)

travelFlag = false
transition.to( Player.pGroup, { time=500, rotation = newAngle, onComplete=Flag } )
end
end
-------------------------------------------------
local function beginRotate( event )
local phase = event.phase
local t = event.target
if phase == "began" then
onTravel(event.x, event.y)
end
end```

[TOPIC: post.html]
#2

### roaminggamer

[GLOBAL: userInfoPane.html]
roaminggamer
• Corona Geek

• 7,641 posts
• Corona SDK

The trick to solving this is to ensure that:

1. The transition's rotation delta < 180 degree in total
2. The object's rotation is normalized in such a way to ensure the target angle is left or right such that transition travels the shortest distance.

Tip: I've solved this a few times before so it is doable, but I don't have time right now to dig up my solution.
You can solve this  on your own I am sure, or hire a hitman.

Shortest distance examples
1. Current angle 0 desired angle 270 --> transition to angle: -90

2. Current angle -90 desired angle 180 --> transition to angle: -180

3. Current angle -180 desired angle 45 --> Normalized object angle to 180, then transition to angle: 45

Edited by roaminggamer, 07 July 2017 - 08:04 AM.

[TOPIC: post.html]
#3

### anaqim

[GLOBAL: userInfoPane.html]
anaqim
• Contributor

• 770 posts
• Corona SDK

Hi, I had this issue but I think i solved it by making sure both start and stop number was on the same side of 0.

I cant dig up the code right now but remember angles can be anything, 2540 deg if you want, its all a sping on the 360 scale.

[TOPIC: post.html]
#4

### infinite.replay

[GLOBAL: userInfoPane.html]
infinite.replay
• Observer

• 6 posts
• Corona SDK

I have come up with a solution to this issue. It might not be the most elegant solution but seems to work quite well.

Basically i check if the angle that has rotated is greater than 180 degrees which means it won't be taking the shortest route. Then I have an if, else statement which checks if the angle is positive or negative.

If it's negative I set the current rotation of the object to 360 minus the absolute value of the rotation which mimics the number being a positive value greater than 180.

If it's positive I do something similar but with -360 plus the object rotation.

Below is the new onTravel function with the checking in place. Also here is a new gyazo gif showing it working.

https://gyazo.com/8760e99da565b79b93b15202aa37f1b3

```local function onTravel(mouseX, mouseY)
local function Flag()
travelFlag = true
--Fires a bullet in the direction of the player facing
fireBullet()
end
if travelFlag then
local prevAngle = Player.pGroup.rotation
local newAngle = (getImageRotation(Player.pGroup.x, Player.pGroup.y, mouseX, mouseY)) * -1
local difference = math.abs(prevAngle - newAngle)
if difference > 180 then
if Player.pGroup.rotation <= 0 then
Player.pGroup.rotation = 360 - math.abs(Player.pGroup.rotation)
else
Player.pGroup.rotation = -360 + Player.pGroup.rotation
end
end
print("Angle = " .. newAngle)
travelFlag = false
transition.to( Player.pGroup, { time=500, rotation = newAngle, onComplete=Flag } )
end
end```

[TOPIC: post.html]
#5

### roaminggamer

[GLOBAL: userInfoPane.html]
roaminggamer
• Corona Geek

• 7,641 posts
• Corona SDK

Same idea packaged as a function:

```local function shortestPathTransition( obj, targetAngle, dps, myEasing )
targetAngle = targetAngle or 0
local dps = dps or 0
dps = dps/1000 -- degrees per second
local myEasing = myEasing or easing.linear

-- Instant Turn
if(dps < 0 ) then
obj.rotation = targetAngle

-- Timed Turn
else
-- Normalize angles
while( obj.rotation < 0 ) do obj.rotation = obj.rotation + 360 end
while( obj.rotation >= 360 ) do obj.rotation = obj.rotation - 360 end
while( targetAngle < 0 ) do targetAngle = targetAngle + 360 end
while( targetAngle >= 360 ) do targetAngle = obj.rotation - 360 end

-- Stop any prior transitions on this object
transition.cancel( obj )

-- Calc initial tween angle
local tweenAngle = obj.rotation - targetAngle

if(tweenAngle >= 180) then
targetAngle = targetAngle + 360
tweenAngle  = targetAngle - obj.rotation
elseif(tweenAngle <= -180) then
targetAngle = targetAngle - 360
tweenAngle  = targetAngle - obj.rotation
end

-- Calc rotation time
local rotateTime = math.abs(math.floor(tweenAngle / dps))

-- Transition
transition.to( obj, { rotation = targetAngle, time = rotateTime, transition = myEasing } )
end
obj.targetAngle = targetAngle
end

--
-- Test it
--
local arrow = display.newImageRect( "arrow.png", 80, 80 )
arrow.targetAngle = 0
arrow.x = display.contentCenterX
arrow.y = display.contentCenterY

local label = display.newText( "TBD", arrow.x, arrow.y + 200 )

function label.enterFrame( self )
self.text = string.format("Arrow Rotation: %d   Rotation Target: %d", arrow.rotation, arrow.targetAngle)
end

local function test()
local targetAngle = math.random( -360, 360 )
shortestPathTransition( arrow, targetAngle, 360 )
timer.performWithDelay( 1500, test )
end

test()

```

[topic_controls]

[/topic_controls]