I have a group of objects and I need to rotate them. Each time I calculate the angle which is between -180…180 degrees.
If I use the command: myGroup:rotate( myAngle )
there is no problem with the correct rotation, whenever angle changes. The best example - a steering wheel. It rotates how you need it, whenever clockwise or counterclockwise.
If I use myGroup.rotation = myAngle
or transition.to( myGroup, { rotation=myAngle, time=500, })
I have a problem, group rotates incorrectly, like it “gets stuck” on a certain angle of a certain position. And if I press on this position it moves clockwise and then counterclockwise, back and forth only, instead of, for example, only clockwise.
So like you handle a steering wheel on top you could rotate in only for180 degrees, then it stocked. Or from the right (left) side of a wheel and rotate only for +/-90 degrees, and then need to rotate it the opposite direction.
I read the API Reference and know that these two methods are not equal. So is there a way to make transition.to with first command?
Are you saying the rotations sometimes go occur in the wrong (unexpected) direction?
I believe that you may be running into a few problems.
Rotations are allowed to take any value, so you should probably normalize them every time before applying a transition.
ssk has a feature for this: ssk.math.normRot( obj ) – Adjust value or rotation to range [0,360) https://roaminggamer.github.io/RGDocs/pages/SSK2/extensions/#math
function player.enterFrame( self )
-- Rotate to face the `targetAngle` at a rate of 180 degrees-per-second
ssk.actions.face( self, { angle = self.targetAngle, rate = 180 } )
end
local obj = <some code to create an object>
obj.targetAngle = 0
obj.enterFrame = enterFrame
listen("enterFrame", obj)
... later you can change the facing angle:
obj.targetAngle = 90 -- Will start turning and face this way automatically
You don’t need to use SSK, just see what I did by looking at the SSK code which does the things I described above.
If your rotate an object 360 degrees and then you rotate it to 180, first it will rotate clockwise but then it will go from 360 to 180 meaning it will rotate counterclockwise.
local function normRot( toNorm )
if( type(toNorm) == "table" ) then
while( toNorm.rotation >= 360 ) do toNorm.rotation = toNorm.rotation - 360 end
while( toNorm.rotation < 0 ) do toNorm.rotation = toNorm.rotation + 360 end
return
else
while( toNorm >= 360 ) do toNorm = toNorm - 360 end
while( toNorm < 0 ) do toNorm = toNorm + 360 end
end
return toNorm
end
0 degrees is up/forward
90 degrees is right
180 degrees is down/backward
270 degrees is left.
For some reason (probably because this is what they did in geometry or some other math class) lots of folks treat 90 degrees as facing forward.
I specifically do not do that because in the context of game making (action games) that does not make sense to me. Since SSK was made for me first… this is just one thing I ask folks to know and adjust to.
Honestly, it’s quite hard to help without seeing some code. For example, the myGroup:rotate() function doesn’t do any transitioning for you, which leads me to believe you are using it in an enterFrame listener, but I can’t be sure. The reason why you are having more success with it than with setting the rotation value might be because the rotate() function adds myAngle to the current rotation, whereas setting the rotation value just sets the rotation of the group to myAngle, so they are doing two different things.
In any case, rotating to face a particular point is a tricky business. You need to account for whether the start rotation is bigger or smaller than the goal rotation and rotate in the appropriate direction. You also need to account for whether the difference between the two rotations is more or less than half a circle (180 degrees), which also affects which direction you need to rotate. The combination leads to four cases that you need to account for:
start rotation is less than end rotation, rotation difference < 180
start rotation is less than end rotation, rotation difference > 180
start rotation is greater than end rotation, rotation difference < 180
start rotation is greater than end rotation, rotation difference > 180
Like I said, tricky. Roaminggamer has offered a lot of help, but I understand that ssk can sometimes seem a bit complicated and overwhelming. Here’s a small sample project that may help you out:
local rect = display.newRect(display.contentCenterX, display.contentCenterY, 10, 1)
rect.anchorX = 0
local function normaliseRotation(r)
while r < 0 do r = r + 360
end
while r > 360 do r = r - 360
end
return r
end
local function rotateRect(e)
rect.rotation = normaliseRotation(rect.rotation)
local startRotation = rect.rotation
local endRotation = normaliseRotation(math.atan2(e.y - rect.y, e.x - rect.x)*180/math.pi)
local angleDiff
if startRotation < endRotation then
if math.abs(startRotation - endRotation) < 180 then angleDiff = endRotation - startRotation
else angleDiff = - (startRotation - endRotation + 360)
end
else
if math.abs(startRotation - endRotation) < 180 then angleDiff = endRotation - startRotation
else angleDiff = math.abs(endRotation + 360 - startRotation)
end
end
transition.to(rect, {rotation = startRotation + angleDiff, time = math.abs(angleDiff*5)})
end
Runtime:addEventListener("tap", rotateRect)
All the code that I had, I already showed - really only three different commands.
Speaking of myGroup.rotation = myAngle
and transition.to( myGroup, { rotation=myAngle, time=500, })
I meant that they working with the same logic, in contrast to command myGroup:rotate( myAngle )
So hasty, If I understood correctly (and I understood correctly because I fix my problem for me):
When myGroup:rotate( myAngle ) is applied to the group, it simply changing the coordinates of its elements. And the group has no parameter “current rotation”.
While myGroup.rotation or transition.to do not change the coordinates of the group, but dynamically rotate it to the desired angle. Therefore, the group has the “current rotation” parameter and for the correct rotation next time, it’s required to take into account the angle at which the group is already rotated.
I fix it like this
local finalRotateAngle = 0 --because group displayed without any rotation
--then any time:
local currentRotateAngle = --calculate it
finalRotateAngle = finalRotateAngle+currentRotateAngle
transition.to( myGroup, { rotation=finalRotateAngle, time=500, })