0

I want the object to rotate only on z. To keep x and y and changing z to 0.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Whilefun.FPEKit;

public class PlayAnimation : MonoBehaviour
{
    public List<GameObject> cameras = new List<GameObject>();
    public GameObject head;

    private Animator anim;
    private bool started = true;
    private float animationLenth;
    private bool rotateHead = false;

    // Start is called before the first frame update
    void Start()
    {
        anim = GetComponent<Animator>();
    }

    private void Update()
    {
        if (FPESaveLoadManager.gameStarted == true && started == true)
        {
            FPEInteractionManagerScript.Instance.BeginCutscene();

            anim.enabled = true;
            anim.Play("Stand Up", 0, 0);
            animationLenth = anim.GetCurrentAnimatorStateInfo(0).length;
            StartCoroutine(AnimationEnded());
            started = false;
        }

        if(rotateHead == true)
        {
            head.transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.Euler(transform.rotation.x, transform.rotation.y, 0f), 1.0f * Time.deltaTime);
        }
    }

    IEnumerator AnimationEnded()
    {
        yield return new WaitForSeconds(animationLenth);

        anim.enabled = false;
        FPEInteractionManagerScript.Instance.EndCutscene();
        rotateHead = true;
    }
}

I'm trying to rotate the head. When the animation is end the head rotation is : X = -9.922001 Y = 6.804 Z = 4.167

When the rotation of the head is ending or maybe it's never ending since it's in the update ? The head rotation is : X = -4.529 Y = -9.392 Z = 0.988 Why x and y change and z never get to 0 ?

Another strange thing I saw now the position of the transform on X when the animation is ended is -5.089218e-12 what is this e-12 ?

Daniel Lip
  • 3,867
  • 7
  • 58
  • 120
  • _"what is this e-12 ?"_ We had a similar question about floats a few moments ago, you should check [Is floating point math broken?](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) – Jeroen van Langen Feb 06 '20 at 19:52
  • 1
    This seems to be working fine for the rotation : head.transform.localRotation = Quaternion.Slerp(head.transform.localRotation, Quaternion.Euler(head.transform.localRotation.x, head.transform.localRotation.y, 0f), 1.0f * Time.deltaTime); – Daniel Lip Feb 06 '20 at 20:29
  • 1
    You should use Slerp instead of Lerp. – Leo Bartkus Feb 07 '20 at 04:59

2 Answers2

1

An example of what I said on Musaps answer:

using UnityEngine;

public class ExampleLerp: MonoBehaviour
{
    public float Start = 2.0f;
    public float End = 0.0f;
    public float TimeToTravel = 3.0f;

    private float elapsedTime = 0.0f;
    private float inverseTime;
    // Start is called before the first frame update
    void Start()
    {
      inverseTime = 1.0f/TimeToTravel;
    }

    private void Update()
    {
      float ratio = 0.0f;   
      // Increment our elapsedTime
      elapsedTime += Time.deltaTime;
      if(elapsedTime > TimeToTravel)
      {
        ratio = 1.0f;
      }
      else
      {
        ratio = elapsedTime * inverseTime // Or can be done as elapsedTime/TimeToTravel
      }

      Debug.log("value is: " + Math.Lerp(Start, End, ratio));

    }
}

By using the current roation, and using the same target rotation, and not storing your progress over time, you will see a slowdown as it approaches the end but it will never actually reach the end mathematically.

AresCaelum
  • 1,558
  • 1
  • 13
  • 18
0

First of all, e-12 is 10^-12 or in your case, it is -0.000000000005089218. This occurs maybe because of the float math.

z does not get to 0 because you are using a lerp function without altering the interpolation ratio on the way. Lerp stands for linear interpolation. The third parameter it gets (1.0f * Time.deltaTime in your code) is the interpolation ratio. If this ratio was 0.5, the value of z would jump to the middle value of the difference (which is (0 - 4.167) * 0.5). For example; Lerp(0, 1, 0.5f) makes it jump to 0.5 in the next frame and 0.75 in the other frame.

Let's consider your game runs at 60 frames per second. That makes Time.deltaTime = 1/60. When Lerp starts executing in your code, z is 4.167 in the first frame. You want it to reach zero. The ratio of the interpolation is 1.0f * Time.deltaTime which is 0.01666... or 1/60. That means z will jump to 1/60 of the difference.

In the second frame, z reaches to (4.167 + (0 - 4.167) / 60) = 4.09755 In the third frame, z reaches to (4.09755 + (0 - 4.09755 / 60) = 4.0292575

You can overcome this by testing the z value against a tolerance value.

if (rotateHead)
{
    const float end = 0f;
    var rotation = transform.rotation;
    var z = Mathf.Lerp(rotation.z, end, 1.0f * Time.deltaTime);
    const float tolerance = 1f;
    if (Math.Abs(z - end) < tolerance) z = 0;
    head.transform.rotation = Quaternion.Euler(rotation.x, rotation.y, z);
}
  • Well thats not quite true you can use lerp to make it to zero however using the `x * time.deltaTime)` wont do it... now if he stored the starting position, and the end position and then stored the time it would take to get start to end using a ratio he can hit 0. for example start at 1, going to 0, if it takes 5 seconds to get there, he increments a value by time.deltaTime, then divides that values by 5 to get his ratio, and clamping it, and using the values (1,0,ratio) when ratio hits 1, the position will be 0 or as close as floating point math will let it. – AresCaelum Feb 06 '20 at 23:57
  • @AresCaelum Your implementation does exactly what Mathf.MoveTowards() does. You just add complexity by achieving the same behaviour with another method. – Musap Kahraman Feb 07 '20 at 20:23
  • Reading the documentation tells you it will only move a max each frame, it does this by using a normalized direction, checking the distance between the target position and current position, if the distance is < maxDistanceDelta it will use that distance. otherwise it will move a max of maxDistanceDelta. Completely different approach same results. Also MoveTowards wont work with the quaternion, which is why my example shows a basic way to achieve it with lerp, since movetowards isnt available. – AresCaelum Feb 07 '20 at 23:26
  • But there is a rotateTowards =) – AresCaelum Feb 07 '20 at 23:32
  • The APIs in Unity gives us full freedom to do these kinds of stuff. It doesn't matter if you use Quaternion.RotateTowards or Vector3.RotateTowards or transform.rotation. Our answers are both correct in the means of solving the problem asked. But you have to keep in mind that there is a Lerp method in the API to implement a decelerated movement. What your implementation or MoveTowards or RotateTowards does is moving or rotating at a constant speed. – Musap Kahraman Feb 08 '20 at 00:18
  • Never said your answer was incorrect, I said the statement `z never gets to 0 because you are using a lerp function` isnt quite correct and just gave an example of how you can use lerp to do this. Yes Unity has all sorts of methods and such to do this, and all the methods can be used to to create the same result, however they all work quite differently. I also address the decelerated movement in my answer. – AresCaelum Feb 08 '20 at 00:22
  • No worries! Thanks for talking with me =) – AresCaelum Feb 08 '20 at 00:31