Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix!: Update should be called before render in first tick #2714

Merged
merged 7 commits into from
Sep 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions packages/flame/lib/src/game/game_widget/game_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,9 @@ class GameWidgetState<T extends Game> extends State<GameWidget<T>> {
await onLoad;
}
game.mount();
if (!game.paused) {
game.update(0);
}
})();

Future<void>? _loaderFuture;
Expand Down Expand Up @@ -362,6 +365,12 @@ class GameWidgetState<T extends Game> extends State<GameWidget<T>> {
Container();
}
currentGame.onGameResize(size);
// This should only be called if the game has already been
// loaded (in the case of resizing for example), since
// update otherwise should be called after onMount.
if (!currentGame.paused && currentGame.isAttached) {
currentGame.update(0);
}
return FutureBuilder(
future: loaderFuture,
builder: (_, snapshot) {
Expand Down
Binary file modified packages/flame/test/_goldens/snapshot_test_3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 11 additions & 5 deletions packages/flame/test/components/mixins/snapshot_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ void main() {
'Snapshot should be created once',
_SnapshotTestGame.new,
(game) async {
final snapshotComponent = game.snapshotComponent;
await game.ready();
final snapshotComponent = game.snapshotComponent;

// Wait a few frames
final canvas = Canvas(PictureRecorder());
Expand All @@ -39,8 +39,8 @@ void main() {
'Should render normally when renderSnapshot is false',
() => _SnapshotTestGame(renderSnapshot: false),
(game) async {
final snapshotComponent = game.snapshotComponent;
await game.ready();
final snapshotComponent = game.snapshotComponent;

// Wait a few frames
const framesToWait = 5;
Expand Down Expand Up @@ -73,14 +73,15 @@ void main() {
'Should generate a snapshot when takeSnapshot is called',
(tester) async {
final game = _SnapshotTestGame(renderSnapshot: false);
final snapshotComponent = game.snapshotComponent;
const framesToWait = 5;
late final _MockSnapshotComponent snapshotComponent;

await tester.runAsync(() async {
final widget = GameWidget(game: game);
await tester.pumpWidget(widget);
await tester.pump();
await game.ready();
snapshotComponent = game.snapshotComponent;

// Wait a few frames
final recorder = PictureRecorder();
Expand Down Expand Up @@ -116,13 +117,14 @@ void main() {
'Should generate a transformed image',
(tester) async {
final game = _SnapshotTestGame(renderSnapshot: false);
final snapshotComponent = game.snapshotComponent;
late final _MockSnapshotComponent snapshotComponent;

await tester.runAsync(() async {
final widget = GameWidget(game: game);
await tester.pumpWidget(widget);
await tester.pump();
await game.ready();
snapshotComponent = game.snapshotComponent;

// Force a frame
final canvas = Canvas(PictureRecorder());
Expand Down Expand Up @@ -173,8 +175,12 @@ void main() {

class _SnapshotTestGame extends FlameGame {
late final _MockSnapshotComponent snapshotComponent;
bool renderSnapshot;

_SnapshotTestGame({bool renderSnapshot = true}) {
_SnapshotTestGame({this.renderSnapshot = true});

@override
Future<void> onLoad() async {
// Add a snapshot-enabled component that has it's own rendered content
snapshotComponent = _MockSnapshotComponent()
..size = Vector2(200, 200)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@ class _MyGame extends FlameGame {
events.add('onMount');
}

@override
void update(double dt) {
super.update(dt);
events.add('update');
}

@override
void render(Canvas canvas) {
super.render(canvas);
events.add('render');
}

@override
void onRemove() {
super.onRemove();
Expand Down Expand Up @@ -207,12 +219,27 @@ void main() {
state.causeResize();

await tester.pump();
expect(events, ['onGameResize']); // no onRemove
expect(events, ['onGameResize', 'update', 'render']); // no onRemove
final game =
tester.allWidgets.whereType<GameWidget<_MyGame>>().first.game;
expect(game?.children, everyElement((Component c) => c.parent == game));
});

testWidgets('update is not called when game is paused', (tester) async {
final events = <String>[];
await tester.pumpWidget(_MyContainer(events));

events.clear();
tester.allWidgets
.whereType<GameWidget<_MyGame>>()
.first
.game
?.pauseEngine();
await tester.pump();
await tester.pump();
expect(events, ['render']);
});

testWidgets('all events are executed in the correct order', (tester) async {
final events = <String>[];
await tester.pumpWidget(_MyApp(events));
Expand All @@ -239,10 +266,15 @@ void main() {
'onGameResize',
'onLoad',
'onMount',
'update',
'render',
'update',
'onRemove',
'onDispose',
'onGameResize',
'onMount',
'update',
'render',
],
);
});
Expand Down
26 changes: 18 additions & 8 deletions packages/flame/test/game/game_widget/game_widget_pause_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,21 @@ class _WrapperState extends State<_Wrapper> {
}

class _MyGame extends FlameGame {
int callCount = 0;
int updateCount = 0;
int renderCount = 0;
double timePassed = 0;

@override
void update(double dt) {
super.update(dt);
timePassed += dt;
updateCount++;
}

callCount++;
@override
void render(Canvas canvas) {
super.render(canvas);
renderCount++;
}
}

Expand All @@ -86,7 +92,8 @@ void main() {
// shouldn't run another frame on the game
await tester.pump();

expect(game.callCount, equals(2));
// Remember that there is one initial update(0) called.
expect(game.updateCount, equals(3));
},
);

Expand All @@ -105,7 +112,8 @@ void main() {
game.resumeEngine();
await tester.pump();

expect(game.callCount, equals(3));
// Remember that there is one initial update(0) called.
expect(game.updateCount, equals(4));
},
);

Expand All @@ -121,7 +129,8 @@ void main() {
await tester.tap(find.text('Toggle'));
await tester.pumpAndSettle();

expect(game.callCount, equals(2));
// Remember that there is one initial update(0) called.
expect(game.updateCount, equals(3));
},
);

Expand All @@ -132,7 +141,7 @@ void main() {
await tester.pump();
await tester.pump();

expect(game.callCount, equals(0));
expect(game.updateCount, equals(0));
},
);

Expand All @@ -149,7 +158,7 @@ void main() {
await tester.pump();
await tester.pump();

expect(game.callCount, equals(2));
expect(game.updateCount, equals(2));
},
);

Expand All @@ -173,7 +182,8 @@ void main() {
await tester.pump(const Duration(seconds: 100));
await tester.pump(frameLength);

expect(game.callCount, equals(4));
// Remember that there is one initial update(0) after mount
expect(game.updateCount, equals(5));
expect(game.timePassed, equals(3));
},
);
Expand Down