Hi, I’m currently working on a puzzle game, the part where I’m struggling - a cog which you can rotate. It’s a 3d model and upon clicking on the left side it should rotate counter-clockwise by 40 degrees, opposite on the right side. Anyway the rotation happens on the y-axis, it all works fine until the y rotation goes into negative angles (-40) in that case instead of rotating to the left it rotates back to 0. Here’s the code in the Move method called by Update :
StartCoroutine(RotateGearA(Vector3.right * 40, 1));
And the coroutine here:
IEnumerator RotateGearA(Vector3 byAngles, float inTime) {
isMoving = true;
var fromAngle = cogA.transform.rotation;
var toAngle = Quaternion.Euler(cogA.transform.eulerAngles + byAngles);
for(var t = 0f; t < 1; t += Time.deltaTime/inTime) {
cogA.transform.rotation = Quaternion.Lerp(fromAngle, toAngle, t);
yield return null;
}
}
I’m not sure whether I should implement an if-else statement in the Move() method to handle the edge cases or if there’s another approach?
PS. If it helps that coroutine is from my previous project where the cogs were 2D sprites, it worked fine there
Euler angles are pretty terrible to work with because it’s not mathematically possible to reliably convert a Quaternion to a single set of Euler angles. So the conversion algorithm has to choose which of the possible conversions to use, and as the rotation changes this is not consistent. So you’ll get random jumps here and there. Further reading.
You can avoid these problems by either:
A) storing your rotation as a Vector3 on your own, using Quaternion.Euler as a one-way street (i.e. never convert a Quaternion to Euler angles);
B) use Quaternion math exclusively
C) for something like this, don’t bother with coding rotations at all; just make a rotation animation, and trigger that animation in script.
Thanks for the info, it appears I fixed it by using the Quaternion operator *
IEnumerator RotateGearA(Vector3 byAngles, float inTime) {
isMoving = true;
var fromAngle = cogA.transform.rotation;
// var toAngle = Quaternion.Euler(cogA.transform.eulerAngles + byAngles);
var toAngle = fromAngle * Quaternion.Euler(byAngles);
for(var t = 0f; t < 1; t += Time.deltaTime/inTime) {
cogA.transform.rotation = Quaternion.Lerp(fromAngle, toAngle, t);
yield return null;
}
}
But for the future I’ll stay away from these evil euler angles 
The important thing is to always avoid Quaternion → Euler conversion, and your new code does avoid that. There’s no problem converting Euler to Quaternion.
2 Likes