Player Bounds
Contents
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.