From 59ee85b4bce559a17b9af938b360559164e4e0ee Mon Sep 17 00:00:00 2001 From: alestiago Date: Mon, 4 Apr 2022 10:06:26 +0100 Subject: [PATCH] feat: started implemented bonusBalls --- lib/game/bloc/game_bloc.dart | 13 +++++++++---- lib/game/bloc/game_event.dart | 10 ++++++++++ lib/game/bloc/game_state.dart | 20 ++++++++++++++++---- lib/game/components/controlled_ball.dart | 16 ++++++++++++++-- test/game/bloc/game_bloc_test.dart | 21 +++++++++++++++++++++ 5 files changed, 70 insertions(+), 10 deletions(-) diff --git a/lib/game/bloc/game_bloc.dart b/lib/game/bloc/game_bloc.dart index c02417a7..12941315 100644 --- a/lib/game/bloc/game_bloc.dart +++ b/lib/game/bloc/game_bloc.dart @@ -36,7 +36,8 @@ class GameBloc extends Bloc { event.letterIndex, ]; - if (newBonusLetters.length == bonusWord.length) { + final achievedBonus = newBonusLetters.length == bonusWord.length; + if (achievedBonus) { emit( state.copyWith( activatedBonusLetters: [], @@ -55,15 +56,19 @@ class GameBloc extends Bloc { } void _onDashNestActivated(DashNestActivated event, Emitter emit) { - const nestsRequiredForBonus = 3; - final newNests = { ...state.activatedDashNests, event.nestId, }; - if (newNests.length == nestsRequiredForBonus) { + + final achievedBonus = newNests.length == 3; + if (achievedBonus) { emit( state.copyWith( + // TODO(alestiago): Question if we should have a private event + // _onBonusBallActivated() to avoid the duplication of code and + // split the logic. + bonusBalls: state.bonusBalls + 1, activatedDashNests: {}, bonusHistory: [ ...state.bonusHistory, diff --git a/lib/game/bloc/game_event.dart b/lib/game/bloc/game_event.dart index b05c5336..f3658ad6 100644 --- a/lib/game/bloc/game_event.dart +++ b/lib/game/bloc/game_event.dart @@ -18,6 +18,16 @@ class BallLost extends GameEvent { List get props => []; } +/// {@template bonus_ball_lost_game_event} +/// Event added when a user drops a bonus ball of the screen. +/// {@endtemplate} +class BonusBallLost extends GameEvent { + const BonusBallLost(); + + @override + List get props => []; +} + /// {@template scored_game_event} /// Event added when a user increases their score. /// {@endtemplate} diff --git a/lib/game/bloc/game_state.dart b/lib/game/bloc/game_state.dart index d08ba04b..c1f10ecc 100644 --- a/lib/game/bloc/game_state.dart +++ b/lib/game/bloc/game_state.dart @@ -5,11 +5,12 @@ part of 'game_bloc.dart'; /// Defines bonuses that a player can gain during a PinballGame. enum GameBonus { /// Bonus achieved when the user activate all of the bonus - /// letters on the board, forming the bonus word + /// letters on the board, forming the bonus word. word, - /// Bonus achieved when the user activates all of the Dash - /// nests on the board, adding a new ball to the board. + /// Bonus achieved when the user activates all [FlutterForest] bumpers. + /// + /// Adds a [GameState.bonusBalls] to the game. dashNest, } @@ -21,15 +22,18 @@ class GameState extends Equatable { const GameState({ required this.score, required this.balls, + required this.bonusBalls, required this.activatedBonusLetters, required this.bonusHistory, required this.activatedDashNests, }) : assert(score >= 0, "Score can't be negative"), - assert(balls >= 0, "Number of balls can't be negative"); + assert(balls >= 0, "Number of balls can't be negative"), + assert(bonusBalls >= 0, "Number of bonus balls can't be negative"); const GameState.initial() : score = 0, balls = 3, + bonusBalls = 0, activatedBonusLetters = const [], activatedDashNests = const {}, bonusHistory = const []; @@ -42,6 +46,12 @@ class GameState extends Equatable { /// When the number of balls is 0, the game is over. final int balls; + /// The number of bonus balls in the game. + /// + /// [bonusBalls] are gained during the game. Usually triggered by activating + /// a [GameBonus]. + final int bonusBalls; + /// Active bonus letters. final List activatedBonusLetters; @@ -62,6 +72,7 @@ class GameState extends Equatable { GameState copyWith({ int? score, int? balls, + int? bonusBalls, List? activatedBonusLetters, Set? activatedDashNests, List? bonusHistory, @@ -74,6 +85,7 @@ class GameState extends Equatable { return GameState( score: score ?? this.score, balls: balls ?? this.balls, + bonusBalls: bonusBalls ?? this.bonusBalls, activatedBonusLetters: activatedBonusLetters ?? this.activatedBonusLetters, activatedDashNests: activatedDashNests ?? this.activatedDashNests, diff --git a/lib/game/components/controlled_ball.dart b/lib/game/components/controlled_ball.dart index 1981e39c..f89530d0 100644 --- a/lib/game/components/controlled_ball.dart +++ b/lib/game/components/controlled_ball.dart @@ -59,14 +59,26 @@ abstract class BallController extends ComponentController { /// /// A [BonusBallController] doesn't change the [GameState.balls] count. /// {@endtemplate} -class BonusBallController extends BallController { +class BonusBallController extends BallController + with HasGameRef, BlocComponent { /// {@macro bonus_ball_controller} BonusBallController(Ball component) : super(component); @override - void lost() { + 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() { + gameRef.read().add(const BonusBallLost()); + } } /// {@template launched_ball_controller} diff --git a/test/game/bloc/game_bloc_test.dart b/test/game/bloc/game_bloc_test.dart index f4b79001..43d3f99a 100644 --- a/test/game/bloc/game_bloc_test.dart +++ b/test/game/bloc/game_bloc_test.dart @@ -24,6 +24,7 @@ void main() { const GameState( score: 0, balls: 2, + bonusBalls: 0, activatedBonusLetters: [], activatedDashNests: {}, bonusHistory: [], @@ -31,6 +32,7 @@ void main() { const GameState( score: 0, balls: 1, + bonusBalls: 0, activatedBonusLetters: [], activatedDashNests: {}, bonusHistory: [], @@ -38,6 +40,7 @@ void main() { const GameState( score: 0, balls: 0, + bonusBalls: 0, activatedBonusLetters: [], activatedDashNests: {}, bonusHistory: [], @@ -58,6 +61,7 @@ void main() { const GameState( score: 2, balls: 3, + bonusBalls: 0, activatedBonusLetters: [], activatedDashNests: {}, bonusHistory: [], @@ -65,6 +69,7 @@ void main() { const GameState( score: 5, balls: 3, + bonusBalls: 0, activatedBonusLetters: [], activatedDashNests: {}, bonusHistory: [], @@ -86,6 +91,7 @@ void main() { const GameState( score: 0, balls: 2, + bonusBalls: 0, activatedBonusLetters: [], activatedDashNests: {}, bonusHistory: [], @@ -93,6 +99,7 @@ void main() { const GameState( score: 0, balls: 1, + bonusBalls: 0, activatedBonusLetters: [], activatedDashNests: {}, bonusHistory: [], @@ -100,6 +107,7 @@ void main() { const GameState( score: 0, balls: 0, + bonusBalls: 0, activatedBonusLetters: [], activatedDashNests: {}, bonusHistory: [], @@ -120,6 +128,7 @@ void main() { GameState( score: 0, balls: 3, + bonusBalls: 0, activatedBonusLetters: [0], activatedDashNests: {}, bonusHistory: [], @@ -127,6 +136,7 @@ void main() { GameState( score: 0, balls: 3, + bonusBalls: 0, activatedBonusLetters: [0, 1], activatedDashNests: {}, bonusHistory: [], @@ -134,6 +144,7 @@ void main() { GameState( score: 0, balls: 3, + bonusBalls: 0, activatedBonusLetters: [0, 1, 2], activatedDashNests: {}, bonusHistory: [], @@ -155,6 +166,7 @@ void main() { GameState( score: 0, balls: 3, + bonusBalls: 0, activatedBonusLetters: [0], activatedDashNests: {}, bonusHistory: [], @@ -162,6 +174,7 @@ void main() { GameState( score: 0, balls: 3, + bonusBalls: 0, activatedBonusLetters: [0, 1], activatedDashNests: {}, bonusHistory: [], @@ -169,6 +182,7 @@ void main() { GameState( score: 0, balls: 3, + bonusBalls: 0, activatedBonusLetters: [0, 1, 2], activatedDashNests: {}, bonusHistory: [], @@ -176,6 +190,7 @@ void main() { GameState( score: 0, balls: 3, + bonusBalls: 0, activatedBonusLetters: [0, 1, 2, 3], activatedDashNests: {}, bonusHistory: [], @@ -183,6 +198,7 @@ void main() { GameState( score: 0, balls: 3, + bonusBalls: 0, activatedBonusLetters: [0, 1, 2, 3, 4], activatedDashNests: {}, bonusHistory: [], @@ -190,6 +206,7 @@ void main() { GameState( score: 0, balls: 3, + bonusBalls: 0, activatedBonusLetters: [], activatedDashNests: {}, bonusHistory: [GameBonus.word], @@ -197,6 +214,7 @@ void main() { GameState( score: GameBloc.bonusWordScore, balls: 3, + bonusBalls: 0, activatedBonusLetters: [], activatedDashNests: {}, bonusHistory: [GameBonus.word], @@ -217,6 +235,7 @@ void main() { GameState( score: 0, balls: 3, + bonusBalls: 0, activatedBonusLetters: [], activatedDashNests: {'0'}, bonusHistory: [], @@ -224,6 +243,7 @@ void main() { GameState( score: 0, balls: 3, + bonusBalls: 0, activatedBonusLetters: [], activatedDashNests: {'0', '1'}, bonusHistory: [], @@ -231,6 +251,7 @@ void main() { GameState( score: 0, balls: 3, + bonusBalls: 1, activatedBonusLetters: [], activatedDashNests: {}, bonusHistory: [GameBonus.dashNest],