0

I'm makeing a simple 2d tile based RPG-game using XNA. I've made a simple tile map with a list of Tile objects that contain a rectangle for each tile. My movement update for the player first creates a rectangle representing the player in the next frame. Then it runs a foreach loop to check every tile in the tile list if it intersects with the player rectangle. If it does, it sets collided boolean to true and also remembers with tile the player would collide with.

If the player will collide, it sets the player position so the player touches the tile insead of going into it. The problem i have is that it's not possible to "slide" against a wall of tiles. For example, if i move down and left at the same time, as soon as i hit a tile the player gets stuck insted if continue moving to the left. Do you have any ideas how i could improve the method so it acts correcly, no matter how i move?

public void MovementUpdate(KeyboardState ks, GameTime time, List<Tile> tlist)
    {
        Direction = Vector2.Zero;
        Rectangle nextPosRec;

        if (ks.IsKeyDown(Keys.Right)){
            Direction.X = MOVE_RIGHT;
        }

        if (ks.IsKeyDown(Keys.Down))
        {
            Direction.Y = MOVE_DOWN;
        }

        if (ks.IsKeyDown(Keys.Up))
        {
            Direction.Y = MOVE_UP;
        }

        if (ks.IsKeyDown(Keys.Left)){
            Direction.X = MOVE_LEFT;
        }

        Vector2 nextPos = Position ;
        nextPos += Direction * Speed * (float)time.ElapsedGameTime.TotalSeconds;
        nextPosRec = new Rectangle((int)nextPos.X, (int)nextPos.Y, 32, 32);

        bool colide = false;
        Tile ctile = new Tile(playerTexture, Position, 0);

        foreach (Tile t in tlist)
        {
            if (t.tileRectangle.Intersects(nextPosRec))
            {
                colide = true;
                ctile = t;
            }
        }

        if (colide == false)
        {
            Position = nextPos;
        }
        else
        {
            if (Position.Y < ctile.tileRectangle.Top - 32)
            {
                //COLLIDE TOP
                Position.Y = ctile.tileRectangle.Top - 32;
            }

            if(Position.Y > ctile.tileRectangle.Bottom)
            {
                //COLLIDE BOTTOM
                Position.Y = ctile.tileRectangle.Bottom;
            }

            if (Position.X < ctile.tileRectangle.Left - 32)
            {
                //COLLIDE LEFT
                Position.X = ctile.tileRectangle.Left - 32;
            }

            if (Position.X > ctile.tileRectangle.Right)
            {
                //COLLIDE RIGHT
                Position.X = ctile.tileRectangle.Right;
            }

        }

    }

Thanks for help!

1 Answers1

0

There are some flaws in your collision logic:

  • You are ignoring multiple collisions and handling only one (collision with ctile)
  • Your collision direction logic is incorrect, it checks if there was an intersection but does not check which border(s) of the tile were crossed, this is where the sticking behavior comes from

The collision handling should be done for each intersecting tile, not just the last one as you are now doing. In your collision handling you could move the object back by the amount that it penetrated into the tile it collided with on x and y axes.

And if you are really using a tile map (a grid of tiles), iterating over all tiles is very inefficient. You could just calculate which tiles intersect with the object that is moving.