Monogame, and nearly every other game framework has pre-built in collision detection using Rectangles. Sometimes however, a Rectangle is not the best shape to fit your game objects. This section is going to cover how you can use circles to do your collision detection.
Adding content
Keyboard/mouse input
Vector2's
Casting between floats and ints
Using Lists
Collision with Rectangles
Here is my example program:
https://github.com/AldworthClass/Collisions-with-Circular-Hitboxes
In terms of computer workload, using circle or rectangular hitboxes makes little difference. Since a Rectangle class comes ready to use, why use circles at all?
1 - If your items can rotate, a circle still works, while things get really complicated with Rectangles.
2 - Sometimes a circle fits your shape better than a rectangle. Sometimes it doesn't. You need to decide what is right for you.
Read through RB Whittaker's tutorial on Circular hitboxes, and follow it to create your own circle class. In practice, it should work in exactly the same way as you would use Rectangles.
http://rbwhitaker.wikidot.com/circle-collision-detection
One of the nice things that makes this easy is that the Vector2 class has a method called Length() that we can use to determine the distance between 2.
There is one correction to the tutorial. If you are going to use the Concise version of his Intersects() method, it should look like this:
// The concise version...
public bool Intersects(Circle other)
{
return ((other.Center - Center).Length() < (other.Radius + Radius));
}
Note that the return statement needs to add the radiuses together, but in the tutorial it subtracts them.
Interestingly, you could re-name the concise version on the internet (with the error) and call it Contains(Circle other), and it would work to determine whether a Circle other is entirely contained in the calling circle. You might as well add this to the class as well:
// The concise version from the web actually works as a Contains method
public bool Contains(Circle other)
{
return ((other.Center - Center).Length() < (other.Radius - Radius));
}
After you have this class made, you are ready to use circles for collision detection.
See my example program for details:
https://github.com/AldworthClass/Collisions-with-Circular-Hitboxes
There is one thing that using circled does that may rsult in a bit more work. The various Draw() methods offered in Monogame, require either a Vector2 as a location, or a destination Rectangle. The location that it will draw your textures will always be their upper left corner. But the location coordinate of our circle refers to its center.
_spritebatch.Draw(fireballTexture, new Vector(fireballCircle.Center.X - fireballCircle.Radius, fireballCircle.Center.X - fireballCircle.Radius), Color.White);
Notice that we need to draw it at a point where the x and y are moved left and up by the radius to draw it in the same location that we are checking for collisions.
What if you want to scale your texture when you draw it? You need to specify a Rectangle. Now, just like above, you need to create a Rectangle in the Draw method. What a hassle.
The easy solution is to add two properties to your Circle Struct that will return the translated location for drawing (Vector2 and Rectangle).
Here are my versions. Simply add these to your Circle struct:
Use this if you need to scale your texture:
// Vector of top left bound for drawing the texture
public Rectangle DrawRect
{
get
{
return new Rectangle((int)(Center.X - Radius), (int)(Center.Y - Radius), (int)Radius * 2, (int)Radius * 2);
}
}
Now you can draw like this:
_spriteBatch.Draw(fireballTexture, fireBallCircle.DrawRect, Color.White);
If the texture's size matches that of the circle hitbox and doesn't need scaling, you can draw it using a Vector2:
// Since the circle
public Vector2 DrawLocation
{
get
{
return new Vector2(Center.X - Radius, Center.Y - Radius);
}
}
Now you can draw like this:
_spriteBatch.Draw(fireballTexture, fireBallCircle.DrawLocation, Color.White);
Here are all texture files used in my example program, as well as my Circle.cs file. You will need to make sure you change its namespace to match that of your project before you can use it: