Ball Hitting Corner Where Bricks Touch, Reversing Direction

Hello. I have an issue where the ball will be moving in one direction, bounce off of a flat edge where two bricks meet (but it is also where two corners of box colliders meet), and reverse direction.

In this first image, the ball is moving to the left:

Then it hits an edge between two bricks:

And then it reverses direction, moving to the right:

So, while I was typing this up, it suggested a similar topic, which was about the ball moving through bricks. That’s not the same error, but before posting this, I tried the fix for that problem by making the collision detection on the ball’s rigidbody “Continuous”, and that seems to have solved this problem as well. I’ll still post it, hopefully it will help someone else searching for this issue.

2 Likes

Hello!

I also met this problem and I also tried continuous mode. After that the problem occurs less often but still exists!

Does anyone have any ideas about it?

Here is my workaround of this problem for Unity version 2018 1.1f1.

I just check if there are adjacent bricks when we hit corner and if there any, correct velocity of the ball.

Ball.cs:

public class Ball : MonoBehaviour {

    private Vector2 velocityBeforeCollision;

    private void FixedUpdate()
    { 
        velocityBeforeCollision = GetComponent<Rigidbody2D>().velocity;
    }

    private void OnCollisionEnter2D(Collision2D collision)
    {
        if (collision.collider.GetComponent<Brick>() && hasStarted) {
            CorrectBounceVelocity(collision);
        }
    }

    private void CorrectBounceVelocity(Collision2D collision) {
        ContactPoint2D[] contactPoints = new ContactPoint2D[1];
        collision.GetContacts(contactPoints);
        Vector2 normal = contactPoints[0].normal;
                
        // define points to check neighboring bricks
        Vector2 checkPointRight = new Vector2(contactPoints[0].point.x + .1f, contactPoints[0].point.y);
        Vector2 checkPointLeft = new Vector2(contactPoints[0].point.x - .1f, contactPoints[0].point.y);
        Vector2 checkPointTop = new Vector2(contactPoints[0].point.x, contactPoints[0].point.y + .1f);
        Vector2 checkPointBottom = new Vector2(contactPoints[0].point.x, contactPoints[0].point.y - .1f);

        Collider2D neighborObject;

        // check for each corner of brick
        if (normal.x > 0 && normal.y > 0) // check if we hit top right corner
        {
            // non-orthogonal normal means that we hit corner
            // check if any of 2 adjacent bricks presents
            if (neighborObject = Physics2D.OverlapArea(checkPointRight, checkPointRight))
            {
                if (neighborObject.GetComponent<Brick>()) { // check if it is brick not ball
                    // if there is adjacent brick we correct ball velocity
                    GetComponent<Rigidbody2D>().velocity = new Vector2(velocityBeforeCollision.x, velocityBeforeCollision.y * -1);
                }
            }
            if (neighborObject = Physics2D.OverlapArea(checkPointTop, checkPointTop))
            {
                if (neighborObject.GetComponent<Brick>())
                {
                    GetComponent<Rigidbody2D>().velocity = new Vector2(velocityBeforeCollision.x * -1, velocityBeforeCollision.y);
                }
            }
        }
        else if (normal.x > 0 && normal.y < 0) // and so on for every other corner...
        {
            if (neighborObject = Physics2D.OverlapArea(checkPointRight, checkPointRight))
            {
                if (neighborObject.GetComponent<Brick>())
                {
                    GetComponent<Rigidbody2D>().velocity = new Vector2(velocityBeforeCollision.x, velocityBeforeCollision.y * -1);
                }
            }
            if (neighborObject = Physics2D.OverlapArea(checkPointBottom, checkPointBottom))
            {
                if (neighborObject.GetComponent<Brick>())
                {
                    GetComponent<Rigidbody2D>().velocity = new Vector2(velocityBeforeCollision.x * -1, velocityBeforeCollision.y);
                }
            }
        }
        else if (normal.x < 0 && normal.y > 0)
        {
            if (neighborObject = Physics2D.OverlapArea(checkPointLeft, checkPointLeft))
            {
                if (neighborObject.GetComponent<Brick>())
                {
                    GetComponent<Rigidbody2D>().velocity = new Vector2(velocityBeforeCollision.x, velocityBeforeCollision.y * -1);
                }
            }
            if (neighborObject = Physics2D.OverlapArea(checkPointTop, checkPointTop))
            {
                if (neighborObject.GetComponent<Brick>())
                {
                    GetComponent<Rigidbody2D>().velocity = new Vector2(velocityBeforeCollision.x * -1, velocityBeforeCollision.y);
                }
            }
        }
        else if (normal.x < 0 && normal.y < 0)
        {
            if (neighborObject = Physics2D.OverlapArea(checkPointLeft, checkPointLeft))
            {
                if (neighborObject.GetComponent<Brick>())
                {
                    GetComponent<Rigidbody2D>().velocity = new Vector2(velocityBeforeCollision.x, velocityBeforeCollision.y * -1);
                }
            }
            if (neighborObject = Physics2D.OverlapArea(checkPointBottom, checkPointBottom))
            {
                if (neighborObject.GetComponent<Brick>())
                {
                    GetComponent<Rigidbody2D>().velocity = new Vector2(velocityBeforeCollision.x * -1, velocityBeforeCollision.y);
                }
            }
        }
    }

}

Privacy & Terms