Difference between revisions of "Player Bounds"

From TRCCompSci - AQA Computer Science
Jump to: navigation, search
(Using CheckBounds)
 
(One intermediate revision by the same user not shown)
Line 1: Line 1:
==Player Bound Idea 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>
  
Now we need to 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:
+
 
 +
==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#>
public bool CheckBounds()
+
 
{
 
            bool check = false;
 
 
             //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);
                map.ObjectGroups["objects"].Objects["Player"].Height);
+
 
  
            return check;
 
}
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Line 30: Line 34:
  
 
<syntaxhighlight lang=c#>
 
<syntaxhighlight lang=c#>
public bool CheckBounds()
 
{
 
            bool check = false;
 
            //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);
 
 
 
             //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)));
 
            return check;
 
}
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Line 54: Line 45:
  
 
<syntaxhighlight lang=c#>
 
<syntaxhighlight lang=c#>
public bool CheckBounds()
 
{
 
            bool check = false;
 
            //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);
 
 
            //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)));
 
  
 
             //check if any corners are on a blocked tile
 
             //check if any corners are on a blocked tile
Line 81: Line 56:
 
             }
 
             }
  
            return check;
 
}
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Line 91: Line 64:
  
 
<syntaxhighlight lang=c#>
 
<syntaxhighlight lang=c#>
public bool CheckBounds()
 
        {
 
            bool check = false;
 
 
                      
 
                      
 
             Vector2 centertile = new Vector2(
 
             Vector2 centertile = new Vector2(
Line 109: Line 79:
 
                 check = true;
 
                 check = true;
  
            return check;
 
        }
 
 
</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#>
public bool CheckBounds()
+
 
        {
 
            bool check = false;
 
  
 
             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 + 1, (int)centertile.Y)!=0)
 
            {
 
                Rectangle right = new Rectangle(
 
                    (int)(centertile.X + 1) * tilepixel,
 
                    (int)centertile.Y * tilepixel,
 
                    tilepixel,
 
                    tilepixel
 
                    );
 
 
                if (playrec.Intersects(right))
 
                    check = true;
 
            }
 
 
            if (collision.GetTile((int)centertile.X - 1, (int)centertile.Y) != 0)
 
            {
 
                Rectangle left = new Rectangle(
 
                    (int)(centertile.X - 1) * tilepixel,
 
                    (int)centertile.Y * tilepixel,
 
                    tilepixel,
 
                    tilepixel
 
                    );
 
 
                if (playrec.Intersects(left))
 
                    check = true;
 
            }
 
 
            if (collision.GetTile((int)centertile.X, (int)centertile.Y-1) != 0)
 
            {
 
                Rectangle top= new Rectangle(
 
                    (int)centertile.X * tilepixel,
 
                    (int)(centertile.Y - 1) * tilepixel,
 
                    tilepixel,
 
                    tilepixel
 
                    );
 
 
                if (playrec.Intersects(top))
 
                    check = true;
 
            }
 
  
 
             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:
 
             }
 
             }
  
 
            return check;
 
        }
 
 
</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#>
public bool CheckBounds()
 
        {
 
            bool check = false;
 
 
            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
 
                );
 
  
 
             for (int x=-1; x<=1; x++)
 
             for (int x=-1; x<=1; x++)
Line 231: Line 140:
 
                 }
 
                 }
 
             }
 
             }
             return check;
+
              
        }
 
 
</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#>
        public bool CheckBounds()
 
        {
 
            bool check = false;
 
 
            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
 
                );
 
  
 
             for (int x = 0; x < map.Width; x++)
 
             for (int x = 0; x < map.Width; x++)
Line 269: Line 167:
 
             }         
 
             }         
  
            return check;
 
        }
 
 
</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>
  
Layer collision =  
+
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

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.