Player Bounds

From TRCCompSci - AQA Computer Science
Jump to: navigation, search

Player Bounds

This wiki includes examples for many TMX map drawing libraries and code. The all work in a slightly different way, as such this section tries to be generic and explain the ideas and less so the code.

The overall structure for Check Bounds

Create a new method in your Game1.cs called CheckBounds, we will need this method to return a boolean to identify if the player is within the bounds or not:

public bool CheckBounds()
{
            bool check = false;
            // YOU WILL PUT YOUR METHOD BETWEEN THESE LINES
            // YOU WILL DECIDE IF A COLLISION HAPPENS AND SET CHECK TO TRUE
            return check;
}


Player Bound Idea 1

We could identify the 4 corners of our player, we need to know the exact coordinates for each. The left top corner is easy because the X & Y of the player will give you this corner. The right top can be calculated by adding the Width onto the X of the player, the Y should be the same. The left bottom can be calculated by adding the height to the Y coordinate of the player. The right bottom can be calculated by adding the width to the X and the height to the Y:

            //get exact coordinates for each corner
            Vector2 lt = new Vector2(map.ObjectGroups["objects"].Objects["Player"].X, map.ObjectGroups["objects"].Objects["Player"].Y);
            Vector2 rt = lt + new Vector2(map.ObjectGroups["objects"].Objects["Player"].Width, 0);
            Vector2 lb = lt + new Vector2(0, map.ObjectGroups["objects"].Objects["Player"].Height);
            Vector2 rb = lt + new Vector2(map.ObjectGroups["objects"].Objects["Player"].Width, map.ObjectGroups["objects"].Objects["Player"].Height);

Now we know the location of each corner we can check to see which tile the corner is over. This can be calculated by dividing the X & Y coordinates by the tilepixel variable. We can add these new vectors into a list:

            //get the tile row and column for each corner
            List<Vector2> corners = new List<Vector2>();
            corners.Add(new Vector2((lt.X / tilepixel), (lt.Y / tilepixel)));
            corners.Add(new Vector2((lb.X / tilepixel), (lb.Y / tilepixel)));
            corners.Add(new Vector2((rt.X / tilepixel), (rt.Y / tilepixel)));
            corners.Add(new Vector2((rb.X / tilepixel), (rb.Y / tilepixel)));

Now we know the tile position for each corner we can check if that tile in our collision layer tile is empty (0) or not. If the tile has a different value then we have collided with the bounds of the room:

            //check if any corners are on a blocked tile
            foreach (Vector2 corner in corners)
            {
                int tile = collision.GetTile((int)corner.X, (int)corner.Y);
                if (tile != 0)
                {
                    check = true;
                }
            }

Player Bounds Idea 2

Everyone will need to be careful regarding just copying and pasting code, especially from key areas such has checking the bounds of the player. I have therefore identified other ways to check the bounds.

Find the center tile and then check the tile to the left & right, and above & below:

                    
            Vector2 centertile = new Vector2(
                (map.ObjectGroups["Objects"].Objects["Player"].X + (map.ObjectGroups["Objects"].Objects["Player"].Width / 2))/tilepixel,
                (map.ObjectGroups["Objects"].Objects["Player"].Y + (map.ObjectGroups["Objects"].Objects["Player"].Height / 2))/tilepixel
                );

            if (collision.GetTile((int)centertile.X - 1, (int)centertile.Y) != 0)
                check = true;
            if (collision.GetTile((int)centertile.X + 1, (int)centertile.Y) != 0)
                check = true;
            if (collision.GetTile((int)centertile.X, (int)centertile.Y - 1) != 0)
                check = true;
            if (collision.GetTile((int)centertile.X, (int)centertile.Y + 1) != 0)
                check = true;

Player Bounds Idea 3

The method above doesn't allow you to get very close to the actual bounds. Instead we can also create a rectangle for the player and the tile to see if they intersect. The tile is calculated by finding the center tile, and then finding the tile below:

            Rectangle playrec = new Rectangle(
                map.ObjectGroups["Objects"].Objects["Player"].X,
                map.ObjectGroups["Objects"].Objects["Player"].Y,
                map.ObjectGroups["Objects"].Objects["Player"].Width,
                map.ObjectGroups["Objects"].Objects["Player"].Height
                );

            Vector2 centertile = new Vector2(
                (map.ObjectGroups["Objects"].Objects["Player"].X + (map.ObjectGroups["Objects"].Objects["Player"].Width / 2)) / tilepixel,
                (map.ObjectGroups["Objects"].Objects["Player"].Y + (map.ObjectGroups["Objects"].Objects["Player"].Height / 2)) / tilepixel
                );

            if (collision.GetTile((int)centertile.X, (int)centertile.Y+1) != 0)
            {
                Rectangle bottom = new Rectangle(
                    (int)centertile.X * tilepixel,
                    (int)(centertile.Y + 1) * tilepixel,
                    tilepixel,
                    tilepixel
                    );

                if (playrec.Intersects(bottom))
                    check = true;
            }

Player Bounds Idea 4

You could also check each of the tiles around the centertile using two for loops. The code, if (x != 0 && y != 0) is to not check the center tile because this will obviously collide with the player :

            for (int x=-1; x<=1; x++)
            {
                for (int y = -1; y <=1; y++)
                {
                    Vector2 tempv = centertile + new Vector2(x, y);
                    if (x != 0 && y != 0)
                    {
                        if (collision.GetTile((int)tempv.X, (int)tempv.Y) != 0)
                        {
                            Rectangle temp = new Rectangle(
                                (int)tempv.X * tilepixel,
                                (int)tempv.Y * tilepixel,
                                tilepixel,
                                tilepixel
                                );

                            if (playrec.Intersects(temp))
                                check = true;
                        }
                    }
                }
            }

Player Bounds Idea 5

Another approach could be to check every tile on the map to see if it collides with the player. This might be a good approach if your map is small, or if each of your locations are a separate map. You can create a rectangle for the player as before:

            for (int x = 0; x < map.Width; x++)
            {
                for (int y = 0; y < map.Height; y++)
                {
                    if (collision.GetTile(x,y) != 0)
                    {
                        Rectangle tile = new Rectangle(
                            (int)x * tilepixel,
                            (int)y * tilepixel,
                            tilepixel,
                            tilepixel
                            );

                        if (playrec.Intersects(tile))
                            check = true;
                    }
                }               
            }

Using CheckBounds

In the variables of Game1.cs make sure you declare:

Layer collision;

Now in the LoadContent, and after you have set up your map add:

collision = map.Layers["Collision"];

Now we need to edit the Update method of Game1.cs, firstly we want to record the current X & Y value of the player before we apply any movement. We can then use ProcessMovent to move the player, and then CheckBounds. If CheckBounds returns true we can use the stored X & Y values to move the player back to the position before the movement:

            //store current position to move back too if collision
            int tempx = map.ObjectGroups["objects"].Objects["Player"].X;
            int tempy = map.ObjectGroups["objects"].Objects["Player"].Y;

            processMovement(keyState, gamePadState);

            //now we have moved checkbounds
            if (CheckBounds())
            {
                map.ObjectGroups["objects"].Objects["Player"].X = tempx;
                map.ObjectGroups["objects"].Objects["Player"].Y = tempy;
            }

You should now have a player confined to the room you created on your map.