anchor.diff:  }
   
   abstract class Collision {
  +  // TODO: Check if this is synchronous.
     StreamController<CollisionEvent> onCollisionController =
         new StreamController<CollisionEvent>();
     Stream<CollisionEvent> get onCollision =>
  
positive.code:   Aabb2 get hitbox;
  }
  
  class Side {
    static const int TOP = 1;
    static const int BOTTOM = 2;
  
negative.code:     }
    }
  }
  
  class SweptBoxCollision extends Collision {
    Body body1;
    Body body2;
  
    Aabb2 _box1 = new Aabb2();
    Aabb2 _box2 = new Aabb2();
    Vector2 _entryDistance = new Vector2.zero();
    Vector2 _exitDistance = new Vector2.zero();
    Vector2 _entryTime = new Vector2.zero();
    Vector2 _exitTime = new Vector2.zero();
  
    SweptBoxCollision(this.body1, this.body2);
  
    void check() {
      _box1.copyFrom(body1.hitbox);
      _box2.copyFrom(body2.hitbox);
  
      _box1.min.sub(body1.speed);
      _box1.max.sub(body1.speed);
  
      if (body1.speed.x > 0) {
        _entryDistance.x = _box2.min.x - _box1.max.x;
        _exitDistance.x = _box2.max.x - _box1.min.x;
      } else {
        _entryDistance.x = _box1.min.x - _box2.max.x;
        _exitDistance.x = _box1.max.x - _box2.min.x;
      }
  
      if (body1.speed.y > 0) {
        _entryDistance.y = _box2.min.y - _box1.max.y;
        _exitDistance.y = _box2.max.y - _box1.min.y;
      } else {
        _entryDistance.y = _box1.min.y - _box2.max.y;
        _exitDistance.y = _box1.max.y - _box2.min.y;
      }
  
      if (body1.speed.x == 0.0) {
        _entryTime.x = double.INFINITY;
        _exitTime.x = double.INFINITY;
      } else {
        _entryTime.x = _entryDistance.x / body1.speed.x;
        _exitTime.x = _exitDistance.x / body1.speed.x;
      }
  
      if (body1.speed.y == 0.0) {
        _entryTime.y = double.INFINITY;
        _exitTime.y = double.INFINITY;
      } else {
        _entryTime.y = _entryDistance.y / body1.speed.y;
        _exitTime.y = _exitDistance.y / body1.speed.y;
      }
  
      double entryTime = max(_entryTime.x, _entryTime.y);
      double exitTime = min(_entryTime.x, _entryTime.y);
  
      if (entryTime > exitTime ||
          _entryTime.x < 0.0 && _entryTime.y < 0.0 ||
          _entryTime.x > 1.0 ||
          _entryTime.y > 1.0) {
  
        return null;
      } else {
        int side;
        if (_entryTime.x > _entryTime.y) {
          if (_entryDistance.x < 0.0) {
            side = Side.RIGHT;
          } else {
            side = Side.LEFT;
          }
        } else {
          if (_entryDistance.y < 0.0) {
            side = Side.BOTTOM;
          } else {
            side = Side.TOP;
          }
        }
        onCollisionController.add(
            new CollisionEvent(body1, side, body2, Side.BOTTOM));
      }
    }
  }
  