flame icon indicating copy to clipboard operation
flame copied to clipboard

Please add a callback method to receive notifications after a component has been removed.

Open FluffyBunniesTasteTheBest opened this issue 3 years ago • 1 comments

It would be convenient if Component would provide a callback to receive a notification once the Component has been removed from the scene.

Imagine, for example, an object pool of Bullets: Each bullet is just a SpriteComponent. Right now, the following code is necessary to return a Bullet to its pool:

class Bullet extends  SpriteComponent {
    ObjectPool _objectPool;

    Bullet(this._objectPool);

    void onRemove() {
      _objectPool.returnToPool(this); 
    }
}

// The bullet would then be used like:
ObjectPool<Bullet> bulletPool;

Bullet newBullet = bulletPool.getInstance();
// Shoot something! - As Bruce Willis would say.

With an onRemoved() callback, the above code could be shortened to:

ObjectPool<SpriteComponent> bulletPool;

SpriteComponent newBullet = bulletPool.getInstance()..onRemovedCallback = () {
    bulletPool.returnToPool(newBullet); // This is just an illustration. Attaching the callback should actually be done in ObjectPool.
};
// Shoot something! - As Schwarzenegger did.

Please note that the above example is just some pseudo code to illustrate the idea.

The big advantages of the callback approach is that it would lead to shorter and cleaner code. Returning to the pool could for example be done at the object pool itself, keeping the code that belongs together in the same file (the object pool) rather than, how it is right now, split over two files (the object pool and the bullet class).

Nothing groundbreaking new, but it would make Flame-Engine more convenient.

What you can do here is to create a mixin

mixin Poolable<T> on Component {
  @override
  void onRemove() {
    (findParent<Game>() as HasObjectPools).pool<T>.returnObject(this);
    super.onRemove();
  }
}
mixin HasObjectPools on Game {
  Map<Type, ObjectPool<Type>> _objectPools;

  ObjectPool<T> get pool<T>() {
    if (!_objectPools.containsKey(T)) {
      _objectPools[T] = ObjectPool<T>();
    }
    return _objectPools[T] as ObjectPool<T>;
  }
}

Then your Bullet class will be simply

class Bullet extends SpriteComponent with Poolable<Bullet> {
  Bullet(): super.fromImage(Images.fromCache('bullet.png'));
}

st-pasha avatar Jan 12 '22 21:01 st-pasha