diff --git a/lib/game/components/controlled_ball.dart b/lib/game/components/controlled_ball.dart index f89530d0..e387a43a 100644 --- a/lib/game/components/controlled_ball.dart +++ b/lib/game/components/controlled_ball.dart @@ -1,5 +1,4 @@ import 'package:flame/components.dart'; -import 'package:flame_bloc/flame_bloc.dart'; import 'package:flame_forge2d/forge2d_game.dart'; import 'package:flutter/material.dart'; import 'package:pinball/flame/flame.dart'; @@ -34,7 +33,7 @@ class ControlledBall extends Ball with Controls { /// [Ball] used in [DebugPinballGame]. ControlledBall.debug() : super(baseColor: const Color(0xFFFF0000)) { - controller = BonusBallController(this); + controller = _DebugBallController(this); } } @@ -51,7 +50,10 @@ abstract class BallController extends ComponentController { /// Triggered by [BottomWallBallContactCallback] when the [Ball] falls into /// a [BottomWall]. /// {@endtemplate} - void lost(); + @mustCallSuper + void lost() { + component.shouldRemove = true; + } } /// {@template bonus_ball_controller} @@ -59,24 +61,13 @@ abstract class BallController extends ComponentController { /// /// A [BonusBallController] doesn't change the [GameState.balls] count. /// {@endtemplate} -class BonusBallController extends BallController - with HasGameRef, BlocComponent { +class BonusBallController extends BallController with HasGameRef { /// {@macro bonus_ball_controller} BonusBallController(Ball component) : super(component); - @override - bool listenWhen(GameState? previousState, GameState newState) { - return (previousState?.balls ?? 0) > newState.balls; - } - - @override - void onNewState(GameState state) { - super.onNewState(state); - component.shouldRemove = true; - } - @override void lost() { + super.lost(); gameRef.read().add(const BonusBallLost()); } } @@ -87,28 +78,21 @@ class BonusBallController extends BallController /// A [LaunchedBallController] changes the [GameState.balls] count. /// {@endtemplate} class LaunchedBallController extends BallController - with HasGameRef, BlocComponent { + with HasGameRef { /// {@macro launched_ball_controller} LaunchedBallController(Ball ball) : super(ball); - @override - bool listenWhen(GameState? previousState, GameState newState) { - return (previousState?.balls ?? 0) > newState.balls; - } - - @override - void onNewState(GameState state) { - super.onNewState(state); - component.shouldRemove = true; - if (state.balls > 0) gameRef.spawnBall(); - } - /// Removes the [Ball] from a [PinballGame]; spawning a new [Ball] if /// any are left. /// /// {@macro ball_controller_lost} @override void lost() { + super.lost(); gameRef.read().add(const BallLost()); } } + +class _DebugBallController extends BallController { + _DebugBallController(Ball ball) : super(ball); +} diff --git a/lib/game/pinball_game.dart b/lib/game/pinball_game.dart index 3c99fbca..ff02c8b8 100644 --- a/lib/game/pinball_game.dart +++ b/lib/game/pinball_game.dart @@ -6,6 +6,7 @@ import 'package:flame/extensions.dart'; import 'package:flame/input.dart'; import 'package:flame_bloc/flame_bloc.dart'; import 'package:flame_forge2d/flame_forge2d.dart'; +import 'package:pinball/flame/flame.dart'; import 'package:pinball/game/game.dart'; import 'package:pinball/gen/assets.gen.dart'; import 'package:pinball_audio/pinball_audio.dart'; @@ -13,9 +14,16 @@ import 'package:pinball_components/pinball_components.dart' hide Assets; import 'package:pinball_theme/pinball_theme.dart' hide Assets; class PinballGame extends Forge2DGame - with FlameBloc, HasKeyboardHandlerComponents { - PinballGame({required this.theme, required this.audio}) { + with + FlameBloc, + HasKeyboardHandlerComponents, + Controls<_GameBallsController> { + PinballGame({ + required this.theme, + required this.audio, + }) { images.prefix = ''; + controller = _GameBallsController(this); } final PinballTheme theme; @@ -25,11 +33,12 @@ class PinballGame extends Forge2DGame @override void onAttach() { super.onAttach(); - spawnBall(); + controller.spawnBall(); } @override Future onLoad() async { + await super.onLoad(); _addContactCallbacks(); await _addGameBoundaries(); @@ -87,6 +96,28 @@ class PinballGame extends Forge2DGame ), ); } +} + +class _GameBallsController extends ComponentController + with BlocComponent, HasGameRef { + _GameBallsController(PinballGame game) : super(game); + + @override + bool listenWhen(GameState? previousState, GameState newState) { + // TODO(alestiago): Fix how the logic works. + final previousBalls = + (previousState?.balls ?? 0) + (previousState?.bonusBalls ?? 0); + final currentBalls = newState.balls + newState.bonusBalls; + final canBallRespawn = newState.balls > 0 && newState.bonusBalls == 0; + + return previousBalls != currentBalls && canBallRespawn; + } + + @override + void onNewState(GameState state) { + super.onNewState(state); + spawnBall(); + } Future spawnBall() async { // TODO(alestiago): Remove once this logic is moved to controller. @@ -96,7 +127,7 @@ class PinballGame extends Forge2DGame } final ball = ControlledBall.launch( - theme: theme, + theme: gameRef.theme, )..initialPosition = Vector2( plunger.body.position.x, plunger.body.position.y + Ball.size.y,