don't know to make smooth rotation

I’m making a Mario Kart clone and I’m trying to make a script so when you get stuck sideways you smoothly rise and rotate to 0 in the z axis, but I can’t make it work, the character just go to the rotation and go like less than half of the desired. If someone can help me I appreciate

using UnityEngine;

public class rightDetect : MonoBehaviour
{
  public float torque;
  public float force;
  public GameObject kart;
  public Rigidbody kRb;


  void OnTriggerEnter(Collider other)
  {
  if (other.tag == "ground")
  {
  Invoke("up", 2.0f);
  Invoke("fixRot", 3.0f);
  Invoke("rbAct", 10.0f);
  }
  }

  void up()
  {
  kRb.useGravity = false;
  kRb.isKinematic = true;
  kRb.detectCollisions = false;

  kart.transform.Translate(Vector3.left * force * Time.deltaTime);
  }

  void fixRot()
  {
  kart.transform.Rotate(0, 0, torque * Time.deltaTime);
  }

  void rbAct()
  {
  kRb.useGravity = true;
  kRb.isKinematic = false;
  kRb.detectCollisions = true;
  }
}

To do anything over a period of time you’re going to need coroutines, or else track the per-frame changes yourself.

In the above code everything I see executes instantly, after the invoke delay, during which time it does nothing.

You want to stick all three of those steps into a single linear coroutine separated by any delays you want, and make them iterate through loops (yielding null) to smoothly fix things up.

And how could I use this in my case?

Look into coroutines. Generally you would have a single coroutine with three separate sequential loops in it.

Each loop might look like this:

const float Interval1 = 2.0f;

for (float t = 0; t < Interval1; t += Time.deltaTime)
{
  float fraction = t / Interval1;

  // put code here to gently rotate your ship from its tipped position back to upright
  // I created the 'fraction' variable above because it is easy to use it
  // with either Quaternion.Lerp to smoothly turn you from one rotation to another,
  // or to use it with Vector3.Lerp for translation (smooth movement)

  // set the rotation here after calculating it with Quaternion.Lerp and 'fraction'

  yield return null;   // gotta have this so it waits until the next frame
}

Edit: and in your case you would set the RB to IsKinematic at the start of your coroutine, and at the end you would put it back to not Kinematic to let the physics resume.

1 Like

I don’t know where to put this in my code. Where does it go?

It does NOT go into your code. This forum is not for me to write your code. This forum is to help you learn!

Steps to integrate above:

  1. Look into coroutines, learn them, love them, they are an (almost) essential part of Unity3D development.

  2. Optionally use the suggestion above framework / approach to implement your smooth rotation… or… roll it yourself.

ok, so I read this post and think I learned something, now the kart goes smooth up if it gets stuck, but I don’t know how to make it rotate 90 degrees to left. I have this at the moment:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class rightDetect : MonoBehaviour
{
    public float speed;

    public Vector3 directionUp;
    public Vector3 rotDir;

    public Rigidbody kRb;
    public GameObject kart;

    void Start()
    {  
        directionUp = new Vector3(0, 0.1f, 0);
    }

    void OnTriggerEnter(Collider other)
    {
        if (other.tag == "ground")
        {
            Invoke("kRbUn", 3.0f);
            Invoke("StCour", 5.5f);
            Invoke("kRbAct", 7.0f);
        }
    }

    IEnumerator smoothMove(Vector3 direction, float speed)
    {
        float startTime = Time.time;
        Vector3 starPos = kart.transform.position;
        Vector3 endPos = kart.transform.position + direction;

        while (starPos != endPos && ((Time.time - startTime) * speed) < 1.0f)
        {
            float move = Mathf.Lerp(0, 1, (Time.time - startTime) * speed);

            kart.transform.position += direction * move;

            yield return null;
        }
    }

    IEnumerator smoothRot(Vector3 direction, float speed)
    {
        float startTime = Time.time;
        Vector3 startRot = //don't know what to do here
        Vector3 endRot = //and here

        while (startRot != endRot && ((Time.time - startTime) * speed) < 1.0f)
        {
            yield return null;
        }
    }

    void kRbUn()
    {
        kRb.isKinematic = true;
        kRb.useGravity = false;
    }

    void kRbAct()
    {
        kRb.isKinematic = false;
        kRb.useGravity = true;
    }

    void StCour()
    {
        StartCoroutine(smoothMove(directionUp, 1.0f));
    }
}

ok, so I have edited another one and now it’s working exactly like I wanted

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class rightDetect : MonoBehaviour
{
    public float speed;

    public Vector3 directionUp;
    public Vector3 rotDir;

    public Rigidbody kRb;
    public GameObject kart;

    void Start()
    {  
        directionUp = new Vector3 (0, 0.07f, 0);
        rotDir = new Vector3 (0, 0.1f, 0);
    }

    void OnTriggerEnter(Collider other)
    {
        if (other.tag == "ground")
        {
            Invoke("kRbUn", 2.0f);
            Invoke("StCourMv", 5.5f);
            Invoke("StCourRot", 6.5f);
            Invoke("kRbAct", 7.0f);
        }
    }

    IEnumerator smoothMove(Vector3 direction, float speed)
    {
        float startTime = Time.time;
        Vector3 starPos = kart.transform.position;
        Vector3 endPos = kart.transform.position + direction;

        while (starPos != endPos && ((Time.time - startTime) * speed) < 1.0f)
        {
            float move = Mathf.Lerp(0, 0.7f, (Time.time - startTime) * speed);

            kart.transform.position += direction * move;

            yield return null;
        }
    }

    IEnumerator smoothRot(Vector3 axis, float angle, float duration = 1.0f)
    {
        Quaternion from = transform.rotation;
        Quaternion to = transform.rotation;
        to *= Quaternion.Euler(kart.transform.forward * 90);

        float elapsed = 0.0f;

        while (elapsed < duration)
        {
            kart.transform.rotation = Quaternion.Slerp(from, to, elapsed / duration);
            elapsed += Time.deltaTime;
            yield return null;
        }
        transform.rotation = to;
        yield return null;
    }

    void kRbUn()
    {
        kRb.isKinematic = true;
        kRb.useGravity = false;
    }

    void kRbAct()
    {
        kRb.isKinematic = false;
        kRb.useGravity = true;
    }

    void StCourMv()
    {
        StartCoroutine(smoothMove(directionUp, 1.0f));
    }

    void StCourRot()
    {
        StartCoroutine(smoothRot(rotDir, 1.0f));
    }
}

now I just need to invert the rotation to -90 and add this in the left stuck detector and adapt this to the up one. Thanks for all your help.

1 Like

Be careful comparing two Vector3 objects (or any floating point objects) for equality. They may never be equal and can go past each other just barely missing each other thanks to floating point inaccuracy.

But if you have it working, awesome!

today I discovered that if I rotate in y axis it rise and rotate to be 0 in y axis and have to rotate again to make what I want instead of just rotating in z axis, do you know what can I change here?

thanks in advance (I think its this way that write, english is not my native language)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class leftDetect : MonoBehaviour
{
    public float speed;

    public Vector3 directionUp;
    public Vector3 rotDir;

    public Rigidbody kRb;
    public GameObject kart;

    void Start()
    {
        directionUp = new Vector3(0, 0.07f, 0);
        rotDir = new Vector3(0, 0.1f, 0);
    }

    void OnTriggerEnter(Collider other)
    {
        if (other.tag == "ground")
        {
            kart.GetComponent<Movement>().enabled = false;

            Invoke("kRbUn", 1.5f);
            Invoke("StCourMv", 3.0f);
            Invoke("StCourRot", 4.0f);
            Invoke("kRbAct", 5.0f);
            Invoke("moveAct", 6.0f);
        }
    }

    IEnumerator smoothMove(Vector3 direction, float speed)
    {
        float startTime = Time.time;
        Vector3 starPos = kart.transform.position;
        Vector3 endPos = kart.transform.position + direction;

        while (starPos != endPos && ((Time.time - startTime) * speed) < 1.0f)
        {
            float move = Mathf.Lerp(0, 0.7f, (Time.time - startTime) * speed);

            kart.transform.position += direction * move;

            yield return null;
        }
    }

    IEnumerator smoothRot(Vector3 axis, float angle, float duration = 1.0f)
    {
        Quaternion from = transform.rotation;
        Quaternion to = transform.rotation;
        to *= Quaternion.Euler(kart.transform.forward * -90);

        float elapsed = 0.0f;

        while (elapsed < duration)
        {
            kart.transform.rotation = Quaternion.Slerp(from, to, elapsed / duration);
            elapsed += Time.deltaTime;
            yield return null;
        }
        transform.rotation = to;
        yield return null;
    }

    void kRbUn()
    {
        kRb.isKinematic = true;
        kRb.useGravity = false;
    }

    void kRbAct()
    {
        kRb.isKinematic = false;
        kRb.useGravity = true;

        kart.GetComponent<Movement>().enabled = true;
    }

    void StCourMv()
    {
        StartCoroutine(smoothMove(directionUp, 1.0f));
    }

    void StCourRot()
    {
        StartCoroutine(smoothRot(rotDir, 1.0f));
    }


    void moveAct()
    {
        kart.GetComponent<Movement>().enabled = true;
    }
}