Rotate child object between specific Y-rotation values

I’m trying to have my player rotate a certain angle depending on what part of the track he is about to enter (left curve, right curve, or straight) so that he is facing the appropriate direction when inside. I know that having him follow nodes in the sections is a better way to go (i.e. path following), but it looks like its quite expensive for mobile platforms. He is a child of another object and I am using a trigger just before the section of track to carry out the appropriate rotation. Unfortunately, its giving varying results.

Sometimes it will Lerp correctly at the correct Speed specified, and other times it will take much longer. The relevant code is below - any advice would be great. Thanks.

void Update ()
{
    //     Vector3 newPlayerRot = new Vector3(player_obj.transform.rotation.x, CurvedSectionRotAmount, player_obj.transform.rotation.z);
    if (rotateFlag)
    {
        // LEFT
        if (gameObject.tag == "Left_Section")
        {
            Vector3 newPlayerRot = new Vector3(player_obj.transform.rotation.x, -CurvedSectionRotAmount, player_obj.transform.rotation.z);

            Debug.Log("ROTATING LEFT");

            player_obj.transform.localEulerAngles = Vector3.Lerp(player_obj.transform.localEulerAngles, newPlayerRot, Time.deltaTime * Speed);
        }

        // RIGHT
        if (gameObject.tag == "Right_Section")
        {
            Vector3 newPlayerRot = new Vector3(player_obj.transform.rotation.x, CurvedSectionRotAmount, player_obj.transform.rotation.z);

            Debug.Log("ROTATING RIGHT");

            player_obj.transform.localEulerAngles = Vector3.Lerp(player_obj.transform.localEulerAngles, newPlayerRot, Time.deltaTime * Speed);
        }

        // STRIAGHT
        if (gameObject.tag == "Straight_Section")
        {
            Vector3 newPlayerRot = new Vector3(player_obj.transform.rotation.x, 0, player_obj.transform.rotation.z);

            Debug.Log("ROTATING TO STRAIGHT");

            player_obj.transform.localEulerAngles = Vector3.Lerp(player_obj.transform.localEulerAngles, newPlayerRot, Time.deltaTime * Speed);
        }

    }

}

void OnTriggerEnter(Collider col)
{
    if (col.gameObject.tag == "Player_Main_Collider")
    {
        Debug.Log("PLAYER HIT ROTATION COLLIDER");

        rotateFlag = true;
    }

   
}

It is highly likely the issue is with how you are using Lerp(). Lerp’s final parameter takes a value between 0 and 1. So Lerps “intended” use would be to set the beginning parameter and end parameter once and then to change the final parameter between 0 and 1 over time.

Your use of Lerp (and it is code I see posted a lot), does two things. First, it changes the starting point each frame. Second, it use an almost fixed value for the third parameter. deltaTime fluctuates a bit, but is generally similar frame to frame. The result is that at each frame you rotate a almost fixed percentage towards your goal of the remaining rotation. Since the amount left to rotate is shrinking, you get a nice eased rotation. But you are not directly connecting your rotation to a specific time.

Fixes:

  • You might be able to move the code to FixedUpdate and change to using Time.fixedTime. I’ve never played with Lerp and fixedTime. You might also have to factor in different target frame rates of different devices.
  • You can change from Lerp() to MoveTowards(). With MoveTowards() you will be specifying a speed, so you will have to calculate the speed based on the distance in the original rotation.
  • You can create a timer for the last parameter so that the rotation happens in a set amount of time. You’ll need to set the initial and final rotation once at the beginning. Note if you need the easing, you can use Mathf.Sin() in combination with a timer and still be able to specify the time of the rotation.