So, I wrote this code where I tell an object that it should keep rotating until it hits 90 degrees, but it keeps on rotating. Anyway here's the code:
public class playerScript : MonoBehaviour
{
public float transformZ;
// Start is called before the first frame update
IEnumerator Start()
{
transformZ = 0;
transform.position = new Vector3 (0, 0, 0);
transform.Rotate(0, 0, transformZ);
while (transformZ != 90)
{
transform.Rotate(0, 0, transformZ);
transformZ = transformZ + 0.1f;
yield return new WaitForSeconds(0.1f);
}
}
Any help would be appreciated!
In your function, you are increasing transformZ by itself + 0.1
every 0.1f
seconds. Instead of this you should just directly use transform.eulerAngles.z
as that provides the exact rotation and you don't need to keep a variable that you increment.
You should not be checking exactly for whether transformZ is not equal to 90, considering this is a float value we are dealing with. There should either be a threshold:
while(Mathf.Abs(90f - transform.eulerAngles.z) < [THRESHOLD])
or you could simply just have the while loop check if its below 90 as Aybe pointed out.
while(transform.eulerAngles.z < 90)
I see various issues here
you increase transformZ
by 0.1
every 0.1
seconds => this will count seconds, not the actually applied rotation (see further below)
you rotate about a value transformZ
that is getting bigger each time. Have in mind that Rotate
does not set a final rotation but rather starts add the current rotation and adds to it.
You are rotating like
Iteration | current rotation | transformZ | resulting rotation 1 | 0 + 0 = 0 2 | 0 + 0.1 = 0.1 3 | 0.1 + 0.2 = 0.3 4 | 0.3 + 0.3 = 0.6 5 | 0.6 + 0.4 = 1.0...
then also in general never use ==
/ ! =
! =
for floating point values
using Rotate
there is always the possibility that you overshoot the target rotation
and then personally I would prefer a continuous rotation instead of 0.1
second jumps.
A solution depends a bit on what you want to control.
For a fixed rotation per second I would do
[SerializeField] private float anglePerSecond;
[SerializeField] private float maxAngle = 90;
IEnumerator Start()
{
...
var initialRotation = transform.rotation;
// precalculate the desired rotation going through Quaternion instead of directly Euler space
var targetRotation = initialRotation * Quaternion.Euler(0, 0, maxAngle);
// here "Quaternion != Quaternion] uses a lower precise check that allows for small rounding errors
while (transform.rotation != targetRotation)
{
// with linear anglePerSecond rotate towards the final rotation
// Without ever overshooting the target rotation
transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, anglePerSecond * Time.deltaTime);
yield return null;
}
// to be sure apply final rotation
transform.rotation = targetRotation;
}
Or if you rather want to control the duration in seconds
[SerializeField] private float durationInSeconds = 1f;
[SerializeField] private float maxAngle = 90;
IEnumerator Start()
{
...
var initialRotation = transform.rotation;
var targetRotation = initialRotation * Quaternion.Euler(0, 0, maxAngle);
// similar as before but this time iterate over a certain time
for(var timePassed = 0f; timePassed < durationInSeconds; timePassed += Time.deltaTime)
{
// factor linear growing from 0 to 1
var factor = timePassed / durationInSeconds;
// advantage: you can add ease in/out quote easily e.g.
//factor = Mathf.SmoothStep(0, 1, factor);
// interpolate via given factor
transform.rotation = Quaternion.Slerp(initialRotation, targetRotation, factor);
yield return null;
}
transform.rotation = targetRotation;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.