4
\$\begingroup\$

I have been racking my brain trying to figure out a problem I am having with physics and basic AABB collision response. I am fairly close as the physics are mostly right. Gravity feels good and movement is solid. The issue I am running into is that when I land on the test block in my project, I can jump off of it most of the time. If I repeatedly jump in place, I will eventually get stuck one or two pixels below the surface of the test block.

If I try to jump, I can become free of the other block, but it will happen again a few jumps later. I feel like I am missing something really obvious with this. I have two functions that support the detection and function to return a vector for the overlap of the two rectangle bounding boxes. I have a single update method that is processing the physics and collision for the entity.

I feel like I am missing something very simple, like an ordering of the physics vs. collision response handling. Any thoughts or help can be appreciated. I apologize for the format of the code, tis prototype code mostly.

The collision detection function:

public static bool Collides(Rectangle source, Rectangle target)
    {
        if (source.Right < target.Left ||
            source.Bottom < target.Top ||
            source.Left > target.Right ||
            source.Top > target.Bottom)
        {
            return false;
        }

        return true;
    }

The overlap function:

public static Vector2 GetMinimumTranslation(Rectangle source, Rectangle target)
    {
        Vector2 mtd = new Vector2();

        Vector2 amin = source.Min();
        Vector2 amax = source.Max();
        Vector2 bmin = target.Min();
        Vector2 bmax = target.Max();

        float left = (bmin.X - amax.X);
        float right = (bmax.X - amin.X);
        float top = (bmin.Y - amax.Y);
        float bottom = (bmax.Y - amin.Y);

        if (left > 0 || right < 0) return Vector2.Zero;
        if (top > 0 || bottom < 0) return Vector2.Zero;

        if (Math.Abs(left) < right)
            mtd.X = left;
        else
            mtd.X = right;

        if (Math.Abs(top) < bottom)
            mtd.Y = top;
        else
            mtd.Y = bottom;

        // 0 the axis with the largest mtd value.
        if (Math.Abs(mtd.X) < Math.Abs(mtd.Y))
            mtd.Y = 0;
        else
            mtd.X = 0;

        return mtd;
    }

The update routine (gravity = 0.001f, jumpHeight = 0.35f, moveAmount = 0.15f):

public void Update(GameTime gameTime)
    {
        Acceleration.Y = gravity;
        Position += new Vector2((float)(movement * moveAmount * gameTime.ElapsedGameTime.TotalMilliseconds), (float)(Velocity.Y * gameTime.ElapsedGameTime.TotalMilliseconds));
        Velocity.Y += Acceleration.Y;

        Vector2 previousPosition = new Vector2((int)Position.X, (int)Position.Y);

        KeyboardState keyboard = Keyboard.GetState();
        movement = 0;

        if (keyboard.IsKeyDown(Keys.Left))
        {
            movement -= 1;
        }

        if (keyboard.IsKeyDown(Keys.Right))
        {
            movement += 1;
        }



        if (Position.Y + 16 > GameClass.Instance.GraphicsDevice.Viewport.Height)
        {
            Velocity.Y = 0;
            Position = new Vector2(Position.X, GameClass.Instance.GraphicsDevice.Viewport.Height - 16);
            IsOnSurface = true;
        }




        if (Collision.Collides(BoundingBox, GameClass.Instance.block.BoundingBox))
        {
            Vector2 mtd = Collision.GetMinimumTranslation(BoundingBox, GameClass.Instance.block.BoundingBox);

            Position += mtd;

            Velocity.Y = 0;
            IsOnSurface = true;
        }

        if (keyboard.IsKeyDown(Keys.Space) && !previousKeyboard.IsKeyDown(Keys.Space))
        {
            if (IsOnSurface)
            {
                Velocity.Y = -jumpHeight;
                IsOnSurface = false;
            }
        }




        previousKeyboard = keyboard;
    }

This is also a full download to the project. https://www.box.com/s/3rkdtbso3xgfgc2asawy

P.S. I know that I could do this with the XNA Platformer Starter Kit algo, but it has some deep flaws that I am going to try to live without. I'd rather go the route of collision response via an overlay function.

Thanks for any and all insight!

\$\endgroup\$
2
\$\begingroup\$

I have found the solution myself.

Basically, I reordered to have all input, velocity adjustments and position adjustments before the collision detection and response correction. Once I did that, it was able to correct my position appropriately. I had my jump handling at the end of the update, and I think that was interfering with collision response adjustments. I also quit applying gravity unless I wasn't colliding with anything, or if I was colliding, only apply gravity if it wasn't on the Y axis.

I am not jumping about with zero sticking!

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .