Skip to content

Commit

Permalink
ref: use pauseEngine and resumeEngine
Browse files Browse the repository at this point in the history
  • Loading branch information
adil192 committed Aug 24, 2023
1 parent d12799f commit a6652a5
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 120 deletions.
46 changes: 2 additions & 44 deletions packages/flame/lib/src/game/game.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,6 @@ abstract mixin class Game {
late final GestureDetectorBuilder gestureDetectors =
GestureDetectorBuilder(refreshWidget)..initializeGestures(this);

/// The game's lifecycle state.
///
/// This is used to discard the first [update] call after the app was in the
/// background to avoid a massive `dt` value.
///
/// See [GameLifecycleState] for more details.
GameLifecycleState gameLifecycleState = GameLifecycleState.foregrounded;

/// This should update the state of the game.
void update(double dt);

Expand Down Expand Up @@ -145,27 +137,9 @@ abstract mixin class Game {
/// This is the lifecycle state change hook; every time the game is resumed,
/// paused or suspended, this is called.
///
/// You may wish to use [gameLifecycleState] instead of [state]
/// to use more game-specific lifecycle states.
///
/// Check [AppLifecycleState] and [GameLifecycleState]
/// for details about the events received.
@mustCallSuper
/// The default implementation does nothing; override to use the hook.
/// Check [AppLifecycleState] for details about the events received.
void lifecycleStateChange(AppLifecycleState state) {
switch (state) {
case (AppLifecycleState.resumed || AppLifecycleState.inactive)
when gameLifecycleState == GameLifecycleState.backgrounded:
// We are coming back from background.
gameLifecycleState = GameLifecycleState.foregrounding;
break;
case (AppLifecycleState.paused || AppLifecycleState.detached)
when gameLifecycleState != GameLifecycleState.backgrounded:
// We are going to background.
gameLifecycleState = GameLifecycleState.backgrounded;
break;
default:
break;
}
}

/// Method to perform late initialization of the [Game] class.
Expand Down Expand Up @@ -390,19 +364,3 @@ abstract mixin class Game {
gameStateListeners.forEach((callback) => callback());
}
}

enum GameLifecycleState {
/// The game is backgrounded.
///
/// This corresponds to [AppLifecycleState.paused] and [AppLifecycleState.detached].
backgrounded,

/// The game has been foregrounded but the first update should be
/// disregarded if `pauseWhenBackgrounded` is true.
foregrounding,

/// The game is foregrounded.
///
/// This corresponds to [AppLifecycleState.resumed] and [AppLifecycleState.inactive].
foregrounded,
}
44 changes: 27 additions & 17 deletions packages/flame_forge2d/lib/forge2d_game.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,10 @@ class Forge2DGame extends FlameGame {
///
/// Defaults to false.
bool pauseWhenBackgrounded;
bool _pausedBecauseBackgrounded = false;

@override
void update(double dt) {
if (!shouldUpdate()) {
return;
}

super.update(dt);
world.stepDt(dt);
}
Expand All @@ -52,19 +49,32 @@ class Forge2DGame extends FlameGame {
return screenToWorld(position)..y *= -1;
}

@protected
bool shouldUpdate() {
switch (gameLifecycleState) {
case GameLifecycleState.backgrounded:
// Don't update when backgrounded
return !pauseWhenBackgrounded;
case GameLifecycleState.foregrounding:
// Discard the first `update` call after the app was in the background
// to avoid a massive [dt] value.
gameLifecycleState = GameLifecycleState.foregrounded;
return !pauseWhenBackgrounded;
case GameLifecycleState.foregrounded:
return true;
@override
@mustCallSuper
void lifecycleStateChange(AppLifecycleState state) {
switch (state) {
case AppLifecycleState.resumed:
case AppLifecycleState.inactive:
if (_pausedBecauseBackgrounded) {
resumeEngine();
}
case AppLifecycleState.paused:
case AppLifecycleState.detached:
case AppLifecycleState.hidden:
if (pauseWhenBackgrounded) {
pauseEngine();
_pausedBecauseBackgrounded = true;
}
}
}
@override
void pauseEngine() {
_pausedBecauseBackgrounded = false;
super.pauseEngine();
}
@override
void resumeEngine() {
_pausedBecauseBackgrounded = false;
super.resumeEngine();
}
}
66 changes: 7 additions & 59 deletions packages/flame_forge2d/test/forge2d_game_test.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'package:flame/components.dart';
import 'package:flame/game.dart';
import 'dart:ui' show AppLifecycleState;

import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:test/test.dart';

Expand All @@ -10,17 +10,6 @@ class _TestForge2dGame extends Forge2DGame {
}
}

class _TestComponent extends Component {
_TestComponent({
required this.onUpdate,
});

final void Function() onUpdate;

@override
void update(double dt) => onUpdate.call();
}

void main() {
group(
'Test corresponding position on screen and in the Forge2D world',
Expand Down Expand Up @@ -69,54 +58,13 @@ void main() {

group('Game lifecycle state:', () {
test('update should only be called if foregrounded', () async {
var updateCalled = false;
void onUpdate() => updateCalled = true;

final game = _TestForge2dGame();
final component = _TestComponent(onUpdate: onUpdate);
await game.add(component);
const dt = 1 / 60;

await game.onLoad();

game.gameLifecycleState = GameLifecycleState.backgrounded;
game.update(dt);
expect(
updateCalled,
false,
reason: 'Update should not run when app is backgrounded',
);
expect(
game.gameLifecycleState,
GameLifecycleState.backgrounded,
reason: 'Game should still be backgrounded',
);

game.gameLifecycleState = GameLifecycleState.foregrounding;
game.update(dt);
expect(
updateCalled,
false,
reason: 'Update should not run on first foregrounded update',
);
expect(
game.gameLifecycleState,
GameLifecycleState.foregrounded,
reason: 'Game should be foregrounded',
);

game.gameLifecycleState = GameLifecycleState.foregrounded;
game.update(dt);
expect(
updateCalled,
true,
reason: 'Update should run when app is foregrounded',
);
expect(
game.gameLifecycleState,
GameLifecycleState.foregrounded,
reason: 'Game should be foregrounded',
);
game.lifecycleStateChange(AppLifecycleState.paused);
expect(game.paused, true);

game.lifecycleStateChange(AppLifecycleState.resumed);
expect(game.paused, false);
});
});
}

0 comments on commit a6652a5

Please sign in to comment.