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: HasGameReference should default to FlameGame #2710

Merged
merged 6 commits into from
Sep 10, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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