How to stop Rigidbody on collision in unity

47 Views Asked by At

When my RigidBody collides with Collison object the event is triggered but the object is not always stopped. It depends on the on the speed it has but that for me is not acceptable. I suspect it has something to do with how Update works but i cant get arund that.

this is the code

public class Mover : MonoBehaviour
{
    private Rigidbody _rb;
    private bool _isColliding;
    [SerializeField] private float moveSpeed = 1f;
    
    // Start is called before the first frame update
    void Start()
    {
        _rb = GetComponent<Rigidbody>();
    }

    // Update is called once per frame
    void Update()
    {
        MovePlayer();
    }
    
    void MovePlayer()
    {

        float xValue = Input.GetAxis("Horizontal") * moveSpeed;
        float zValue = Input.GetAxis("Vertical") * moveSpeed;
        
        
        Vector3 movement = new Vector3(xValue, 0f, zValue);
        
        _rb.MovePosition(_rb.position + movement * Time.fixedDeltaTime);

    }

    
    private void OnCollisionEnter(Collision collision)
    {
        _isColliding = true;
        _rb.velocity = Vector3.zero;
        _rb.angularVelocity = Vector3.zero;
    }

}

but when debugging _rb.velocity _rb.angularVelocity seem to already be at zero

What i tried was

  • setting walls to static
  • adding new Physic Material as suggested in older threads
  • i have resized wall collison boxes so that they dont overlap
  • I have set collision detection on rigidBody to Continous
  • tried to catch and handle the event on the "wall" side.
 public class WallHit : MonoBehaviour
{
    private void OnCollisionEnter(Collision collision) 
    {

        if (collision.gameObject.CompareTag("Player"))
        {
            Rigidbody rbdy = collision.gameObject.GetComponent<Rigidbody>();

            rbdy.velocity = Vector3.zero;

            rbdy.angularVelocity = Vector3.zero;
        }
    }

}
  • tried with _rb.isKinematic = true; OnCollisionEnter, but it only slows it down permanently
  • and also tried to handle it with raycast
void Update()
{
    // Check for player input
    if (!IsColliding())
    {
        MovePlayer();
    }
}

bool IsColliding()
{
    // Calculate movement vector based on player input
    float xValue = Input.GetAxis("Horizontal") * moveSpeed;
    float zValue = Input.GetAxis("Vertical") * moveSpeed;
    Vector3 movement = new Vector3(xValue, 0f, zValue);

    // Perform a collision check using a Raycast
    RaycastHit hit;
    if (Physics.Raycast(transform.position, movement, out hit, movement.magnitude * Time.deltaTime))
    {
        // If a collision is detected, return true
        return true;
    }

    // If no collision is detected, return false
    return false;
}

void MovePlayer()
{
    // Move the player
    float xValue = Input.GetAxis("Horizontal") * moveSpeed;
    float zValue = Input.GetAxis("Vertical") * moveSpeed;
    Vector3 movement = new Vector3(xValue, 0f, zValue);
    _rb.MovePosition(_rb.position + movement * Time.fixedDeltaTime);
}

i am runnign out of ideas and i refusing to belive this cannot be handled

2

There are 2 best solutions below

2
Miguel Angel Villarreal torres On BEST ANSWER

It can be difficult to handle collisions at high speeds due to physical timing constraints in Unity3d, so I modified the code so I can set a minimum and maximum speed and the speeds I tested seem to work as intended, so try it for yourself.

    private Rigidbody _rb;

    [SerializeField] private float moveSpeed = 1f;
    [SerializeField] private float maxSpeed = 10f; 

    void Start()
    {
        _rb = GetComponent<Rigidbody>();
    }

    void Update()
    {
        MovePlayer();
    }

    void MovePlayer()
    {
        float xValue = Input.GetAxis("Horizontal") * moveSpeed;
        float zValue = Input.GetAxis("Vertical") * moveSpeed;

        Vector3 movement = new Vector3(xValue, 0f, zValue);

        _rb.AddForce(movement, ForceMode.Acceleration);

        _rb.velocity = Vector3.ClampMagnitude(_rb.velocity, maxSpeed);
    }

    private void OnCollisionEnter(Collision collision)
    {
        if (Vector3.Dot(_rb.velocity.normalized, collision.contacts[0].normal) < -0.5f)
        {
            _rb.velocity = Vector3.zero;
            _rb.angularVelocity = Vector3.zero;
        }
1
Miguel Angel Villarreal torres On

Normalize the motion vector: It is advisable to normalize the motion vector so that the player does not move faster when moving diagonally. You can do this by calling movement.Normalize() after calculating the motion vector If that is not the solution, tell me more about the scene so I can recreate and fix the problem.