If I have a Rigidbody on my model I must rotate/scale/move it inside FixedUpdate ?

and move it with the rigidbody forces ? or I can move the transform just in the Update ?

If you’re intention is to provide physically natural movement, it is best to use forces. This is done in FixedUpdate(). If this is what you want, I can provide a formula for you on how to calculate the exact forces you need.

If you want to teleport a rigidbody that is normally subject to physics, it is best to set the rigidbody’s transform position, and then the rigidbody’s position afterwards. Believe it or not, I’ve had to do both in order to ensure that the object actually moves there completely. This can be done at any time.

If you want to write your own custom movement entirely, you can make the rigidbody kinematic and then use MovePosition(). This can be done at any time. However, the object will move to the specified position regardless of whether an object is in the way. Also, the rigidbody will not react to forces (i.e. from collisions) that act upon it, but other rigidbodies will react appropriately to it.

Lastly, you may want to use a CharacterController depending on what you’re trying to do.

1 Like

My character (I didn’t make it , I bought it) have this components :

Animator , Rigidbody , Capsule Collider , Third Person User Control , Third Person Character.

I’m using the keys WSAD to control the character movements. and a cinemachine free look camera using the mouse to look around.

Then I have this script on another object that I’m trying to manipulate some rotations and movements on the character(player).

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

public class DetectCollision : MonoBehaviour
{
    public Transform player;
    public Transform target;
    public Text currPosDistanceUiText;
    public bool rotateAutomatic = false;
    public bool turnOnOffPlayerAnimator = false;

    float timeElapsed = 0;
    float lerpDuration = 3;
    float startValue = 1;
    float endValue = 0;
    float valueToLerp = 0;

    private Animator playerAnimator;
    private bool entered = false;
    private bool prevFacing = false;
    private bool stopped = false;
    private bool move = true;
    private bool rot = false;
    private Vector3 currPos;

    // Start is called before the first frame update
    void Start()
    {
        playerAnimator = player.GetComponent<Animator>();

        if (turnOnOffPlayerAnimator)
            playerAnimator.enabled = false;
    }

    // Update is called once per frame
    void Update()
    {
        var currFacing = IsFacing(target);
        if (currFacing != prevFacing)
        {
            // here you switched from facing to not facing or vise verca.
            timeElapsed = 0;
        }
        prevFacing = currFacing;

        var distance = Vector3.Distance(player.position, target.position);

        if (IsFacing(target))
        {
            if (entered && distance > 30 && move)
            {
                if (timeElapsed < lerpDuration)
                {
                    valueToLerp = Mathf.Lerp(startValue, endValue, timeElapsed / lerpDuration);
                    playerAnimator.SetFloat("Forward", valueToLerp);
                    timeElapsed += Time.deltaTime;
                }
                playerAnimator.SetFloat("Forward", valueToLerp);
                stopped = true;
                valueToLerp = 0;
            }

            if (move == false)
            {
                playerAnimator.SetFloat("Forward", 0);
            }

            if (playerAnimator.GetFloat("Forward") == 0 && stopped)
            {
                move = false;
                rot = true;
                currPos = player.position;
             
                Debug.Log("Player current position when valueToLerp value is 0 : " + currPos);
            }
        }
        else
        {
            if (rotateAutomatic == false)
            {
                if (valueToLerp < 0.9f)
                {
                    if (timeElapsed < lerpDuration)
                    {
                        valueToLerp = Mathf.Lerp(endValue, startValue, timeElapsed / lerpDuration);
                        playerAnimator.SetFloat("Forward", valueToLerp);
                        timeElapsed += Time.deltaTime;
                    }
                    playerAnimator.SetFloat("Forward", valueToLerp);
                }
            }

            var dist = Vector3.Distance(player.position, currPos);
            currPosDistanceUiText.text = dist.ToString();
            if (dist > 2)
            {
                move = true;
            }
        }

        if (rotateAutomatic && rot)
        {
            StartCoroutine(ScaleOverSeconds(new Vector3(0.3f,0.3f,0.3f),
                new Vector3(0,90,0), new Vector3(player.localPosition.x + 20,0,0) , 5));
            rot = false;
            //StartCoroutine(AnimateRotationTowards(player, Quaternion.Euler(0, 180, 0), 5f));

            /*player.rotation = Quaternion.Lerp(player.rotation, Quaternion.Euler(0, 180, 0), Time.time * 0.0003f);

            if (timeElapsed < lerpDuration)
            {
                valueToLerp = Mathf.Lerp(endValue, startValue, timeElapsed / lerpDuration);
                playerAnimator.SetFloat("Forward", valueToLerp);
                timeElapsed += Time.deltaTime;
            }
            playerAnimator.SetFloat("Forward", valueToLerp);*/
        }

        if (turnOnOffPlayerAnimator)
        {
            playerAnimator.enabled = false;
        }
        else
        {
            playerAnimator.enabled = true;
        }
    }

    private void OnTriggerEnter(Collider other)
    {
        entered = true;

        Debug.Log("Entered !");
    }

    private void OnTriggerExit(Collider other)
    {
        entered = false;

        Debug.Log("Exited !");
    }

    private bool IsFacing(Transform target)
    {
        Vector3 forward = player.TransformDirection(Vector3.forward);
        Vector3 toTarget = target.position - player.position;
        return Vector3.Dot(forward, toTarget) > 0;
    }

    private System.Collections.IEnumerator AnimateRotationTowards(Transform target, Quaternion rot, float dur)
    {
        rotateAutomatic = true;
        float t = 0f;
        Quaternion start = target.rotation;
        while (t < dur)
        {
            target.rotation = Quaternion.Slerp(start, rot, t / dur);
            yield return null;
            t += Time.deltaTime;
        }
        target.rotation = rot;
    }

    public IEnumerator ScaleOverSeconds(Vector3 scaleTo, Vector3 rotateTo, Vector3 moveTo, float seconds)
    {
        float elapsedTime = 0;
        Vector3 startingScale = player.localScale;
        Vector3 startingRotation = player.localEulerAngles;
        Vector3 startingPosition = player.localPosition;
     
        while (elapsedTime < seconds)
        {
            player.localScale = Vector3.Lerp(startingScale, scaleTo, (elapsedTime / seconds));
            player.localEulerAngles = Vector3.Lerp(startingRotation, rotateTo, (elapsedTime / seconds));
            player.localPosition = Vector3.Lerp(startingPosition, moveTo, (elapsedTime / seconds));

            elapsedTime += Time.deltaTime;
         
            yield return null;
        }
        player.localScale = scaleTo;
        player.localEulerAngles = rotateTo;
        player.localPosition = moveTo;
    } 
}

The script is a bit messed but everything , almost everything is working as I wanted so far.
The problem is with the function : ScaleOverSeconds

It was working fine and smooth when I used the Lerp for scaling and rotating. The player is scaling and rotating at the same time. but then I tried to add also a movement to the player. So the player should scale,rotate,move the same time.

The problem is as soon as I added the move part for the player in this function the player is stuttering. stuttering/shaking when moving and when stopped at the end when it finished moving the player is keep stuttering.

That’s why I asked about the FixedUpdate because the stuttering problem.