0
\$\begingroup\$

I have a problem with top-down racing game I'm working on. I need to implement AABB collision with other cars and objects. But when going fast enough, the car can go through thin objects when hitting top and left sides or bottom right corner if the surface is limited with colliders on each side. Here's da codez of collision response:

private void OnCollision(BoundsCollider sender, BoundsCollider collider)
{
    // TODO: question stackexchange gamedev what's wrong with left and top
    // maybe i should compare the center point...
    if (sender.Rect.Left < collider.Rect.Right) // right
    {
        sender.GameObject.Transform.Position += new Vector2(1, 0);
        if (GameObject.IsAI)
        {
            if (collider.GameObject != null)
            {
                Velocity = new Vector2(-collider.GameObject.Rigidbody.Velocity.X, Velocity.Y);
            }
            else
            {
                Velocity = new Vector2(-Velocity.X, Velocity.Y);
            }
            AngularVelocity = 0.01f;
        }
        else
        {
            Velocity = new Vector2(-Velocity.X, Velocity.Y);
        }
    }
    else if (sender.Rect.Right >= collider.Rect.Left) // left (working wrong)
    {
        sender.GameObject.Transform.Position += new Vector2(-1, 0);
        if (GameObject.IsAI)
        {
            if (collider.GameObject != null)
            {
                Velocity = new Vector2(-collider.GameObject.Rigidbody.Velocity.X, Velocity.Y);
            }
            else
            {
                Velocity = new Vector2(-Velocity.X, Velocity.Y);
            }
            AngularVelocity = -0.01f;
        }
        else
        {
            Velocity = new Vector2(-Velocity.X, Velocity.Y);
        }
    }
    if (sender.Rect.Top < collider.Rect.Bottom) // bottom
    {
        sender.GameObject.Transform.Position += new Vector2(0, 1);
        if (GameObject.IsAI)
        {
            if (collider.GameObject != null)
            {
                Velocity = new Vector2(Velocity.X, -collider.GameObject.Rigidbody.Velocity.Y);
            }
            else
            {
                Velocity = new Vector2(Velocity.X, -Velocity.Y);
            }
        }
        else
        {
            Velocity = new Vector2(Velocity.X, -Velocity.Y);
        }
    }
    else if (sender.Rect.Bottom >= collider.Rect.Top) // top (working wrong)
    {
        sender.GameObject.Transform.Position += new Vector2(0, -1);
        if (GameObject.IsAI)
        {
            if (collider.GameObject != null)
            {
                Velocity = new Vector2(Velocity.X, -collider.GameObject.Rigidbody.Velocity.Y);
            }
            else
            {
                Velocity = new Vector2(Velocity.X, -Velocity.Y);
            }
        }
        else
        {
            Velocity = new Vector2(Velocity.X, -Velocity.Y);
        }
    }
}

How do I do it right? If you'll need the whole project, I'll share one with you.

BTW I also use MonoGame.Extended for RectangleF and other stuff

UPD: I've partually fixed it but now you can get out from the corners. How do I fix this? Don't suggest intersection, it doesn't work right (when colliding the wall from left/right, it sends you up and down)

    private void OnCollision(BoundsCollider sender, BoundsCollider collider)
    {
        if (sender.Rect.Center.X > collider.Rect.Center.X) // right
        {
            sender.GameObject.Transform.Position += new Vector2(1, 0);
            if (GameObject.IsAI)
            {
                if (collider.GameObject != null)
                {
                    Velocity = new Vector2(-collider.GameObject.Rigidbody.Velocity.X, Velocity.Y);
                }
                else
                {
                    Velocity = new Vector2(-Velocity.X, Velocity.Y);
                }
                AngularVelocity = 0.01f;
            }
            else
            {
                Velocity = new Vector2(-Velocity.X, Velocity.Y);
            }
        }
        else if (sender.Rect.Center.X < collider.Rect.Center.X) // left
        {
            sender.GameObject.Transform.Position += new Vector2(-1, 0);
            if (GameObject.IsAI)
            {
                if (collider.GameObject != null)
                {
                    Velocity = new Vector2(-collider.GameObject.Rigidbody.Velocity.X, Velocity.Y);
                }
                else
                {
                    Velocity = new Vector2(-Velocity.X, Velocity.Y);
                }
                AngularVelocity = -0.01f;
            }
            else
            {
                Velocity = new Vector2(-Velocity.X, Velocity.Y);
            }
        }
        if (sender.Rect.Center.Y > collider.Rect.Center.Y) // bottom
        {
            sender.GameObject.Transform.Position += new Vector2(0, 1);
            if (GameObject.IsAI)
            {
                if (collider.GameObject != null)
                {
                    Velocity = new Vector2(Velocity.X, -collider.GameObject.Rigidbody.Velocity.Y);
                }
                else
                {
                    Velocity = new Vector2(Velocity.X, -Velocity.Y);
                }
            }
            else
            {
                Velocity = new Vector2(Velocity.X, -Velocity.Y);
            }
        }
        else if (sender.Rect.Center.Y < collider.Rect.Center.Y) // top
        {
            sender.GameObject.Transform.Position += new Vector2(0, -1);
            if (GameObject.IsAI)
            {
                if (collider.GameObject != null)
                {
                    Velocity = new Vector2(Velocity.X, -collider.GameObject.Rigidbody.Velocity.Y);
                }
                else
                {
                    Velocity = new Vector2(Velocity.X, -Velocity.Y);
                }
            }
            else
            {
                Velocity = new Vector2(Velocity.X, -Velocity.Y);
            }
        }
    }
\$\endgroup\$
-1
\$\begingroup\$

I made a solution to precisely detect on which side the object was hit. The previous solution was firing both top and right if object was hit from right and in the upper half.

I use sub-rects from top, bottom, left and right. Then the object is pushed back by width/height intersection between the object's sub-rect and collider's main rect.

But the problem is left and right still work wrong. After a bit of testing various cases (I'd create two 10x10 RectangleFs, one of them is at (0;0) while another one is at (5;0) and write in the VS debug output console. It wrote {X: 0, Y: 0, Width: 0, Height: 10! The width is 0 when it supposed to be 5! It was clearly a Monogame.Extended bug. I've reported it: https://github.com/craftworkgames/MonoGame.Extended/issues/414

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.