Search code examples
flutterflame

How can I replace Flutter widgets with canvas and vice versa?


I'm making a 2D game using Flutter Flame. The library uses a canvas, as seen here:

start() {
  var previous = Duration.ZERO;

  window.onBeginFrame = (now) {
    var recorder = new PictureRecorder();
    var canvas = new Canvas(
        recorder,
        new Rect.fromLTWH(
            0.0, 0.0, window.physicalSize.width, window.physicalSize.height));

    Duration delta = now - previous;
    if (previous == Duration.ZERO) {
      delta = Duration.ZERO;
    }
    previous = now;

    var t = delta.inMicroseconds / Duration.MICROSECONDS_PER_SECOND;

    update(t);
    render(canvas);

    var deviceTransform = new Float64List(16)
      ..[0] = window.devicePixelRatio
      ..[5] = window.devicePixelRatio
      ..[10] = 1.0
      ..[15] = 1.0;

    var builder = new SceneBuilder()
      ..pushTransform(deviceTransform)
      ..addPicture(Offset.zero, recorder.endRecording())
      ..pop();

    window.render(builder.build());
    window.scheduleFrame();
  };

  window.scheduleFrame();
}

It's worth noting that Flutter Flame uses a custom BindingBase, similar to how the Widgets work.

class _CustomBinder extends BindingBase with ServicesBinding {}

This works great for the game, but I was hoping to use real flutter widgets for the main menu, settings pages, etc.

Is there a way to swap between these two contexts?

To provide an idea of what I'm looking for, I'd like there to exist these two functions:

loadHomeScreen(); // replaces the canvas, if any, with Flutter widgets
loadCanvasScene(); // replaces the Flutter widgets with the canvas

Solution

  • In the newer versions of Flame (0.8.x), the game becomes a regular Widget, and thus support for apps that have regular widgets for menus and settings.

    Start as a regular app, and in one of your build methods, add the widget of your game implementation:

    class MyGame extends BaseGame {
      // your game here
    }
    
    // in your game screen class
    
    final MyGame game = new MyGame();
    
    @override
    Widget build(BuildContext context) {
      return game.widget;
    }
    

    For a more in-depth example, check this complete game, built using the latest version of Flame. The specific code you are looking for, that switches between game and app is here.