The Genesis and Rebirth of flame_riverpod

The Genesis and Rebirth of flame_riverpod
This is fire.

Genesis

Flame is a Dart package that provides solutions to a number of problems in the game development domain.

Riverpod is a Dart package that helps application developers manage state, maintain a separation of concerns, increase the testability of their code, and more.

You might want to use Riverpod in conjunction with Flame in scenarios like:

  • Performing asynchronous tasks that your Flame game depends on, such as when making requests to a web service, or loading data from a file.
  • Sharing data from parts of your application that are not game-like, e.g. profile information entered by a user prior to beginning a game.

flame_riverpod can help.

I wrote flame_riverpod shortly after becoming acquainted with Flame and discovering that the only state management bridge package at the time was flame_bloc. At the time, based on the experience I had with BLoC, I did not feel that it was a good fit for my use case - quick prototyping.


I think BLoC is a respectable choice for industrial-grade applications.

Putting differences of opinion in how an application should be structured, I think it is reasonable to make the comment that with BLoC, there is a relatively high upfront cost paid during development and a relatively low marginal cost of writing tests.

One consequence of this is that it becomes harder to justify not writing tests.


Shortly thereafter, I published the first version of flame_riverpod, my first Dart package.

It had a number of limitations that made it suboptimal for use in a production app - nevertheless, the bar was cleared. Flame Components could access Riverpod Providers.

Rebirth

Several months later, after an exchange with the maintainers of Flame and Riverpod, I published flame_riverpod 5.0.0, with a whole new API. The API is comprised of:

  • RiverpodAwareGameWidget (and its State object, RiverpodAwareGameWidgetState)
  • RiverpodGameMixin
  • RiverpodComponentMixin
  • ComponentRef

RiverpodAwareGameWidget is a GameWidget - the point of difference compared to the vanilla GameWidget is that the RiverpodAwareGameWidget requires a GlobalKey which is used internally.

Its companion State object, RiverpodAwareGameWidgetState is responsible for invoking the aggregated list of all Riverpod API calls associated with the Flame game inside its build method. This list is stored on RiverpodGameMixin.

ComponentRef represents the subset of the Riverpod WidgetRef API that is accessible to Components.


The part that game developers will interact with most frequently is RiverpodComponentMixin.

RiverpodComponentMixin contains a reference to an aggregated list of Riverpod API calls that are associated with the current component.

This mixin aims to manage these callbacks in accordance with the Component lifecycle on behalf of the user. Ideally, when the Component is mounted, the callbacks are added to the GameWidget build method. When the Component is removed, the callbacks are removed too.

The order of operations in a Component that uses the RiverpodComponentMixin is of great importance. If the mixin's onMount method (super.onMount in the context of a custom Component) is called before addToGameWidgetBuild, or if it is not called at all, the mixin cannot manage the lifecycle of callbacks (e.g. ref.watch, ref.listen, etc.) on behalf of the user. I recommend taking a look at the example project or the implementation of the package itself.


I’m relatively pleased with the new API and I hope it helps bring more games to life.

Shortly after the release of flame_riverpod 5.0.0, I transferred the package to the Flame Engine team and so it has come to pass that Riverpod is now officially supported by Flame.

Special thanks to Lucas Klingsbo and Remi Rousselet.