Search code examples
c#unity-game-enginephysics

Problems with Vector.Reflect in Unity2D


I am working on a 2D top down project in Unity2D. Hoping to familiarize myself with the Unity physics engine I decided to give the player object physics based movement by applying force to the character. One of the features I was hoping to implement into this movement was a ricochet effect where they player will bounce off of walls on collision.

Currently my script uses Vector2.Reflect to calculate this:

private Rigidbody2D playerRB;

    public float playerSpeed = 0.01f;
    public float playerBounce = 10f;

    // Start is called before the first frame update
    void Start()
    {
        // Fetch components from object.
        playerRB = GetComponent<Rigidbody2D>();
    }

    void FixedUpdate()
    {
        // Process player input
        Vector3 playerInput = new Vector3(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"), 0);
        playerRB.AddForce(playerInput * playerSpeed);

    }
    void OnCollisionEnter2D(Collision2D collision)
    {
        Debug.Log("Collision Detected");

        Vector2 bounceDirection = Vector2.Reflect(playerRB.velocity.normalized, collision.contacts[0].normal).normalized;
        playerRB.AddForce(bounceDirection * playerBounce, ForceMode2D.Impulse);

    }

Unfortunately, my current script is not producing the desired result. When I collide with the wall, nothing happens, the player object doesn't seem to recieve any opposing forces. I suspect the issue could be related to the player object being a square and potentially having multiple collision points against a flat surface. Is there a better way for me to implement this? Would raycasting be a better solution?


Solution

  • The problem is because the collision has already occurred.
    Caching the velocity in FixedUpdate fixes the issue.

    private Vector2 velocity;
    
    void Start()
    {
        playerRB = GetComponent<Rigidbody2D>();
    }
    void FixedUpdate()
    {
        Vector3 playerInput = new Vector3(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"), 0);
        playerRB.AddForce(playerInput * playerSpeed);
    
        velocity = playerRB.velocity;
    }
    void OnCollisionEnter2D(Collision2D collision)
    {
        reflection = Vector2.Reflect(velocity, collision.contacts[0].normal);
        playerRB.AddForce(reflection * playerBounce, ForceMode2D.Impulse);
    }