I'm trying to have an object oscillate between -45 and 45 degrees, and the following is the code I am using. Note that direction
is initialized to 1, zRotation
to 360, and speed
to 100. This works perfectly fine. However, when I change speed
to 1000, the object does a complete 360 rotation before continuing to oscillate correctly. I'm confused why that happens.
This is my code(inside the Update
method):
zRotation = speed * Time.deltaTime * direction;
var newRotation =
Quaternion.Euler(
new Vector3(
0,
0,
zRotation));
if (zRotation < 315)
direction = 1;
if (zRotation > 405)
direction = -1;
transform.rotation = newRotation;
I am using the values 315(-45 degrees) and 405(45 degrees) because it is easier to determine if my object has reached -45 and 45 degrees this way.
I'm aware that this behavior can easily and more cleanly be achieved using Lerp, but this is for an assignment and we haven't covered Lerp yet, so I don't want to use material that hasn't been taught yet.
CodePudding user response:
The problem is that you do not limit the zRotation
values between your desired values. In the current state of your code you only rely on your computer being fast and having little Time.deltaTime
values (the time elapsed since the last frame).
If you have any kind of hiccup (which happens often in the first couple of frames after starting up), the Time.deltaTime
value is going to be relatively large, resulting in a zRotation
that is so large that it takes longer to return into the [-45...45] range. You can check this by adding a line of
Debug.Log($"Time: {Time.deltaTime} - Rotation: {zRotation}");
to your update method.
This way the following scenario can occur (each line is the log of a frame):
- Time: 0 - Rotation: 360
- Time: 0,02 - Rotation: 380
- Time: 0,02 - Rotation: 420
- Time: 0,333 - Rotation: 733,33
In the last step there was a deltaTime
value that was so big that caused the zRotation
to get loose and go really far from your desired range.
If you limit the rotation values with
zRotation = Mathf.Min(Mathf.Max(zRotation, 315), 405);
You would not go out of the desired range. (Of course you have to update your if statements from <
to <=
or you could leave some kind of threshold in the Min(Max())
part.
I would also advise you use the modulo operator (%
) and initialize the value of zRotation
to 0
so that you don't have to constantly keep track of the 360-minAngle, 360 minAngle values, you could just use the angles in a much easier way and the modulo operator helps you stay in the [-360...360] range.
I updated your code:
public class Rotator : MonoBehaviour
{
private float direction = 1;
private float zRotation = 0; // zRotation initialized to 0 instead of 360
public float speed = 1000;
void Update()
{
zRotation = (speed * Time.deltaTime * direction) % 360; // Use of the modulo operator
zRotation = Mathf.Min(Mathf.Max(zRotation, -45), 45); // Limiting the angles so the object does not 'spin out'
//If you want to see what's going on in the log
Debug.Log($"Time: {Time.deltaTime} - Rotation: {zRotation}");
var newRotation =
Quaternion.Euler(
new Vector3(
0,
0,
zRotation));
if (zRotation <= -45) // LTE because of the limitation to -45
direction = 1;
if (zRotation >= 45) /// GTE because of the limitation to 45
direction = -1;
transform.rotation = newRotation;
}
}