04. Colliding Entities against TileShapeCollections

Introduction

This walk-through shows how to perform collision between entities and TileShapeCollection  instances. The two most common types tile-based collisions are:

  1. Solid collision – collision which prevents a character from passing through a tile, such as solid walls in a maze
  2. True/false tests – used to perform additional logic when  collisions occur, such as dealing damage to a character when touching spikes

We’ll be looking at both types.

Creating an Entity

For this guide, we’ll create an entity to test our collision code. This entity will need to be collidable (implements ICollidable) and needs logic for movement in response to input.

To create a new entity:

  1. In Glue, right-click on the Entities folder
  2. Select Add Entity

  3. Enter the name Player
  4. Check the Circle checkbox to give the entity a circle collision object
  5. Verify that ICollidable is checked – this should happen automatically when Circle is checked
  6. Click OK

The new entity should appear in the Entities folder in Glue.

Since the Player entity has its ImplementsICollidable set to true, any shape (Circle, Polygon, AxisAlignedRectangle) in the entity will be used in collision functions.

Adding Entity Movement

To make the entity move in response to keyboard input:

  1. Open the Player.cs  file in Visual Studio
  2. Modify the CustomActivity  method as shown in the following code snippet:

Adding Player to GameScreen

Our entity is ready to go – we just need to add it to GameScreen. Note that we’re adding the Player to the GameScreen rather than Level1 because we want every level to have a player.

To add the entity to GameScreen, drag+drop the entity onto the screen:

DragEntityOnScreen2

The Player will now appear on the game screen and can move with the arrow keys.

Performing Solid Collision

Solid collision can be used to prevent an entity from passing through solid objects on a tile map. In this example we’ll be colliding the Player instance against tiles that we set up to have rectangle collision in the previous tutorial.

Note that we are going to write this code in Level1.cs for the sake of simplicity.

First we’ll need to make the PlayerInstance accessible from the Level1 Screen:

  1. Expand GameScreen
  2. Expand Objects under GameScreen
  3. Select PlayerInstance
  4. Click the Properties tab
  5. Set ExposedInDerived to True

Now we can access PlayerInstance in Level1. We’ll use the CollisionManager extension methods for TileShapeCollections:

  1. Open Level1.cs in Visual Studio
  2. Modify CustomInitialize and the using statement as shown in the code below:

The Player will no longer be able to move through solid collision:

SolidCollision

Note that the collision relationship can be used just like collision relationships created between standard objects such as entity vs. entity. For example, we can handle when a collision occurs by subscribing to the CollisionOccured  event as shown in the following code:

Common Collision Code

The code above is useful for showing how to write collision code, but it suffers from being written in our Level1.cs file. A real game may contain multiple levels and we want to avoid duplicating the collision code in every screen. Instead, we’ll want our collision code to live in the GameScreen.cs file, at least if it’s intended to be common functionality.

This introduces a little bit of complexity – we want the collision logic in GameScreen, but we have our level TMX file (and assocaited collision) in the Level1 screen. We can solve this problem by creating a collision object in GameScreen, then assigning it in Level1.

First, we’ll define a TileShapeCollection in GameScreen:

  1. Expand GameScreen in Glue
  2. Right-click on Objects
  3. Select Add Object
  4. Verify FlatRedBall or Custom Type is selected
  5. Select the TileShapeCollection type
  6. Enter the name SolidCollision
  7. Click OK

We need to set the SetByDerived property to True so that derived screens (Level1) can create the object from its TMX file:

  1. Select the newly-created SolidCollision object
  2. Select the Properties tab
  3. Set SetByDerived to True

Notice that once this value is set, the SolidCollision object will appear in Level1. It is colored yellow to indicate that it is defined in a base screen (GameScreen) and can be set by this screen. To set this from the TMX file:

  1. Expand Level1 in Glue
  2. Select the (yellow) SolidCollision
  3. Click the Properties tab

  4. Scroll to the bottom of the properties list
  5. Change SourceType to File
  6. Change SourceFile to
  7. Change SourceName to

Now our SolidCollision object is assigned in Level1, but we can write code against it in GameScreen. To write general code against this object:

  1. Clear out any collision code from Level1.cs  (which was written earlier in this tutorial)
  2. Open GameScreen.cs
  3. Modify CustomInitialize so it contains the following code:
 

The game should behave the same as before, except now the code is in the core GameScreen which means if will be shared when we add more levels in a future tutorial.

[+]Alternative Approach - Populating TileShapeCollection In Code

So far this tutorial has created a TileShapeCollection by reading from a layer. While this requires no code, it does place some limitations:

  • A TileShapeCollection can only be created from a single layer. Some games may want to create collision from multiple layers into a single TileShapeCollection.
  • All collision from a single layer can only be added to a single TileShapeCollection. Some games may paint tiles with different types of collision in a single layer.

TileShapeCollections can be constructed and populated in code in a variety of ways. For example, collisions can be created from tiles by the properties added to those tiles.

First, tiles need to be given properties for any collidable tiles. To do this:

  1. Open the Level1Tmx.tmx in Tiled
  2. Click the Edit button to edit the tileset

  3. Select a tile which will be painted and have collision

  4. Instead of adding collision through the Tile Collision Editor, we’ll instead add a property. Click the + button to add a custom property

  5. Enter a name for the property. This property will be used in code to add collision. For example, we’ll add a property HasCollision. Note that we will simply use the presence of this property to add collision so the type doesn’t matter.

  6. Click OK to add the new property.

This can be repeated for any tiles which need to have collision.

Next we’ll add collision for these tiles in code. We can either add collision to a TileShapeCollection created in Glue or we can create our own in code. For the sake of this example we’ll create one completely in code. To do this, modify the Level1.cs file to contain the following code (only code relevant to creating the TileShapeCollection in code is shown).

Keep in mind:

  • AddCollisionFromTilesWithProperty can be called multiple times, adding additional shapes. This allows you to create one TileShapeCollection from many types of tiles.
  • Your screen can contain any number of TileShapeCollections. Some games may need different TileShapeCollections to create different types of behavior. For example, a level may contain:
    • SpikesCollision (kills the player)
    • HealingCollision (heals the player’s health when colliding)
    • DeepGrassCollision (slows the player’s movement when colliding)
    • WaterCollision (makes the player’s movement switch to “swimming”)
  • TileShapeCollections can be created in code or in Glue. TileShapeCollections can even be defined in the base GameScreen, then assigned in a derived (level) screen’s CustomInitialize.
  • TileShapeCollection provides many methods for creating collision, including placing collision one tile at a time. See the TileShapeCollection class for more information.

Conclusion

This guide shows how to work with TileShapeCollection  to perform solid collision (collision which prevents an entity from passing through the collision area) and non-solid collision (collision which is used to drive custom logic).

A typical game may include many TileShapeCollection  instances for different types of collision.

Although we didn’t cover it in this guide, the TileShapeCollection class uses axis-based partitioning for efficient collision. In most cases, even mobile platforms will be able to perform collision against TileShapeCollection  instances with tens of thousands of rectangles with very little impact on performance.

Developers interested in the details of this partitioning are encouraged to look at the TileShapeCollection  source code.