Skip to content

Commit

Permalink
fix: HasGameReference should default to FlameGame (#2710)
Browse files Browse the repository at this point in the history
It doesn't make any sense for HasGameReference to have Game as a base instead of FlameGame since the mixin is on Component and clearly in a component tree context, so this PR sets the base to be FlameGame (like HasGameRef).
  • Loading branch information
spydon committed Sep 10, 2023
1 parent a097cc0 commit 93dcb3a
Show file tree
Hide file tree
Showing 10 changed files with 36 additions and 39 deletions.
7 changes: 2 additions & 5 deletions doc/tutorials/klondike/app/lib/step4/components/card.dart
Expand Up @@ -3,7 +3,6 @@ import 'dart:ui';

import 'package:flame/components.dart';
import 'package:flame/events.dart';
import 'package:flame/game.dart';
import '../klondike_game.dart';
import '../pile.dart';
import '../rank.dart';
Expand Down Expand Up @@ -242,10 +241,8 @@ class Card extends PositionComponent with DragCallbacks {
if (!_isDragging) {
return;
}
final cameraZoom = (findGame()! as FlameGame)
.firstChild<CameraComponent>()!
.viewfinder
.zoom;
final cameraZoom =
findGame()!.firstChild<CameraComponent>()!.viewfinder.zoom;
final delta = event.delta / cameraZoom;
position.add(delta);
attachedCards.forEach((card) => card.position.add(delta));
Expand Down
21 changes: 14 additions & 7 deletions packages/flame/lib/src/components/core/component.dart
Expand Up @@ -273,7 +273,7 @@ class Component {
} else if (_parent == null) {
addToParent(newParent);
} else {
final root = findGame()! as ComponentTreeRoot;
final root = findGame()!;
root.enqueueMove(this, newParent);
}
}
Expand Down Expand Up @@ -384,9 +384,16 @@ class Component {

@internal
static Game? staticGameInstance;
Game? findGame() {
return staticGameInstance ??
((this is Game) ? (this as Game) : _parent?.findGame());
FlameGame? findGame() {
assert(
staticGameInstance is FlameGame || staticGameInstance == null,
'A component needs to have a FlameGame as the root.',
);
final gameInstance = staticGameInstance is FlameGame
? staticGameInstance! as FlameGame
: null;
return gameInstance ??
((this is FlameGame) ? (this as FlameGame) : _parent?.findGame());
}

/// Whether the children list contains the given component.
Expand Down Expand Up @@ -581,7 +588,7 @@ class Component {
child._parent = this;
final game = findGame();
if (isMounted && !child.isMounted) {
(game! as FlameGame).enqueueAdd(child, this);
game!.enqueueAdd(child, this);
} else {
// This will be reconciled during the mounting stage
children.add(child);
Expand Down Expand Up @@ -627,7 +634,7 @@ class Component {
"$this, component's parent = ${child._parent}",
);
if (isMounted) {
final root = findGame()! as ComponentTreeRoot;
final root = findGame()!;
if (child.isMounted || child.isMounting) {
if (!child.isRemoving) {
root.enqueueRemove(child, this);
Expand Down Expand Up @@ -740,7 +747,7 @@ class Component {
_priority = newPriority;
final game = findGame();
if (game != null && _parent != null) {
(game as FlameGame).enqueueRebalance(_parent!);
game.enqueueRebalance(_parent!);
}
}
}
Expand Down
3 changes: 1 addition & 2 deletions packages/flame/lib/src/components/mixins/has_game_ref.dart
@@ -1,7 +1,6 @@
import 'package:flame/src/components/core/component.dart';
import 'package:flame/src/experimental/has_game_reference.dart';
import 'package:flame/src/game/flame_game.dart';
import 'package:flame/src/game/game.dart';
import 'package:flame/src/game/mixins/single_game_instance.dart';

/// [HasGameRef] mixin provides property [game] (or [gameRef]), which is the
Expand Down Expand Up @@ -32,7 +31,7 @@ mixin HasGameRef<T extends FlameGame> on Component {
T get gameRef => game;

@override
Game? findGame() => _game ?? super.findGame();
FlameGame? findGame() => _game ?? super.findGame();

T _findGameAndCheck() {
final game = findGame();
Expand Down
7 changes: 2 additions & 5 deletions packages/flame/lib/src/components/mixins/notifier.dart
Expand Up @@ -12,11 +12,8 @@ import 'package:meta/meta.dart';
mixin Notifier on Component {
FlameGame get _gameRef {
final game = findGame();
assert(
game == null || game is FlameGame,
"Notifier can't be used without FlameGame",
);
return game! as FlameGame;
assert(game != null, "Notifier can't be used without FlameGame");
return game!;
}

@override
Expand Down
@@ -1,4 +1,3 @@
import 'package:flame/game.dart';
import 'package:flame/src/components/core/component.dart';
import 'package:flame/src/events/flame_game_mixins/double_tap_dispatcher.dart';
import 'package:flame/src/events/messages/double_tap_cancel_event.dart';
Expand Down Expand Up @@ -29,7 +28,7 @@ mixin DoubleTapCallbacks on Component {
@override
void onMount() {
super.onMount();
final game = findGame()! as FlameGame;
final game = findGame()!;
if (game.findByKey(const DoubleTapDispatcherKey()) == null) {
final dispatcher = DoubleTapDispatcher();
game.registerKey(const DoubleTapDispatcherKey(), dispatcher);
Expand Down
Expand Up @@ -4,7 +4,6 @@ import 'package:flame/src/events/messages/drag_cancel_event.dart';
import 'package:flame/src/events/messages/drag_end_event.dart';
import 'package:flame/src/events/messages/drag_start_event.dart';
import 'package:flame/src/events/messages/drag_update_event.dart';
import 'package:flame/src/game/flame_game.dart';
import 'package:meta/meta.dart';

/// This mixin can be added to a [Component] allowing it to receive drag events.
Expand Down Expand Up @@ -66,7 +65,7 @@ mixin DragCallbacks on Component {
@mustCallSuper
void onMount() {
super.onMount();
final game = findGame()! as FlameGame;
final game = findGame()!;
if (game.findByKey(const MultiDragDispatcherKey()) == null) {
final dispatcher = MultiDragDispatcher();
game.registerKey(const MultiDragDispatcherKey(), dispatcher);
Expand Down
@@ -1,4 +1,3 @@
import 'package:flame/game.dart';
import 'package:flame/src/components/core/component.dart';
import 'package:flame/src/events/flame_game_mixins/has_tappable_components.dart';
import 'package:flame/src/events/messages/tap_cancel_event.dart';
Expand All @@ -23,7 +22,7 @@ mixin TapCallbacks on Component {
@mustCallSuper
void onMount() {
super.onMount();
final game = findGame()! as FlameGame;
final game = findGame()!;
if (game.findByKey(const MultiTapDispatcherKey()) == null) {
final dispatcher = MultiTapDispatcher();
game.registerKey(const MultiTapDispatcherKey(), dispatcher);
Expand Down
10 changes: 3 additions & 7 deletions packages/flame/lib/src/experimental/has_game_reference.dart
@@ -1,6 +1,5 @@
import 'package:flame/src/components/core/component.dart';
import 'package:flame/src/components/mixins/has_game_ref.dart';
import 'package:flame/src/game/game.dart';
import 'package:flame/src/game/flame_game.dart';
import 'package:flame/src/game/mixins/single_game_instance.dart';

/// [HasGameReference] mixin provides property [game], which is the cached
Expand All @@ -9,10 +8,7 @@ import 'package:flame/src/game/mixins/single_game_instance.dart';
/// The type [T] on the mixin is the type of your game class. This type will be
/// the type of the [game] reference, and the mixin will check at runtime that
/// the actual type matches the expectation.
///
/// This class is equivalent to [HasGameRef] in all respects except that its
/// generic parameter [T] can be any [Game], not just a "FlameGame".
mixin HasGameReference<T extends Game> on Component {
mixin HasGameReference<T extends FlameGame> on Component {
T? _game;

/// Reference to the top-level Game instance that owns this component.
Expand All @@ -28,7 +24,7 @@ mixin HasGameReference<T extends Game> on Component {
set game(T? value) => _game = value;

@override
Game? findGame() => _game ?? super.findGame();
FlameGame? findGame() => _game ?? super.findGame();

T _findGameAndCheck() {
final game = findGame();
Expand Down
10 changes: 7 additions & 3 deletions packages/flame/test/experimental/has_game_reference_test.dart
Expand Up @@ -5,13 +5,16 @@ import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';

class _GameReferenceGame extends FlameGame {}

void main() {
group('HasGameReference', () {
testWithFlameGame(
testWithGame(
'component with default HasGameReference',
_GameReferenceGame.new,
(game) async {
final component1 = _Component<FlameGame>();
final component2 = _Component<Game>();
final component2 = _Component<_GameReferenceGame>();
game.addAll([component1, component2]);
expect(component1.game, game);
expect(component2.game, game);
Expand Down Expand Up @@ -102,7 +105,8 @@ void main() {
});
}

class _Component<T extends Game> extends Component with HasGameReference<T> {}
class _Component<T extends FlameGame> extends Component
with HasGameReference<T> {}

class _MyGame extends FlameGame {
bool calledFoo = false;
Expand Down
8 changes: 4 additions & 4 deletions packages/flame_test/lib/src/flame_test.dart
Expand Up @@ -17,28 +17,28 @@ extension FlameGameExtension on Component {
/// returned future to resolve.
Future<void> ensureAdd(Component component) async {
await add(component);
await (component.findGame()! as FlameGame).ready();
await component.findGame()!.ready();
}

/// Makes sure that the [components] are added to the tree if you wait for the
/// returned future to resolve.
Future<void> ensureAddAll(Iterable<Component> components) async {
await addAll(components);
await (components.first.findGame()! as FlameGame).ready();
await components.first.findGame()!.ready();
}

/// Makes sure that the [component] is removed from the tree if you wait for
/// the returned future to resolve.
Future<void> ensureRemove(Component component) async {
remove(component);
await (component.findGame()! as FlameGame).ready();
await component.findGame()!.ready();
}

/// Makes sure that the [components] are removed from the tree if you wait for
/// the returned future to resolve.
Future<void> ensureRemoveAll(Iterable<Component> components) async {
removeAll(components);
await (components.first.findGame()! as FlameGame).ready();
await components.first.findGame()!.ready();
}
}

Expand Down

0 comments on commit 93dcb3a

Please sign in to comment.