I am struggling with an issue in Unity where I am stopping a rigidbody's motion, but after the motion is stopped the rigidbody still moves slightly. It is causing me major issues as I need the object to freeze with the exact position and rotation at the time it was stopped.
I have uploaded a small package where you can see this problem first hand. Any help in identifying the problem and overcoming it would be greatly appreciated.
To see the problem, simply create a new project and import the package. Start the game and press the "spacebar" key to see the issue, pressing the "r" resets the game so you can see it again (without having to restart the game in the editor each time).
As requested here is the code I am using to illustrate this problem:
public class PlayerController : MonoBehaviour{ private Rigidbody rb; void Start() { rb = GetComponent<Rigidbody>(); }} public class TrapController : MonoBehaviour { // Trap data float trapSpeed = 120; float trapRadius = 3; // Player data private PlayerController player; private Rigidbody playerRb; void Start() { player = FindObjectOfType<PlayerController>(); playerRb = player.GetComponent<Rigidbody>(); // Start the trap StartCoroutine(TrapPlayer()); } private void Update() { if (Input.GetKeyDown(KeyCode.Space)) HaltTrap(); } private IEnumerator TrapPlayer() { Vector3 offset; float angle = 0; while (true) { // Force player to move in a circular motion angle += trapSpeed * Time.fixedDeltaTime; offset = new Vector3(Mathf.Cos(angle * Mathf.Deg2Rad), 0, Mathf.Sin(angle * Mathf.Deg2Rad)) * trapRadius; Vector3 position = transform.position + offset; playerRb.MovePosition(position); // Force player to face tangential Vector3 towardsTrap = transform.position - player.transform.position; playerRb.MoveRotation(Quaternion.LookRotation(towardsTrap * 90)); yield return new WaitForFixedUpdate(); } } private void HaltTrap() { // Stop the motion StopAllCoroutines(); playerRb.velocity = Vector3.zero; playerRb.angularVelocity = Vector3.zero; Debug.Log("1. Value when trap halted: " + player.transform.rotation.eulerAngles.y); // Start reporting the angle StartCoroutine(ReportAngle()); } private IEnumerator ReportAngle() { float value = player.transform.rotation.eulerAngles.y; Debug.Log("2. Value at start of Report: " + value); while (true) { float newValue = player.transform.rotation.eulerAngles.y; if (newValue != value) { Debug.Log("---> Value has changed to: " + newValue); value = newValue; } yield return null; } } This is an illustration of what happens when running the code:
It might be hard for you to see but if you look at the console you can see that the angle has changed after stopping it. I have tried toggling isKinematic on and off in the HaltTrap() function. This stops the rotational change from taking place whilst the object is stationary, but as soon as I try to move the position, the rotation changes. Thus, toggling this only seems to delay the change, not prevent it.
