feat: include DashNest bonus (#80)

* feat: included dash nest logic

Co-authored-by: Allison Ryan <77211884+allisonryan0002@users.noreply.github.com>
pull/88/head
Alejandro Santiago 3 years ago committed by GitHub
parent d5f41277c8
commit 823cdb6af5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -12,6 +12,7 @@ class GameBloc extends Bloc<GameEvent, GameState> {
on<BallLost>(_onBallLost); on<BallLost>(_onBallLost);
on<Scored>(_onScored); on<Scored>(_onScored);
on<BonusLetterActivated>(_onBonusLetterActivated); on<BonusLetterActivated>(_onBonusLetterActivated);
on<DashNestActivated>(_onDashNestActivated);
} }
static const bonusWord = 'GOOGLE'; static const bonusWord = 'GOOGLE';
@ -52,4 +53,28 @@ class GameBloc extends Bloc<GameEvent, GameState> {
); );
} }
} }
void _onDashNestActivated(DashNestActivated event, Emitter emit) {
const nestsRequiredForBonus = 3;
final newNests = {
...state.activatedDashNests,
event.nestId,
};
if (newNests.length == nestsRequiredForBonus) {
emit(
state.copyWith(
activatedDashNests: {},
bonusHistory: [
...state.bonusHistory,
GameBonus.dashNest,
],
),
);
} else {
emit(
state.copyWith(activatedDashNests: newNests),
);
}
}
} }

@ -45,3 +45,12 @@ class BonusLetterActivated extends GameEvent {
@override @override
List<Object?> get props => [letterIndex]; List<Object?> get props => [letterIndex];
} }
class DashNestActivated extends GameEvent {
const DashNestActivated(this.nestId);
final String nestId;
@override
List<Object?> get props => [nestId];
}

@ -7,6 +7,10 @@ enum GameBonus {
/// Bonus achieved when the user activate all of the bonus /// 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, word,
/// Bonus achieved when the user activates all of the Dash
/// nests on the board, adding a new ball to the board.
dashNest,
} }
/// {@template game_state} /// {@template game_state}
@ -19,6 +23,7 @@ class GameState extends Equatable {
required this.balls, required this.balls,
required this.activatedBonusLetters, required this.activatedBonusLetters,
required this.bonusHistory, required this.bonusHistory,
required this.activatedDashNests,
}) : assert(score >= 0, "Score can't be negative"), }) : 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");
@ -26,6 +31,7 @@ class GameState extends Equatable {
: score = 0, : score = 0,
balls = 3, balls = 3,
activatedBonusLetters = const [], activatedBonusLetters = const [],
activatedDashNests = const {},
bonusHistory = const []; bonusHistory = const [];
/// The current score of the game. /// The current score of the game.
@ -39,6 +45,9 @@ class GameState extends Equatable {
/// Active bonus letters. /// Active bonus letters.
final List<int> activatedBonusLetters; final List<int> activatedBonusLetters;
/// Active dash nests.
final Set<String> activatedDashNests;
/// Holds the history of all the [GameBonus]es earned by the player during a /// Holds the history of all the [GameBonus]es earned by the player during a
/// PinballGame. /// PinballGame.
final List<GameBonus> bonusHistory; final List<GameBonus> bonusHistory;
@ -57,6 +66,7 @@ class GameState extends Equatable {
int? score, int? score,
int? balls, int? balls,
List<int>? activatedBonusLetters, List<int>? activatedBonusLetters,
Set<String>? activatedDashNests,
List<GameBonus>? bonusHistory, List<GameBonus>? bonusHistory,
}) { }) {
assert( assert(
@ -69,6 +79,7 @@ class GameState extends Equatable {
balls: balls ?? this.balls, balls: balls ?? this.balls,
activatedBonusLetters: activatedBonusLetters:
activatedBonusLetters ?? this.activatedBonusLetters, activatedBonusLetters ?? this.activatedBonusLetters,
activatedDashNests: activatedDashNests ?? this.activatedDashNests,
bonusHistory: bonusHistory ?? this.bonusHistory, bonusHistory: bonusHistory ?? this.bonusHistory,
); );
} }
@ -78,6 +89,7 @@ class GameState extends Equatable {
score, score,
balls, balls,
activatedBonusLetters, activatedBonusLetters,
activatedDashNests,
bonusHistory, bonusHistory,
]; ];
} }

@ -25,18 +25,21 @@ void main() {
score: 0, score: 0,
balls: 2, balls: 2,
activatedBonusLetters: [], activatedBonusLetters: [],
activatedDashNests: {},
bonusHistory: [], bonusHistory: [],
), ),
const GameState( const GameState(
score: 0, score: 0,
balls: 1, balls: 1,
activatedBonusLetters: [], activatedBonusLetters: [],
activatedDashNests: {},
bonusHistory: [], bonusHistory: [],
), ),
const GameState( const GameState(
score: 0, score: 0,
balls: 0, balls: 0,
activatedBonusLetters: [], activatedBonusLetters: [],
activatedDashNests: {},
bonusHistory: [], bonusHistory: [],
), ),
], ],
@ -56,12 +59,14 @@ void main() {
score: 2, score: 2,
balls: 3, balls: 3,
activatedBonusLetters: [], activatedBonusLetters: [],
activatedDashNests: {},
bonusHistory: [], bonusHistory: [],
), ),
const GameState( const GameState(
score: 5, score: 5,
balls: 3, balls: 3,
activatedBonusLetters: [], activatedBonusLetters: [],
activatedDashNests: {},
bonusHistory: [], bonusHistory: [],
), ),
], ],
@ -82,18 +87,21 @@ void main() {
score: 0, score: 0,
balls: 2, balls: 2,
activatedBonusLetters: [], activatedBonusLetters: [],
activatedDashNests: {},
bonusHistory: [], bonusHistory: [],
), ),
const GameState( const GameState(
score: 0, score: 0,
balls: 1, balls: 1,
activatedBonusLetters: [], activatedBonusLetters: [],
activatedDashNests: {},
bonusHistory: [], bonusHistory: [],
), ),
const GameState( const GameState(
score: 0, score: 0,
balls: 0, balls: 0,
activatedBonusLetters: [], activatedBonusLetters: [],
activatedDashNests: {},
bonusHistory: [], bonusHistory: [],
), ),
], ],
@ -113,18 +121,21 @@ void main() {
score: 0, score: 0,
balls: 3, balls: 3,
activatedBonusLetters: [0], activatedBonusLetters: [0],
activatedDashNests: {},
bonusHistory: [], bonusHistory: [],
), ),
GameState( GameState(
score: 0, score: 0,
balls: 3, balls: 3,
activatedBonusLetters: [0, 1], activatedBonusLetters: [0, 1],
activatedDashNests: {},
bonusHistory: [], bonusHistory: [],
), ),
GameState( GameState(
score: 0, score: 0,
balls: 3, balls: 3,
activatedBonusLetters: [0, 1, 2], activatedBonusLetters: [0, 1, 2],
activatedDashNests: {},
bonusHistory: [], bonusHistory: [],
), ),
], ],
@ -145,46 +156,87 @@ void main() {
score: 0, score: 0,
balls: 3, balls: 3,
activatedBonusLetters: [0], activatedBonusLetters: [0],
activatedDashNests: {},
bonusHistory: [], bonusHistory: [],
), ),
GameState( GameState(
score: 0, score: 0,
balls: 3, balls: 3,
activatedBonusLetters: [0, 1], activatedBonusLetters: [0, 1],
activatedDashNests: {},
bonusHistory: [], bonusHistory: [],
), ),
GameState( GameState(
score: 0, score: 0,
balls: 3, balls: 3,
activatedBonusLetters: [0, 1, 2], activatedBonusLetters: [0, 1, 2],
activatedDashNests: {},
bonusHistory: [], bonusHistory: [],
), ),
GameState( GameState(
score: 0, score: 0,
balls: 3, balls: 3,
activatedBonusLetters: [0, 1, 2, 3], activatedBonusLetters: [0, 1, 2, 3],
activatedDashNests: {},
bonusHistory: [], bonusHistory: [],
), ),
GameState( GameState(
score: 0, score: 0,
balls: 3, balls: 3,
activatedBonusLetters: [0, 1, 2, 3, 4], activatedBonusLetters: [0, 1, 2, 3, 4],
activatedDashNests: {},
bonusHistory: [], bonusHistory: [],
), ),
GameState( GameState(
score: 0, score: 0,
balls: 3, balls: 3,
activatedBonusLetters: [], activatedBonusLetters: [],
activatedDashNests: {},
bonusHistory: [GameBonus.word], bonusHistory: [GameBonus.word],
), ),
GameState( GameState(
score: GameBloc.bonusWordScore, score: GameBloc.bonusWordScore,
balls: 3, balls: 3,
activatedBonusLetters: [], activatedBonusLetters: [],
activatedDashNests: {},
bonusHistory: [GameBonus.word], bonusHistory: [GameBonus.word],
), ),
], ],
); );
}); });
group('DashNestActivated', () {
blocTest<GameBloc, GameState>(
'adds the bonus when all nests are activated',
build: GameBloc.new,
act: (bloc) => bloc
..add(const DashNestActivated('0'))
..add(const DashNestActivated('1'))
..add(const DashNestActivated('2')),
expect: () => const [
GameState(
score: 0,
balls: 3,
activatedBonusLetters: [],
activatedDashNests: {'0'},
bonusHistory: [],
),
GameState(
score: 0,
balls: 3,
activatedBonusLetters: [],
activatedDashNests: {'0', '1'},
bonusHistory: [],
),
GameState(
score: 0,
balls: 3,
activatedBonusLetters: [],
activatedDashNests: {},
bonusHistory: [GameBonus.dashNest],
),
],
);
});
}); });
} }

@ -67,5 +67,22 @@ void main() {
}, },
); );
}); });
group('DashNestActivated', () {
test('can be instantiated', () {
expect(const DashNestActivated('0'), isNotNull);
});
test('supports value equality', () {
expect(
DashNestActivated('0'),
equals(DashNestActivated('0')),
);
expect(
DashNestActivated('0'),
isNot(equals(DashNestActivated('1'))),
);
});
});
}); });
} }

@ -11,6 +11,7 @@ void main() {
score: 0, score: 0,
balls: 0, balls: 0,
activatedBonusLetters: const [], activatedBonusLetters: const [],
activatedDashNests: const {},
bonusHistory: const [], bonusHistory: const [],
), ),
equals( equals(
@ -18,6 +19,7 @@ void main() {
score: 0, score: 0,
balls: 0, balls: 0,
activatedBonusLetters: [], activatedBonusLetters: [],
activatedDashNests: {},
bonusHistory: [], bonusHistory: [],
), ),
), ),
@ -31,6 +33,7 @@ void main() {
score: 0, score: 0,
balls: 0, balls: 0,
activatedBonusLetters: [], activatedBonusLetters: [],
activatedDashNests: {},
bonusHistory: [], bonusHistory: [],
), ),
isNotNull, isNotNull,
@ -47,6 +50,7 @@ void main() {
balls: -1, balls: -1,
score: 0, score: 0,
activatedBonusLetters: const [], activatedBonusLetters: const [],
activatedDashNests: const {},
bonusHistory: const [], bonusHistory: const [],
), ),
throwsAssertionError, throwsAssertionError,
@ -63,6 +67,7 @@ void main() {
balls: 0, balls: 0,
score: -1, score: -1,
activatedBonusLetters: const [], activatedBonusLetters: const [],
activatedDashNests: const {},
bonusHistory: const [], bonusHistory: const [],
), ),
throwsAssertionError, throwsAssertionError,
@ -78,6 +83,7 @@ void main() {
balls: 0, balls: 0,
score: 0, score: 0,
activatedBonusLetters: [], activatedBonusLetters: [],
activatedDashNests: {},
bonusHistory: [], bonusHistory: [],
); );
expect(gameState.isGameOver, isTrue); expect(gameState.isGameOver, isTrue);
@ -90,6 +96,7 @@ void main() {
balls: 1, balls: 1,
score: 0, score: 0,
activatedBonusLetters: [], activatedBonusLetters: [],
activatedDashNests: {},
bonusHistory: [], bonusHistory: [],
); );
expect(gameState.isGameOver, isFalse); expect(gameState.isGameOver, isFalse);
@ -105,6 +112,7 @@ void main() {
balls: 1, balls: 1,
score: 0, score: 0,
activatedBonusLetters: [], activatedBonusLetters: [],
activatedDashNests: {},
bonusHistory: [], bonusHistory: [],
); );
expect(gameState.isLastBall, isTrue); expect(gameState.isLastBall, isTrue);
@ -119,6 +127,7 @@ void main() {
balls: 2, balls: 2,
score: 0, score: 0,
activatedBonusLetters: [], activatedBonusLetters: [],
activatedDashNests: {},
bonusHistory: [], bonusHistory: [],
); );
expect(gameState.isLastBall, isFalse); expect(gameState.isLastBall, isFalse);
@ -134,6 +143,7 @@ void main() {
balls: 3, balls: 3,
score: 0, score: 0,
activatedBonusLetters: [1], activatedBonusLetters: [1],
activatedDashNests: {},
bonusHistory: [], bonusHistory: [],
); );
expect(gameState.isLetterActivated(1), isTrue); expect(gameState.isLetterActivated(1), isTrue);
@ -147,6 +157,7 @@ void main() {
balls: 3, balls: 3,
score: 0, score: 0,
activatedBonusLetters: [1], activatedBonusLetters: [1],
activatedDashNests: {},
bonusHistory: [], bonusHistory: [],
); );
expect(gameState.isLetterActivated(0), isFalse); expect(gameState.isLetterActivated(0), isFalse);
@ -163,6 +174,7 @@ void main() {
balls: 0, balls: 0,
score: 2, score: 2,
activatedBonusLetters: [], activatedBonusLetters: [],
activatedDashNests: {},
bonusHistory: [], bonusHistory: [],
); );
expect( expect(
@ -180,6 +192,7 @@ void main() {
balls: 0, balls: 0,
score: 2, score: 2,
activatedBonusLetters: [], activatedBonusLetters: [],
activatedDashNests: {},
bonusHistory: [], bonusHistory: [],
); );
expect( expect(
@ -197,12 +210,14 @@ void main() {
score: 2, score: 2,
balls: 0, balls: 0,
activatedBonusLetters: [], activatedBonusLetters: [],
activatedDashNests: {},
bonusHistory: [], bonusHistory: [],
); );
final otherGameState = GameState( final otherGameState = GameState(
score: gameState.score + 1, score: gameState.score + 1,
balls: gameState.balls + 1, balls: gameState.balls + 1,
activatedBonusLetters: const [0], activatedBonusLetters: const [0],
activatedDashNests: const {'1'},
bonusHistory: const [GameBonus.word], bonusHistory: const [GameBonus.word],
); );
expect(gameState, isNot(equals(otherGameState))); expect(gameState, isNot(equals(otherGameState)));
@ -212,6 +227,7 @@ void main() {
score: otherGameState.score, score: otherGameState.score,
balls: otherGameState.balls, balls: otherGameState.balls,
activatedBonusLetters: otherGameState.activatedBonusLetters, activatedBonusLetters: otherGameState.activatedBonusLetters,
activatedDashNests: otherGameState.activatedDashNests,
bonusHistory: otherGameState.bonusHistory, bonusHistory: otherGameState.bonusHistory,
), ),
equals(otherGameState), equals(otherGameState),

@ -156,6 +156,7 @@ void main() {
score: 10, score: 10,
balls: 1, balls: 1,
activatedBonusLetters: [], activatedBonusLetters: [],
activatedDashNests: {},
bonusHistory: [], bonusHistory: [],
), ),
); );

@ -30,9 +30,9 @@ void main() {
await game.ready(); await game.ready();
await game.ensureAdd(board); await game.ensureAdd(board);
final leftFlippers = board.findNestedChildren<Flipper>( final leftFlippers = board.descendants().whereType<Flipper>().where(
condition: (flipper) => flipper.side.isLeft, (flipper) => flipper.side.isLeft,
); );
expect(leftFlippers.length, equals(1)); expect(leftFlippers.length, equals(1));
}, },
); );
@ -43,10 +43,9 @@ void main() {
final board = Board(); final board = Board();
await game.ready(); await game.ready();
await game.ensureAdd(board); await game.ensureAdd(board);
final rightFlippers = board.descendants().whereType<Flipper>().where(
final rightFlippers = board.findNestedChildren<Flipper>( (flipper) => flipper.side.isRight,
condition: (flipper) => flipper.side.isRight, );
);
expect(rightFlippers.length, equals(1)); expect(rightFlippers.length, equals(1));
}, },
); );
@ -58,7 +57,7 @@ void main() {
await game.ready(); await game.ready();
await game.ensureAdd(board); await game.ensureAdd(board);
final baseboards = board.findNestedChildren<Baseboard>(); final baseboards = board.descendants().whereType<Baseboard>();
expect(baseboards.length, equals(2)); expect(baseboards.length, equals(2));
}, },
); );
@ -70,7 +69,7 @@ void main() {
await game.ready(); await game.ready();
await game.ensureAdd(board); await game.ensureAdd(board);
final kickers = board.findNestedChildren<Kicker>(); final kickers = board.descendants().whereType<Kicker>();
expect(kickers.length, equals(2)); expect(kickers.length, equals(2));
}, },
); );
@ -83,7 +82,7 @@ void main() {
await game.ready(); await game.ready();
await game.ensureAdd(board); await game.ensureAdd(board);
final roundBumpers = board.findNestedChildren<RoundBumper>(); final roundBumpers = board.descendants().whereType<RoundBumper>();
expect(roundBumpers.length, equals(3)); expect(roundBumpers.length, equals(3));
}, },
); );

@ -234,6 +234,7 @@ void main() {
score: 0, score: 0,
balls: 2, balls: 2,
activatedBonusLetters: [0], activatedBonusLetters: [0],
activatedDashNests: {},
bonusHistory: [], bonusHistory: [],
); );
whenListen( whenListen(
@ -259,6 +260,7 @@ void main() {
score: 0, score: 0,
balls: 2, balls: 2,
activatedBonusLetters: [0], activatedBonusLetters: [0],
activatedDashNests: {},
bonusHistory: [], bonusHistory: [],
); );
@ -283,6 +285,7 @@ void main() {
score: 0, score: 0,
balls: 2, balls: 2,
activatedBonusLetters: [0], activatedBonusLetters: [0],
activatedDashNests: {},
bonusHistory: [], bonusHistory: [],
); );

@ -13,6 +13,7 @@ void main() {
score: 10, score: 10,
balls: 2, balls: 2,
activatedBonusLetters: [], activatedBonusLetters: [],
activatedDashNests: {},
bonusHistory: [], bonusHistory: [],
); );

@ -88,6 +88,7 @@ void main() {
score: 0, score: 0,
balls: 0, balls: 0,
activatedBonusLetters: [], activatedBonusLetters: [],
activatedDashNests: {},
bonusHistory: [], bonusHistory: [],
); );

@ -1,4 +1,3 @@
import 'package:flame/components.dart';
import 'package:pinball/game/game.dart'; import 'package:pinball/game/game.dart';
import 'package:pinball_theme/pinball_theme.dart'; import 'package:pinball_theme/pinball_theme.dart';
@ -21,41 +20,3 @@ extension DebugPinballGameTest on DebugPinballGame {
), ),
); );
} }
extension ComponentX on Component {
T findNestedChild<T extends Component>({
bool Function(T)? condition,
}) {
T? nestedChild;
propagateToChildren<T>((child) {
final foundChild = (condition ?? (_) => true)(child);
if (foundChild) {
nestedChild = child;
}
return !foundChild;
});
if (nestedChild == null) {
throw Exception('No child of type $T found.');
} else {
return nestedChild!;
}
}
List<T> findNestedChildren<T extends Component>({
bool Function(T)? condition,
}) {
final nestedChildren = <T>[];
propagateToChildren<T>((child) {
final foundChild = (condition ?? (_) => true)(child);
if (foundChild) {
nestedChildren.add(child);
}
return true;
});
return nestedChildren;
}
}

Loading…
Cancel
Save