0

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 Answers 2

1

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;
        }
Sign up to request clarification or add additional context in comments.

2 Comments

This seem to be working, but what is the best way to handle this? because i also found out that moving logic to FixedUpdate also solved this problem somehow, but it is still not clear what the best practice is
The best way is to add a stable minimum and maximum speed. I haven't yet figured out a way to make collisions work 100% at very high speeds and apparently I was searching the Unity forums and a lot of people say that it's hard to get collisions to work at high speeds.
0

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.

1 Comment

Interesting it works, but at the same time now changing the movement speed does not have any affect at all. Its a very simple scene, a plane with 4 walls and a cube as an object

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.