1
votes

This is a follow up question to a question that I posted last night. I have to write a game in a Windows Form for school, and I am creating a maze game in which a player must navigate through a maze before they are killed. As a maze game, some collision detection must be used to make sure that the player doesn't simply run through the walls (this would be quite a boring game). I've implemented a feature which prevents this based on the question that I asked last night, but I'm getting some weird results.

When the player touches a wall, the game stops them, and the player ends up getting stuck. The player CANNOT move unless they press a combination of keys to move through the wall (my game uses WASD, so if I touch a wall, I can press W + A and go through the wall to the other side where my player gets unstuck).

This is my collision code:

                // This goes in the main class
                foreach (Rectangle wall in mazeWalls)
                {
                    if (playerRectangle.IntersectsWith(wall))
                    {
                        player.Stop();
                    }
                }   

This is the player's movement code:

    public void Move(Direction dir)
    {
        // First, check & save the current position.
        this.lastX = this.x;
        this.lastY = this.y;

        if (dir == Direction.NORTH)
        {
            if (!CheckCollision())
            {
                this.y -= moveSpeed;
            }
            else
            {
                this.y += 1;
            }

        }
        else if (dir == Direction.SOUTH)
        {
            if (!CheckCollision())
            {
                this.y += moveSpeed;
            }
            else
            {
                this.y -= 1;
            }


        }
        else if (dir == Direction.EAST)
        {
            if (!CheckCollision())
            {
                this.x += moveSpeed;
            }
            else
            {
                this.x -= 1;
            }

        }
        else if (dir == Direction.WEST)
        {
            if (!CheckCollision())
            {
                this.x -= moveSpeed;
            }
            else
            {
                this.x += 1;
            }


        }
    }

My CheckCollision() method:

    private bool CheckCollision()
    {            
        // First, check to see if the player is hitting any of the boundaries of the game.
        if (this.x <= 0)
        {
            isColliding = true;
        }
        else if (this.x >= 748)
        {
            isColliding = true;
        }
        else if (this.y <= 0)
        {
            isColliding = true;
        }
        else if (this.y >= 405)
        {
            isColliding = true;
        }
        else if (isColliding)
        {
            isColliding = false;
        }
        // Second, check for wall collision.
        return isColliding;
    }

The Stop() method:

    public void Stop()
    {
        this.x = lastX;
        this.y = lastY;            
    }

Here is a gif that I have uploaded so that you can see the behavior of the player with the maze walls. Notice how he slides through the walls and repeatedly gets stuck.

My question is how do I get this player to stop sticking and actually be able to slide and move with the walls? I've tried multiple collision patterns, and used last night's (very helpful) answer, but he won't stop sticking to the walls! Let me know if you need any other details/information.

EDIT: The Input code, as requested by Dan-o: http://pastebin.com/bFpPrq7g

1
ensure your code logic is solid. there may be a possibility the code is performing checking 2 key pressed events about the same time then breaking your logic. try ensure only the key pressed event checking only work in exclusive mode, like using thread waiting/blocking for last-in event (queueing approach).Kelmen
@Kelmen Would you like me to post my keyboard input code? Because the game is built in a WinForm, the input is handled by keyboard events, which to be honest I don't know a whole lot about. I can post it if you'd like.MrSir
sorry, i not interested in doing code review. i'm giving you a direction how to improve/debug your codes. if you have no idea how to approach this, like use Debug.WriteLine("x is " + x.ToString()). and attempt to reproduce this issue in dev mode, when it happen, look at your VS Output window, check the message, see is the x value changed to some unexpected value, and trace back your code, add more stuffs to pinpoint the cause.Kelmen
@Kelmen Thanks. It wasn't really for code review; I just wanted to see if posting that kind of code would be beneficial to solving the problem.MrSir
@MrSir: Yes, post the keyboard input code please.Sam Axe

1 Answers

1
votes

Game design is a complicated subject. There are some pretty well documented strategies for implementing 2D maze games. The most anyone can do here is to make general suggestions based on what you've done knowing that a commercial game is not what trying to make here. So anyhow, I'll throw in my two cents. I've only done anything like this in OpenGL, not with Windows Forms.

The first thing I see is that your sprite doesn't stay centered in it's lanes. Calculating that will ultimately make things easier because there are always only 4 possible directions that the player can be moving. North, South, East, and West don't mean as much when diagonal is also possible.

Design your gameboard so that your walls and your lanes are the same width. Use evenly spaces rows and columns. Since you're using a fixed board size, this should be as simple as dividing your width and height by the number of rows and columns you want.

Once you've done this, you will always know what lane you're in based on your x and y coordinates. If your columns are 80 pixels wide, for instance, and you're at x = 160 then you know you're in column 2 (1 in a 0-based array). This is the only way you are going to be able to put enemies on the board and be able to programmatically track where they are going. Also, you'll be able to size your players and enemies appropriately for the lanes.

Let's say your rows and columns are 80Wx60H pixels (they can be whatever you like best). Now let's say that your player is moving East starting from 0, 160. And, he can move North and South when he gets to column 3 (2 in a zero-based model), according to your map. Meaning, when he gets to 160, 160. Remember, if x = 0 starts column 1, then 80 starts column 2, and so on.

Forgetting collisions for a moment, you could use logic like this.

RectangleF playerRectangle = new RectangleF();
int COLUMN_WIDTH = 80;
int ROW_HEIGHT = 60;

if (playerRectangle.IntersectsWith(wall)){
    int column = playerRectangle.X / COLUMN_WIDTH;

    //----------------------------------------------
    // This will return false if the player 
    // is not positioned right at the column. The 
    // result of % will contain decimal digits.
    // playerRectangle.X has to be a float though.
    //----------------------------------------------
    if(column % 1 == 0){
        //--------------------------------------------
        // do this based on your keyboard logic. this 
        // is pseudo-code
        //--------------------------------------------
        if(keys == keys.UP){
            // Move up
        }
        else if(keys == keys.DOWN){
            // Move down
        }
    }
}

Another thing you'll want to do is to store an orientation property with your walls. That way when you collide with one, you'll know what your options are for movement. If the wall you collide with is WallOrientation.NorthSouth, you can only move North or South once you hit it. Or, you can go in reverse to the direction you hit it from. If no keys are pressed you sit still. Some thing like this will do.

public enum WallOrientation{
    NorthSouth,
    EastWest
}

None of this code is tested. I just wrote it on the fly so there could be mistakes. I'm just trying to give you some ideas. I hope this advice helps you out some.