0
\$\begingroup\$

I am developing a basic 2D platformer game to learn the basics of making a game engine and XNA. I have a CollisionHandler class that deals with AABB collisions between the player and the tiles of the map. The player on screen can collide with the tiles but it jitters when there is gravity (the character drops through the number of pixels that is the gravity vector). After dropping through those pixels when the frame refreshes he bounces back to above the block and then drops through again, as though the drawing happens before the position of the player is adjusted after the collision detection. I've narrowed it down to this possibility because without gravity, and while moving left to right, the player stops at a block (collides) but moves through the block at a distance which is the number of pixels that is the velocity while the move key is being pressed and when this key is released he 'snaps' back to where he should be.

This is the Update() function in the main Game class. I've tried different orders of updating the player and the CollisionHandler to no avail.

 protected override void Update(GameTime gameTime)
    {
        if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
            Exit();

        player.Update();
        collisionHandler.Update();
        base.Update(gameTime);
    }

This is the main part that I am struggling with in the Player class. I've also found that if the player is sliding without a key being pressed (there is no deceleration after a button press for now) he stops right on the dot at a block. Right now I've experimented with just collisions on the left side of the player while I sort this issue out.

        public void Update()
    {
        Input();
        Velocity += Gravity;
        Pos = new Vector2(Pos.X + Velocity.X, Pos.Y + Velocity.Y);
        rectangle = new Rectangle(Pos.X, Pos.Y, texture.Width, texture.Height);

    }

    public void Draw(SpriteBatch spriteBatch)
    {
        spriteBatch.Draw(texture, rectangle, Color.White);
    }

    public void Input()
    {
        if (Keyboard.GetState().IsKeyDown(Keys.D))
            Velocity = new Vector2(5, 0);
        else if (Keyboard.GetState().IsKeyDown(Keys.A))
            Velocity = new Vector2(-5, 0);
    }

    public void Collide(Rectangle r2)
    {
        this.Pos = this.Pos + GetLeftCollisionOverlap(r2);
        Velocity = new Vector2(0, 0);
    }

    public Vector2 GetLeftCollisionOverlap(Rectangle r2)
    {
        Rectangle r1 = this.rectangle;
        if (r1.Left < r2.Right)
            return new Vector2(r2.Right - r1.Left, 0);
        else
            return new Vector2(0, 0);
    }

This is the Handler that I am working with to detect collisions.

public class CollisionHandler
{
    private List<CollisionTile> tiles;
    private Player player;

    public CollisionHandler(List<CollisionTile> tiles, Player player)
    {
        this.tiles = tiles;
        this.player = player;
    }

    public void Update()
    {
        foreach(CollisionTile tile in tiles)
        {
            if(IsColliding(player.rectangle, tile.Rect))
            {
                player.Collide(tile.Rect);
            }
        }
    }

    public bool IsColliding(Rectangle r1, Rectangle r2)
    {
        if (!(r1.Right < r2.Left ||
             r1.Left > r2.Right ||
             r1.Top > r2.Bottom ||
             r1.Bottom < r2.Top))
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

Some ideas that I've had to solve this problem are getting collisions before they happen, like a WillCollide method of some sort that prevents movement if there is a collision that will happen in the next frame. The only problem that I've had with this is that the way that the classes are structured I can't get the tile rectangles in the player class, and I'd prefer if the references for tiles and players are in the collision handler only, and leave it the way it is so that the player doesn't 'know' about the existence of any other classes.

Let me know what you think about this problem. I've done quite a bit of searching and haven't found anything that has worked for me.

Thanks - Alex

\$\endgroup\$
1
\$\begingroup\$

I found the problem with this code. In the Player.Collide() I was updating the Pos of the player but not the rectangle/bounding box of this player. When I changed this the code worked as planned!

\$\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.