Difference between revisions of "Player Bounds"
(→Using CheckBounds) |
|||
(One intermediate revision by the same user not shown) | |||
Line 1: | Line 1: | ||
− | == | + | =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: | 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: | ||
Line 6: | Line 9: | ||
{ | { | ||
bool check = false; | 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; | return check; | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | + | ||
+ | ==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: | ||
<syntaxhighlight lang=c#> | <syntaxhighlight lang=c#> | ||
− | + | ||
− | |||
− | |||
//get exact coordinates for each corner | //get exact coordinates for each corner | ||
Vector2 lt = new Vector2(map.ObjectGroups["objects"].Objects["Player"].X, map.ObjectGroups["objects"].Objects["Player"].Y); | 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 rt = lt + new Vector2(map.ObjectGroups["objects"].Objects["Player"].Width, 0); | ||
Vector2 lb = lt + new Vector2(0, map.ObjectGroups["objects"].Objects["Player"].Height); | Vector2 lb = lt + new Vector2(0, map.ObjectGroups["objects"].Objects["Player"].Height); | ||
− | Vector2 rb = lt + new Vector2(map.ObjectGroups["objects"].Objects["Player"].Width, | + | Vector2 rb = lt + new Vector2(map.ObjectGroups["objects"].Objects["Player"].Width, map.ObjectGroups["objects"].Objects["Player"].Height); |
− | + | ||
− | |||
− | |||
</syntaxhighlight> | </syntaxhighlight> | ||
Line 30: | Line 34: | ||
<syntaxhighlight lang=c#> | <syntaxhighlight lang=c#> | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
//get the tile row and column for each corner | //get the tile row and column for each corner | ||
List<Vector2> corners = new List<Vector2>(); | List<Vector2> corners = new List<Vector2>(); | ||
Line 46: | Line 40: | ||
corners.Add(new Vector2((rt.X / tilepixel), (rt.Y / tilepixel))); | corners.Add(new Vector2((rt.X / tilepixel), (rt.Y / tilepixel))); | ||
corners.Add(new Vector2((rb.X / tilepixel), (rb.Y / tilepixel))); | corners.Add(new Vector2((rb.X / tilepixel), (rb.Y / tilepixel))); | ||
− | |||
− | |||
− | |||
</syntaxhighlight> | </syntaxhighlight> | ||
Line 54: | Line 45: | ||
<syntaxhighlight lang=c#> | <syntaxhighlight lang=c#> | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
//check if any corners are on a blocked tile | //check if any corners are on a blocked tile | ||
Line 81: | Line 56: | ||
} | } | ||
− | |||
− | |||
</syntaxhighlight> | </syntaxhighlight> | ||
Line 91: | Line 64: | ||
<syntaxhighlight lang=c#> | <syntaxhighlight lang=c#> | ||
− | |||
− | |||
− | |||
Vector2 centertile = new Vector2( | Vector2 centertile = new Vector2( | ||
Line 109: | Line 79: | ||
check = true; | check = true; | ||
− | |||
− | |||
</syntaxhighlight> | </syntaxhighlight> | ||
==Player Bounds Idea 3== | ==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 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: |
<syntaxhighlight lang=c#> | <syntaxhighlight lang=c#> | ||
− | + | ||
− | |||
− | |||
Rectangle playrec = new Rectangle( | Rectangle playrec = new Rectangle( | ||
Line 132: | Line 98: | ||
(map.ObjectGroups["Objects"].Objects["Player"].Y + (map.ObjectGroups["Objects"].Objects["Player"].Height / 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) | if (collision.GetTile((int)centertile.X, (int)centertile.Y+1) != 0) | ||
Line 185: | Line 112: | ||
} | } | ||
− | |||
− | |||
− | |||
</syntaxhighlight> | </syntaxhighlight> | ||
Line 193: | Line 117: | ||
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 : | 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 : | ||
<syntaxhighlight lang=c#> | <syntaxhighlight lang=c#> | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
for (int x=-1; x<=1; x++) | for (int x=-1; x<=1; x++) | ||
Line 231: | Line 140: | ||
} | } | ||
} | } | ||
− | + | ||
− | |||
</syntaxhighlight> | </syntaxhighlight> | ||
==Player Bounds Idea 5== | ==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: | + | 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: |
<syntaxhighlight lang=c#> | <syntaxhighlight lang=c#> | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
for (int x = 0; x < map.Width; x++) | for (int x = 0; x < map.Width; x++) | ||
Line 269: | Line 167: | ||
} | } | ||
− | |||
− | |||
</syntaxhighlight> | </syntaxhighlight> | ||
==Using CheckBounds== | ==Using CheckBounds== | ||
In the variables of Game1.cs make sure you declare: | In the variables of Game1.cs make sure you declare: | ||
+ | <syntaxhighlight lang=c#> | ||
+ | Layer collision; | ||
+ | </syntaxhighlight> | ||
− | + | Now in the LoadContent, and after you have set up your map add: | |
+ | <syntaxhighlight lang=c#> | ||
+ | collision = map.Layers["Collision"]; | ||
+ | </syntaxhighlight> | ||
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: | 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: |
Latest revision as of 10:27, 15 February 2024
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.