Collision Detection 💥

Flame comes with a powerful built-in collision detection system, but this API is not strongly typed. Components always get the colliding component as a PositionComponent and developers need to manually check what type of class it is.

flame_behaviors is all about enforcing a strongly typed API. It provides a special behavior called CollisionBehavior that describes the type of entity being targeted for collision. It does not, however, do any real collision detection. That is done by the PropagatingCollisionBehavior.

The PropagatingCollisionBehavior handles the collision detection by registering a hitbox on the parent entity. When that hitbox has a collision, the PropagatingCollisionBehavior checks if the component that the parent entity is colliding with contains the target entity type specified in CollisionBehavior.

There are two main benefits of letting the PropagatingCollisionBehavior handle the collision detection, the first and most important one is performance. By only registering collision callbacks on the entities themselves, the collision detection system does not have to go through any “collidable” behaviors, for which there could be many per entity. We only do that now if we confirm a collision has happened.

The second benefit is that it allows for separation of concerns. Each CollisionBehavior handles a specific collision use case and ensures that the developer does not have to write a bunch of if statements in one big method to figure out what it is colliding with.

A good use case of this collisional behavior pattern can be seen in the flame_behaviors example

class MyEntityCollisionBehavior
    extends CollisionBehavior<MyCollidingEntity, MyParentEntity> {
  @override
  void onCollisionStart(
    Set<Vector2> intersectionPoints,
    MyCollidingEntity other,
  ) {
    // We are starting colliding with MyCollidingEntity
  }

  @override
  void onCollisionEnd(MyCollidingEntity other) {
    // We stopped colliding with MyCollidingEntity
  }
}

class MyParentEntity extends Entity {
  MyParentEntity()
    : super(
        behaviors: [
          PropagatingCollisionBehavior(RectangleHitbox()),
          MyEntityCollisionBehavior(),
        ],
      );
   ...   
}