diff --git a/doc/tutorials/klondike/app/lib/step4/components/card.dart b/doc/tutorials/klondike/app/lib/step4/components/card.dart index d05135e177..caf08032bb 100644 --- a/doc/tutorials/klondike/app/lib/step4/components/card.dart +++ b/doc/tutorials/klondike/app/lib/step4/components/card.dart @@ -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'; @@ -242,10 +241,8 @@ class Card extends PositionComponent with DragCallbacks { if (!_isDragging) { return; } - final cameraZoom = (findGame()! as FlameGame) - .firstChild()! - .viewfinder - .zoom; + final cameraZoom = + findGame()!.firstChild()!.viewfinder.zoom; final delta = event.delta / cameraZoom; position.add(delta); attachedCards.forEach((card) => card.position.add(delta)); diff --git a/packages/flame/lib/src/components/core/component.dart b/packages/flame/lib/src/components/core/component.dart index 92c4850cf2..97655d3fe6 100644 --- a/packages/flame/lib/src/components/core/component.dart +++ b/packages/flame/lib/src/components/core/component.dart @@ -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); } } @@ -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. @@ -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); @@ -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); @@ -740,7 +747,7 @@ class Component { _priority = newPriority; final game = findGame(); if (game != null && _parent != null) { - (game as FlameGame).enqueueRebalance(_parent!); + game.enqueueRebalance(_parent!); } } } diff --git a/packages/flame/lib/src/components/mixins/has_game_ref.dart b/packages/flame/lib/src/components/mixins/has_game_ref.dart index 5d9bf36d0f..169ea418cd 100644 --- a/packages/flame/lib/src/components/mixins/has_game_ref.dart +++ b/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 @@ -32,7 +31,7 @@ mixin HasGameRef on Component { T get gameRef => game; @override - Game? findGame() => _game ?? super.findGame(); + FlameGame? findGame() => _game ?? super.findGame(); T _findGameAndCheck() { final game = findGame(); diff --git a/packages/flame/lib/src/components/mixins/notifier.dart b/packages/flame/lib/src/components/mixins/notifier.dart index 57efd13177..e59c2a281b 100644 --- a/packages/flame/lib/src/components/mixins/notifier.dart +++ b/packages/flame/lib/src/components/mixins/notifier.dart @@ -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 diff --git a/packages/flame/lib/src/events/component_mixins/double_tap_callbacks.dart b/packages/flame/lib/src/events/component_mixins/double_tap_callbacks.dart index a7f4c43d8e..30bab8694c 100644 --- a/packages/flame/lib/src/events/component_mixins/double_tap_callbacks.dart +++ b/packages/flame/lib/src/events/component_mixins/double_tap_callbacks.dart @@ -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'; @@ -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); diff --git a/packages/flame/lib/src/events/component_mixins/drag_callbacks.dart b/packages/flame/lib/src/events/component_mixins/drag_callbacks.dart index aae10578cd..d66417ad12 100644 --- a/packages/flame/lib/src/events/component_mixins/drag_callbacks.dart +++ b/packages/flame/lib/src/events/component_mixins/drag_callbacks.dart @@ -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. @@ -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); diff --git a/packages/flame/lib/src/events/component_mixins/tap_callbacks.dart b/packages/flame/lib/src/events/component_mixins/tap_callbacks.dart index d78d94a7eb..221d236769 100644 --- a/packages/flame/lib/src/events/component_mixins/tap_callbacks.dart +++ b/packages/flame/lib/src/events/component_mixins/tap_callbacks.dart @@ -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'; @@ -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); diff --git a/packages/flame/lib/src/experimental/has_game_reference.dart b/packages/flame/lib/src/experimental/has_game_reference.dart index 01a94523c6..ad78669f87 100644 --- a/packages/flame/lib/src/experimental/has_game_reference.dart +++ b/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 @@ -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 on Component { +mixin HasGameReference on Component { T? _game; /// Reference to the top-level Game instance that owns this component. @@ -28,7 +24,7 @@ mixin HasGameReference on Component { set game(T? value) => _game = value; @override - Game? findGame() => _game ?? super.findGame(); + FlameGame? findGame() => _game ?? super.findGame(); T _findGameAndCheck() { final game = findGame(); diff --git a/packages/flame/test/experimental/has_game_reference_test.dart b/packages/flame/test/experimental/has_game_reference_test.dart index ed87ea5bfa..b99a0bc270 100644 --- a/packages/flame/test/experimental/has_game_reference_test.dart +++ b/packages/flame/test/experimental/has_game_reference_test.dart @@ -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(); - final component2 = _Component(); + final component2 = _Component<_GameReferenceGame>(); game.addAll([component1, component2]); expect(component1.game, game); expect(component2.game, game); @@ -102,7 +105,8 @@ void main() { }); } -class _Component extends Component with HasGameReference {} +class _Component extends Component + with HasGameReference {} class _MyGame extends FlameGame { bool calledFoo = false; diff --git a/packages/flame_test/lib/src/flame_test.dart b/packages/flame_test/lib/src/flame_test.dart index 4b30332cd1..a78a70effe 100644 --- a/packages/flame_test/lib/src/flame_test.dart +++ b/packages/flame_test/lib/src/flame_test.dart @@ -17,28 +17,28 @@ extension FlameGameExtension on Component { /// returned future to resolve. Future 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 ensureAddAll(Iterable 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 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 ensureRemoveAll(Iterable components) async { removeAll(components); - await (components.first.findGame()! as FlameGame).ready(); + await components.first.findGame()!.ready(); } }