Game Widget¶
The GameWidget is the bridge between Flutter and Flame. Since Flame games are not Flutter widgets
by themselves, the GameWidget wraps a Game instance and places it into the Flutter widget tree,
just like any other widget. This lets
you combine a full-screen game with Flutter UI elements (navigation bars, overlays, dialogs) or
embed a game as only part of your app’s layout.
The GameWidget is a Flutter widget which is used to insert a Game
instance into the Flutter widget tree.
The GameWidget is sufficiently feature-rich to run as the root of your
Flutter application. Thus, the simplest way to use GameWidget is like
this:
void main() {
runApp(
GameWidget(game: MyGame()),
);
}
At the same time, GameWidget is a regular Flutter widget, and can be
inserted arbitrarily deep into the widget tree, including the possibility
of having multiple GameWidgets within a single app.
The layout behavior of this widget is that it will expand to fill all available space. Thus, when used as a root widget it will make the app full-screen. Inside any other layout widget it will take as much space as possible.
In addition to hosting a Game instance, the GameWidget also provides
some structural support, with the following features:
loadingBuilderto display something while the game is loading;errorBuildershown if the game throws an error;backgroundBuilderto draw some decoration behind the game;overlayBuilderMapto draw one or more widgets on top of the game.
It should be noted that GameWidget does not clip the content of its
canvas, which means the game can potentially draw outside of its boundaries
(not always, depending on which camera is used). If this is not desired,
then consider wrapping the widget in Flutter’s ClipRect.
Constructors¶
Renders the provided game instance.
A GameWidget which will create and own a Game instance, using the
provided gameFactory.
This constructor can be useful when you want to put GameWidget into
another widget, but would like to avoid the need to store the game’s
instance yourself. For example:
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(20),
child: GameWidget.controlled(
gameFactory: MyGame.new,
),
);
}
}
Properties¶
The game instance which this widget will render, if it was provided with
the default constructor. Otherwise, if the GameWidget.controlled
constructor was used, this will always be null.
A function that creates a Game that this widget will render.
The text direction to be used in text elements in a game.
Builder to provide a widget which will be displayed while the game is
loading. By default this is an empty Container.
If set, errors during the game loading will be caught and this widget will be shown. If not provided, errors are propagated normally.
Builder to provide a widget tree to be built between the game elements and
the background color provided via Game.backgroundColor.
A collection of widgets that can be displayed over the game’s surface.
These widgets can be turned on-and-off dynamically from within the game
via the Game.overlays property.
void main() {
runApp(
GameWidget(
game: MyGame(),
overlayBuilderMap: {
'PauseMenu': (context, game) {
return Container(
color: const Color(0xFF000000),
child: Text('A pause menu'),
);
},
},
),
);
}
The list of overlays that will be shown when the game starts (but after it was loaded).
The FocusNode to control the games focus to receive event inputs. If omitted, defaults to an internally controlled focus node.
Whether the focusNode requests focus once the game is mounted.
Defaults to true.
The shape of the mouse cursor when it is hovering over the game canvas.
This property can be changed dynamically via Game.mouseCursor.
Whether the game should assume the behavior of a RepaintBoundary,
defaults to true.
How the game widget behaves during hit testing.
HitTestBehavior.opaque(default): the game absorbs all pointer events on its surface, preventing widgets behind it from receiving them.HitTestBehavior.deferToChild: the game only intercepts events at positions where a component with event callbacks (e.g.TapCallbacks) exists. Events at other positions pass through to widgets behind.HitTestBehavior.translucent: the game receives events where it has event-handling components, but always allows widgets behind it to be hit-tested as well.
Hit Test Behavior¶
The behavior argument controls how the GameWidget participates in Flutter’s hit testing. This
determines whether pointer events (taps, drags, etc.) are absorbed by the game or allowed to pass
through to widgets underneath it in the widget tree.
There are three possible values from Flutter’s HitTestBehavior:
HitTestBehavior.opaque(default): The game absorbs all pointer events on its entire surface, preventing any widgets behind it from receiving them. This is the classic behavior where the game acts as a solid layer.HitTestBehavior.deferToChild: The game only intercepts events at positions where a component with event callbacks (e.g.TapCallbacks) exists. Events at positions with no interactive components pass through to widgets behind theGameWidget. This is useful when layering a game on top of Flutter UI and you want the underlying widgets to remain interactive in areas the game doesn’t need to handle.HitTestBehavior.translucent: The game receives events where it has event-handling components, but always allows widgets behind it to be hit-tested as well. Both the game and the widgets behind it can receive the same event.
Allowing taps to pass through¶
A common use case is placing a GameWidget on top of other Flutter widgets in a Stack. By
default, the game will block all interaction with the widgets underneath. To let taps pass through
to those widgets, set behavior to HitTestBehavior.deferToChild:
Widget build(BuildContext context) {
return Stack(
children: [
// Flutter widgets underneath
Center(
child: ElevatedButton(
onPressed: () => print('Button tapped!'),
child: const Text('Tap me'),
),
),
// Game on top, letting taps pass through
Positioned.fill(
child: GameWidget(
game: MyGame(),
behavior: HitTestBehavior.deferToChild,
),
),
],
);
}
In this setup, tapping an area with no interactive game components will reach the ElevatedButton
behind the game. Tapping a game component that uses TapCallbacks will be handled by the game
instead.
Note
When using deferToChild or translucent, FlameGame determines whether a
position has an interactive component by traversing the component tree via
componentsAtPoint. Games that directly extend the low-level Game class
report a hit on their entire surface by default; override
containsEventHandlerAt to customize this.