Collision detection in a 2D maze with thick walls

2019-05-08 05:50发布

I have to make a game with Windows Forms for school. My game consists of a user having to get through a maze. I'm trying to prevent my user from going straight through the walls using collision detection, but am getting stuck because of the varying shape of the rectangles being used to represent walls. Here's an image of the game. This question may be similar to this one, however with my movement I believe that it is quite different, as I don't have a grid system or graphical map laid out.

As you can see, the walls are fairly thick. Each wall is represented by a C# Rectangle, as is my Player image (the little yellow ghost). I know how to determine if the player is crossing through these walls using C#'s IntersectsWith(Rectangle r) method, but I'm not exactly sure how to use this information in order to handle the collision and STOP the player from moving through the walls at all.

Here's what I've tried:

This is my actual movement code. Because the game is built in WinForm, the movement is triggered by keyboard events such as OnKeyPressed and OnKeyUp

    public void Move(Direction dir)
    {
        HandleCollision(); // Handle collision while player is trying to move.
        if (dir == Direction.NORTH)
        {                
            this.y -= moveSpeed;
        }
        if (dir == Direction.SOUTH)
        {                
            this.y += moveSpeed;
        }
        if (dir == Direction.EAST)
        {
            this.x += moveSpeed;
        }
        if (dir == Direction.WEST)
        {
            this.x -= moveSpeed;
        }
    }

This is my collision method, HandleCollision():

    private void HandleCollision()
    {
        // First, check to see if the player is hitting any of the boundaries of the game.
        if (this.x <= 0)
        {
            this.x = 0;
        }
        if (this.x >= 748)
        {
            this.x = 748;
        }
        if (this.y <= 0)
        {
            this.y = 0;
        }
        if (this.y >= 405)
        {
            this.y = 405;
        }           
        // Second, check for wall collision.

        foreach (Rectangle wall in mazeWalls)
        {
            if (playerRectangle.IntersectsWith(wall))
            {
                if (player.X > wall.X) { player.X += wall.Width; }
                else if (player.X < wall.X) { player.X -= wall.Width; }
                else if (player.Y > wall.Y) { player.Y += wall.Height; }
                else if (player.Y < wall.Y) { player.Y -= wall.Height; }                    
            }
        }
    }

Now this code above kind of works. However, because the player's coordinates are having the wall's width/height added to it, this makes some weird collision teleportation across the map where the player ends up bouncing around. So what would be the most efficient way of going about implementing a collision detection system which can replace all the code within the if (playerRectangle.IntersectsWith(wall)) { block?

1条回答
兄弟一词,经得起流年.
2楼-- · 2019-05-08 06:17

In the move, save the current position, perform the move, check for collision, and if true, restore the old position.

For this to work, HandleCollision would return a Boolean value, true for each successful test (successful=collision detected), false at the end if no condition was met. The method would not modify any x or y value at all. To reflect its new function, this method should be renamed to CheckCollision.


From the gif in your other post it seems that your playing field is divided into squares, and walls and sprite are composed of multiple squares? Then your move should proceed in increments of one square until the intended increment is met. For each square the collision has to be checked.

For a more advanced method with only one check per move you need some linear mathematics. The collision check will need the current point P and the increment d of the move. You need to check if between P and P+d the wall is crossed. This is usually indicated by a sign change in a linear condition. For a vertical wall W to the left of P, if d points to the wall, P.x+d.x-(W.x+W.width) will be negative. Determine s with W.x+W.width<=P.x+s*d.x. For horizontal walls, you have to do the same check in the y-coordinate. Take the minimal s over all objects hit and P+s*d as the new position.

查看更多
登录 后发表回答