Part 6 - Collisions
In this walkthrough, add the ability for the game to detect collisions from projectiles.
Adding a ProjectileType
on the Projectile
Class
In order to properly check for collisions, it will be necessary to know the type of each Projectile
object. If a projectile is coming from the Player
, it should check for collisions with Enemy
objects. If a projectile is coming from an Enemy
, it should check for collisions with the Player
object.
Add the Field and Property
First, update the Projectile
class with a new field and property. Open up the Projectile.cs class to get started.
- In the body of the
Projectile
class, type in "propfull" and press Enter- This code snippet creates a template for a new property
- For the type of the new field/property, enter
ProjectileType
- Press Tab to go to the next part of the template; the field name
- For the field name, enter
projectileType
- Press Tab again to move onto the property name, and enter
ProjectileType
The code should ultimately look something like this:
private ProjectileType projectileType;
public ProjectileType ProjectileType
{
get { return projectileType; }
set { projectileType = value; }
}
Add the Constructor Parameter
Now that there is a ProjectileType
on the Projectile
class, it needs to be populated!
- Find the
Projectile
constructor - In the method signature, add a
ProjectileType
parameter namedprojectileType
- In the body of the constructor, set the
this.projectileType
field to the value of theprojectileType
parameter - Open up the ArcadeFlyerGame.cs file, and find the
FireProjectile
method - Update the call to the
Projectile
constructor, and pass in theprojectileType
parameter value
At this point, there should be no errors in the code. Nothing will have changed, but the new ProjectileType
property will make it possible to distinguish between projectiles in the game.
Sprite Collisions
At long last, it's time to check whether any of the objects in our game collide with each other. One structure for doing this is by modifying our Sprite
class, to add a method to see if any other sprites collide with it.
Every Sprite
has a member Rectangle
named PositionRectangle
. The Rectangle
class has a method named Intersects()
, which takes another Rectangle
as a parameter, and returns a bool
indicating if the two rectangles overlap. We can write a "wrapper" for this in our Sprite
class, to tell us if a Sprite
intersects with another Sprite
.
- In the Sprite.cs file, inside the
Sprite
class, add a new method namedOverlaps
- Make the
Overlaps
method take aSprite
object namedotherSprite
as the parameter - Make the
Overlaps
method return abool
indicating if the two sprites overlap - The
Overlaps
method should callIntersects
on thePositionRectangle
of this object, and pass in thePositionRectangle
of theotherSprite
as the parameter toIntersects
public bool Overlaps(Sprite otherSprite)
{
bool doesOverlap = this.PositionRectangle.Intersects(otherSprite.PositionRectangle);
return doesOverlap;
}
Removing Projectile
Objects On Collision
Now that it is possible to detect collisions between sprites, it's time to update the game. If an enemy projectile comes in contact with the player, that projectile should be removed. Similarly, if a player projectile comes in contact with an enemy, that projectile should be removed. For now, the collision will not have any other effect (that will come later).
for
Loop Setup
In order to remove Projectile
objects from the projectiles
list, it will be necessary to loop through each object. However, using a traditional for
loop or foreach
loop will not work; when an object is removed from a List
, it disrupts the flow of the loop. Instead, loop through the list backwards so that removed objects do not interfere with the current position in the list.
- Find the
Update
method on theArcadeFlyerGame
class - In the body of the
Update
method, remove theforeach
loop that loops through theprojectiles
list - Create a new
for
loop structure - For the initialization, create a new
int i
variable and set it to theCount
of theprojectiles
list minus1
- For the condition, check if the
i
variable value is greater than or equal to0
- For the increment, decrease the value of the
i
variable by1
usingi--
- In the body of the
for
loop, define a newProjectile
variablep
, and set it to the element in theprojectiles
list ati
- Under that, call the
Projectile
'sUpdate
method on thep
variable
for (int i = projectiles.Count - 1; i >= 0; i--)
{
Projectile p = projectiles[i];
p.Update();
}
for
Loop Body
Now that the for
loop will properly loop through each Projectile
object, it's time to remove the ones that collide!
- Declare a new
bool
variable namedplayerProjectile
- Set the value of the
playerProjectile
variable to check if the currentProjectile
objectp
has aProjectileType
ofProjectileType.Player
- Under that, create an
if
statement - In the condition for the
if
statement, check ifplayerProjectile
is false AND there is a collision between theplayer
and the current projectilep
- In the body of the
if
statement, remove the currentProjectile
objectp
from theprojectiles
list withprojectiles.Remove(p)
- Under the
if
, create anelse if
- In the condition for the
else if
statement, check ifplayerProjectile
is true AND there is a collision between theenemy
and the current projectilep
- In the body of the
else if
, remove the currentProjectile
objectp
from theprojectiles
list withprojectiles.Remove(p)
bool playerProjectile = p.ProjectileType == ProjectileType.Player;
if (!playerProjectile && player.Overlaps(p))
{
projectiles.Remove(p);
}
else if (playerProjectile && enemy.Overlaps(p))
{
projectiles.Remove(p);
}
Run the game, and verify that when the proper projectiles collide with the player or the enemy, they disappear! This is a stepping stone toward destroying enemies and tracking the player's life and score.
Final Code
The final code for this walkthrough is available on GitHub.