flame icon indicating copy to clipboard operation
flame copied to clipboard

(flame) allow specifying when a Component requires repaint

Open alestiago opened this issue 3 years ago • 4 comments

What could be improved

As a flame user I would like to be able to specify which components require a repaint.

For example:

void main() {
  runApp(
    WidgetsApp(
      color: Colors.transparent,
      builder: (_, __) => GameWidget.controlled(gameFactory: _MyGame.new),
    ),
  );
}

class _MyGame extends FlameGame {
  @override
  Color backgroundColor() => Colors.green;

  @override
  Future<void> onLoad() async {
    await super.onLoad();
    add(_CircleComponent(
      position: size.clone() / 2,
      radius: 10,
    ));
  }
}

class _CircleComponent extends CircleComponent {
  _CircleComponent({
    super.position,
    super.radius,
  });

  var _renderCounter = 0;

  @override
  void render(Canvas canvas) {
    super.render(canvas);
    print('rendered ${++_renderCounter} times');
  }
}

The above snippet would shows how the render method is called multiple times. Instead, as a flame user I would like this method to only run once if I know nothing has changed.

As a flame user I would expect that if my game is idle and nothing is changing the render method is not called multiple times (or at least I'm given an API to avoid it).

A proposal would be a RepaintBoundaryComponent. Examples:

// Never repaints its children
RepaintBoundaryComponent(
  shouldRepaint: false,
  children: [],
);

// Only repaints children when property1 or property2 changed
RepaintBoundaryComponent(
  shouldRepaint: property1 != oldProperty1 || property2 != oldProperty2,
  children: [],
);

Why should this be improved

In many occasions the developer is aware that some components would only require to be painted once. Such as game walls, backgrounds and so on.

The performance improvement can be significant if something as such is incorporated. For example, flame games that require to render sprites that are big/high quality are currently painting the image over and over again. If the sprite is never expected to change its position and never expected to be painted on top of it then painting the image once would suffice.

I think there is a distinction between components that don't change their position for the entire lifetime of the game (although they could potentially change visually due to camera changes) and components that don't change their position for the entire lifetime of the game and are also never painted anything on top.

Any risks?

I believe implementing this is complex given how flame currently operates.

More information

alestiago avatar Aug 22 '22 05:08 alestiago

(cc: @jamesblasco)

alestiago avatar Aug 22 '22 05:08 alestiago

I think this is close to impossible, or maybe only possible in very few cases and it would add insane complexity to add this, since Flame wouldn't be able to start off with a fresh canvas each time. Or do you have a solution in mind that you could share?

spydon avatar Aug 22 '22 06:08 spydon

We already have the layer API if you wish to cache results and such.

As @spydon mentioned, if we want to do this we somehow have to reuse the same canvas and clip out parts that we want to repaint, but imho that is a complexity that isn't scalable for something like a game engine.

Considering we already have the layer API that can cache render results, I would suggest looking into that first.

wolfenrain avatar Aug 22 '22 07:08 wolfenrain

IMO very few type of games will benefit from such a system. For example, to actually see any performance improvement from such a system, the component in question needs to satisfy these conditions:

  • Does not animate
  • Does not change position, angle, scale, size
  • Does not use effects/decorators
  • Nothing dynamic gets rendered on top of it
  • Nothing dynamic gets rendered behind it
  • Is big/high quality enough to cause performance issues

It is hard for me to think of any use-case for each a component in games. To be honest, as a game developer, I'd be more worried and confused if the render method is not getting executed every frame 😅

ufrshubham avatar Sep 06 '22 05:09 ufrshubham