The term "collision" in game development refers to both detecting whether objects are touching as well as changing the state of these objects when this touching occurs.
Almost all games requires some type of collision. For example, Pong used ball vs. paddle collision and Super Mario Bros. performs collision between Mario and the ground to test whether he should fall or not. Even games which might not seem to use collision likely do. For example, mouse-driven adventure games like King's Quest VI used collision to detect whether the cursor is overlapping certain areas when clicking.
The only games free from collision are pure text-based games, but it's likely that if you're working on one of those you probably won't need to use FlatRedBall.
Before we get into how FlatRedBall handles collision, let's cover some basic terminology.
We've already discussed what a collision is, so let's give some examples. The following image shows three situations and labels whether a collision is occurring:
Notice that collision doesn't just occur if the edges of two objects are touching. When FlatRedBall performs collision, it considers objects to be filled in. Therefore, if one object is inside of another, a collision is still occurring.
A move collision is a collision where one or both of the involved shapes are repositioned during the collision to prevent overlap. The term "move" was selected because this type of collision can result in the shapes moving to new positions. The amount that each shape is moved depends on their masses relative to each other. It is very common to make one object static by giving it a non-zero mass and giving the other object a mass of zero. The following image shows the result of a move collision assuming that the rectangle is static and the circle is not.
To use FlatRedBall terms, move collisions will adjust the position of the involved shape(s) if a collision does occur.
A "bounce" collision is a collision which can be used to simulate physics. As the name implies, bounce collisions cause objects to bounce against each other. Just like move collisions, bounce collisions use the masses of two objects to calculate how the forces from the bounce should be applied. Just like with move collisions, it is common to have one object in a bounce collision have a non-zero mass while the other has a mass of zero. This causes one of the shapes (the one with the non-zero mass) to not be affected by the collision.
You're probably pretty familiar with the word "shape". In FlatRedBall, shape defines a shape like a square, triangle, or circle. To be a little more precise, a shape is an object which is a PositionedObject, has collision methods, and is managed by the ShapeManager class.
You may also be expecting there to be a Shape interface or class that all shapes implement. Actually, there isn't such an interface or class. The reason for this is performance. Initial performance measurement tests in FlatRedBall showed that the majority of time spent in collision loops is the actual method calls. In other words, we compared the amount of time required to call collision methods to the amount of time calling "empty" methods and over half of the time was spent in the method call.
Of course this ratio can fluctuate depending on the complexity of the collision method and the frequency of collision occurrence. However, making a method virtual makes the method call itself take longer than otherwise, and we decided to give up the convenience of a base class for better performance. FlatRedBall provides a number of shape classes, and this list may continue to grow as more sophisticated collision needs are satisfied. If you'd like to find out which shape classes are available, check out the ShapeManager page.
Most games use Shapes to detect whether collision is occurring; however, not all games keep collision Shapes visible. Therefore, it is likely that your game will use Shapes for collision and another type of object for drawing (such as Sprites). In this situation, the Shapes that you use will approximate the collidable area of your visible object. In some cases simple Shapes such as Circles and AxisAlignedRectangles will be sufficient. In cases where more complex collision shapes are needed, the Polygon object is a good alternative. In more complex situations multiple Shapes can be used.
As you'll see in the next sections where we begin writing some sample code, Shapes have a Visible property which can be used to control whether the FlatRedBall Engine draws them. In the following examples the Shapes that are created through the ShapeManager will automatically be set to be Visible. When using Shapes only for collision and attaching them to other objects, it is not necessary to create them through or add them to the ShapeManager. Keep this in mind as you read other documentation about Shapes.
Collision can be detected between shapes simply by calling CollideAgainst. The following code example creates two Circles. One Circle is positioned at the point of the mouse. If a collision occurs, the moving Circle becomes orange. Otherwise, it is blue. Add the following using statements:
Add the following at class scope:
Add the following to Initialize after initializing FlatRedBall:
Add the following to Update:
WARNING: The code above may not compile because the Color struct is not qualified (the code doesn't know which namespace it is in). Which "using" statement you add to your code depends on which version of FlatRedBall you are using. For more information, see the Color page.
The CollideAgainst method is a method that only returns whether collision has occurred - it does not modify the calling Shape or the argument Shape. The following sections describe methods which do.
The CollideAgainstMove method returns a true or false depending on whether the calling Shape and the argument Shape are touching. This method also modifies the Position of one or both Shapes.
Keep in mind that since this method modifies the Position, we should not directly modify the Positions in custom code every frame. Doing so would result in the CollideAgainstMove and our own code both attempting to control the Position of the involved Shapes. While this won't cause a crash, it may result in unexpected or undesirable behavior. In most cases where CollideAgainstMove is used, the Shapes involved (or their Parent Entities) are controlled either by Velocity or Acceleration.
We'll use Velocity for the following example: Use the same using statements, class-level declarations, and Initialize code as above, then replace the custom Update logic with the following:
The first "1" argument is the mass of the first object. The second "1" is the mass of the second object. Try changing the first argument to 0. This will make secondCircle immovable. Then try changing the first argument back to 1, then the second to 0. This will make the moving circle unaffected by secondCircle.
The third method that we'll look at is CollideAgainstBounce. The CollideAgainstBouncegives us all of the same functionality as CollideAgainstMove( true/false return value as well as repositioning), but it also modifies the involved Shapes' Velocity values. For bouncing to behave properly, we have to make sure that we're not controlling the involved Shapes' position or velocity. Therefore, this leaves us with controlling acceleration. To use CollideAgainstBounce, simply replace your custom Update code with the following:
Now the two Circles will collide against each other and bounce. Of course, you will probably notice that this setup results in secondCircle being moved off of the screen very quickly. You may want to change the firstCircle's mass to 0 to keep the secondCircle on screen so you can test multiple collisions.
This article covers a lot of information about collisions; however, this topic has a lot of depth. To find out more, start at the ShapeManager page and follow the links to the information you're interested in.