From f91aee2a0dbc77898a159bb1bab06846a52c86c0 Mon Sep 17 00:00:00 2001 From: alestiago Date: Wed, 13 Apr 2022 23:22:25 +0200 Subject: [PATCH] feat: implemented GoogleWord --- lib/game/bloc/game_bloc.dart | 34 +- lib/game/bloc/game_event.dart | 12 +- lib/game/bloc/game_state.dart | 13 - lib/game/components/components.dart | 2 +- lib/game/components/google_word.dart | 85 ++++ lib/game/game_assets.dart | 6 + lib/game/pinball_game.dart | 2 +- .../lib/src/components/google_letter.dart | 5 +- test/game/bloc/game_bloc_test.dart | 107 ----- test/game/bloc/game_event_test.dart | 70 ++-- test/game/bloc/game_state_test.dart | 42 -- test/game/components/bonus_word_test.dart | 376 ------------------ test/game/components/flutter_forest_test.dart | 1 - .../components/game_flow_controller_test.dart | 2 - test/game/components/google_word_test.dart | 35 ++ .../score_effect_controller_test.dart | 5 - test/game/view/game_hud_test.dart | 1 - test/helpers/mocks.dart | 2 - 18 files changed, 173 insertions(+), 627 deletions(-) create mode 100644 lib/game/components/google_word.dart delete mode 100644 test/game/components/bonus_word_test.dart create mode 100644 test/game/components/google_word_test.dart diff --git a/lib/game/bloc/game_bloc.dart b/lib/game/bloc/game_bloc.dart index ce1a78b4..ba604f17 100644 --- a/lib/game/bloc/game_bloc.dart +++ b/lib/game/bloc/game_bloc.dart @@ -11,14 +11,11 @@ class GameBloc extends Bloc { GameBloc() : super(const GameState.initial()) { on(_onBallLost); on(_onScored); - on(_onBonusLetterActivated); + on(_onBonusActivated); on(_onDashNestActivated); on(_onSparkyTurboChargeActivated); } - static const bonusWord = 'GOOGLE'; - static const bonusWordScore = 10000; - void _onBallLost(BallLost event, Emitter emit) { emit(state.copyWith(balls: state.balls - 1)); } @@ -29,29 +26,12 @@ class GameBloc extends Bloc { } } - void _onBonusLetterActivated(BonusLetterActivated event, Emitter emit) { - final newBonusLetters = [ - ...state.activatedBonusLetters, - event.letterIndex, - ]; - - final achievedBonus = newBonusLetters.length == bonusWord.length; - if (achievedBonus) { - emit( - state.copyWith( - activatedBonusLetters: [], - bonusHistory: [ - ...state.bonusHistory, - GameBonus.word, - ], - ), - ); - add(const Scored(points: bonusWordScore)); - } else { - emit( - state.copyWith(activatedBonusLetters: newBonusLetters), - ); - } + void _onBonusActivated(BonusActivated event, Emitter emit) { + emit( + state.copyWith( + bonusHistory: [...state.bonusHistory, event.bonus], + ), + ); } void _onDashNestActivated(DashNestActivated event, Emitter emit) { diff --git a/lib/game/bloc/game_event.dart b/lib/game/bloc/game_event.dart index ee5315ad..392cc50f 100644 --- a/lib/game/bloc/game_event.dart +++ b/lib/game/bloc/game_event.dart @@ -33,17 +33,13 @@ class Scored extends GameEvent { List get props => [points]; } -class BonusLetterActivated extends GameEvent { - const BonusLetterActivated(this.letterIndex) - : assert( - letterIndex < GameBloc.bonusWord.length, - 'Index must be smaller than the length of the word', - ); +class BonusActivated extends GameEvent { + const BonusActivated(this.bonus); - final int letterIndex; + final GameBonus bonus; @override - List get props => [letterIndex]; + List get props => [bonus]; } class DashNestActivated extends GameEvent { diff --git a/lib/game/bloc/game_state.dart b/lib/game/bloc/game_state.dart index 0d9485e9..8473057d 100644 --- a/lib/game/bloc/game_state.dart +++ b/lib/game/bloc/game_state.dart @@ -23,7 +23,6 @@ class GameState extends Equatable { const GameState({ required this.score, required this.balls, - required this.activatedBonusLetters, required this.bonusHistory, required this.activatedDashNests, }) : assert(score >= 0, "Score can't be negative"), @@ -32,7 +31,6 @@ class GameState extends Equatable { const GameState.initial() : score = 0, balls = 3, - activatedBonusLetters = const [], activatedDashNests = const {}, bonusHistory = const []; @@ -44,9 +42,6 @@ class GameState extends Equatable { /// When the number of balls is 0, the game is over. final int balls; - /// Active bonus letters. - final List activatedBonusLetters; - /// Active dash nests. final Set activatedDashNests; @@ -57,14 +52,9 @@ class GameState extends Equatable { /// Determines when the game is over. bool get isGameOver => balls == 0; - /// Shortcut method to check if the given [i] - /// is activated. - bool isLetterActivated(int i) => activatedBonusLetters.contains(i); - GameState copyWith({ int? score, int? balls, - List? activatedBonusLetters, Set? activatedDashNests, List? bonusHistory, }) { @@ -76,8 +66,6 @@ class GameState extends Equatable { return GameState( score: score ?? this.score, balls: balls ?? this.balls, - activatedBonusLetters: - activatedBonusLetters ?? this.activatedBonusLetters, activatedDashNests: activatedDashNests ?? this.activatedDashNests, bonusHistory: bonusHistory ?? this.bonusHistory, ); @@ -87,7 +75,6 @@ class GameState extends Equatable { List get props => [ score, balls, - activatedBonusLetters, activatedDashNests, bonusHistory, ]; diff --git a/lib/game/components/components.dart b/lib/game/components/components.dart index 058bfe20..e05f9f00 100644 --- a/lib/game/components/components.dart +++ b/lib/game/components/components.dart @@ -1,6 +1,5 @@ export 'alien_zone.dart'; export 'board.dart'; -export 'bonus_word.dart'; export 'camera_controller.dart'; export 'controlled_ball.dart'; export 'controlled_flipper.dart'; @@ -8,6 +7,7 @@ export 'controlled_plunger.dart'; export 'controlled_sparky_computer.dart'; export 'flutter_forest.dart'; export 'game_flow_controller.dart'; +export 'google_word.dart'; export 'launcher.dart'; export 'score_effect_controller.dart'; export 'score_points.dart'; diff --git a/lib/game/components/google_word.dart b/lib/game/components/google_word.dart new file mode 100644 index 00000000..73e78361 --- /dev/null +++ b/lib/game/components/google_word.dart @@ -0,0 +1,85 @@ +// ignore_for_file: avoid_renaming_method_parameters + +import 'dart:async'; + +import 'package:flame/components.dart'; +import 'package:flame_forge2d/flame_forge2d.dart'; +import 'package:flutter/material.dart'; +import 'package:pinball/flame/flame.dart'; +import 'package:pinball/game/game.dart'; +import 'package:pinball_components/pinball_components.dart'; + +/// {@template bonus_word} +/// Loads all [GoogleLetter]s to compose a [GoogleWord]. +/// {@endtemplate} +class GoogleWord extends Component + with HasGameRef, Controls<_GoogleWordController> { + /// {@macro bonus_word} + GoogleWord({ + required Vector2 position, + }) : _position = position { + controller = _GoogleWordController(this); + } + + final Vector2 _position; + + @override + Future onLoad() async { + await super.onLoad(); + + final offsets = [ + Vector2(-12.92, -1.82), + Vector2(-8.33, 0.65), + Vector2(-2.88, 1.75), + Vector2(2.88, 1.75), + Vector2(8.33, 0.65), + Vector2(12.92, -1.82), + ]; + + final letters = []; + for (var index = 0; index < offsets.length; index++) { + letters.add( + GoogleLetter(index)..initialPosition = _position + offsets[index], + ); + } + + await addAll(letters); + } +} + +class _GoogleWordController extends ComponentController + with HasGameRef { + _GoogleWordController(GoogleWord googleWord) : super(googleWord); + + static const _googleWord = 'Google'; + + final Set _activatedIndexes = {}; + + void activate(int index) { + if (!_activatedIndexes.add(index)) return; + + component.children.whereType().elementAt(index).activate(); + + final activatedBonus = _activatedIndexes.length == _googleWord.length; + if (activatedBonus) { + gameRef.audio.googleBonus(); + gameRef.read().add(const BonusActivated(GameBonus.word)); + component.children.whereType().forEach( + (letter) => letter.deactivate(), + ); + _activatedIndexes.clear(); + } + } +} + +/// Activates a [GoogleLetter] when it contacts with a [Ball]. +@visibleForTesting +class BonusLetterBallContactCallback + extends ContactCallback { + @override + void begin(Ball ball, GoogleLetter googleLetter, Contact contact) { + (googleLetter.parent! as GoogleWord) + .controller + .activate(googleLetter.index); + } +} diff --git a/lib/game/game_assets.dart b/lib/game/game_assets.dart index 4d06bd13..db4b89c3 100644 --- a/lib/game/game_assets.dart +++ b/lib/game/game_assets.dart @@ -58,6 +58,12 @@ extension PinballGameAssetsX on PinballGame { images.load(components.Assets.images.sparky.bumper.c.inactive.keyName), images.load(components.Assets.images.backboard.backboardScores.keyName), images.load(components.Assets.images.backboard.backboardGameOver.keyName), + images.load(components.Assets.images.googleWord.letter1.keyName), + images.load(components.Assets.images.googleWord.letter2.keyName), + images.load(components.Assets.images.googleWord.letter3.keyName), + images.load(components.Assets.images.googleWord.letter4.keyName), + images.load(components.Assets.images.googleWord.letter5.keyName), + images.load(components.Assets.images.googleWord.letter6.keyName), images.load(Assets.images.components.background.path), ]; } diff --git a/lib/game/pinball_game.dart b/lib/game/pinball_game.dart index 0dd1b52e..63165c66 100644 --- a/lib/game/pinball_game.dart +++ b/lib/game/pinball_game.dart @@ -82,7 +82,7 @@ class PinballGame extends Forge2DGame Future _addBonusWord() async { await add( - BonusWord( + GoogleWord( position: Vector2( BoardDimensions.bounds.center.dx - 4.1, BoardDimensions.bounds.center.dy + 1.8, diff --git a/packages/pinball_components/lib/src/components/google_letter.dart b/packages/pinball_components/lib/src/components/google_letter.dart index 9e9e2dec..65779fd6 100644 --- a/packages/pinball_components/lib/src/components/google_letter.dart +++ b/packages/pinball_components/lib/src/components/google_letter.dart @@ -9,11 +9,14 @@ import 'package:pinball_components/pinball_components.dart'; /// {@endtemplate} class GoogleLetter extends BodyComponent with InitialPosition { /// {@macro google_letter} - GoogleLetter(int index) + GoogleLetter(this.index) : _sprite = _GoogleLetterSprite( _GoogleLetterSprite.spritePaths[index], ); + /// Index of the letter in the "GOOGLE" word. + final int index; + final _GoogleLetterSprite _sprite; /// Activates this [GoogleLetter]. diff --git a/test/game/bloc/game_bloc_test.dart b/test/game/bloc/game_bloc_test.dart index fb543814..2d03e023 100644 --- a/test/game/bloc/game_bloc_test.dart +++ b/test/game/bloc/game_bloc_test.dart @@ -21,7 +21,6 @@ void main() { const GameState( score: 0, balls: 2, - activatedBonusLetters: [], activatedDashNests: {}, bonusHistory: [], ), @@ -41,14 +40,12 @@ void main() { const GameState( score: 2, balls: 3, - activatedBonusLetters: [], activatedDashNests: {}, bonusHistory: [], ), const GameState( score: 5, balls: 3, - activatedBonusLetters: [], activatedDashNests: {}, bonusHistory: [], ), @@ -69,21 +66,18 @@ void main() { const GameState( score: 0, balls: 2, - activatedBonusLetters: [], activatedDashNests: {}, bonusHistory: [], ), const GameState( score: 0, balls: 1, - activatedBonusLetters: [], activatedDashNests: {}, bonusHistory: [], ), const GameState( score: 0, balls: 0, - activatedBonusLetters: [], activatedDashNests: {}, bonusHistory: [], ), @@ -91,103 +85,6 @@ void main() { ); }); - group('BonusLetterActivated', () { - blocTest( - 'adds the letter to the state', - build: GameBloc.new, - act: (bloc) => bloc - ..add(const BonusLetterActivated(0)) - ..add(const BonusLetterActivated(1)) - ..add(const BonusLetterActivated(2)), - expect: () => const [ - GameState( - score: 0, - balls: 3, - activatedBonusLetters: [0], - activatedDashNests: {}, - bonusHistory: [], - ), - GameState( - score: 0, - balls: 3, - activatedBonusLetters: [0, 1], - activatedDashNests: {}, - bonusHistory: [], - ), - GameState( - score: 0, - balls: 3, - activatedBonusLetters: [0, 1, 2], - activatedDashNests: {}, - bonusHistory: [], - ), - ], - ); - - blocTest( - 'adds the bonus when the bonusWord is completed', - build: GameBloc.new, - act: (bloc) => bloc - ..add(const BonusLetterActivated(0)) - ..add(const BonusLetterActivated(1)) - ..add(const BonusLetterActivated(2)) - ..add(const BonusLetterActivated(3)) - ..add(const BonusLetterActivated(4)) - ..add(const BonusLetterActivated(5)), - expect: () => const [ - GameState( - score: 0, - balls: 3, - activatedBonusLetters: [0], - activatedDashNests: {}, - bonusHistory: [], - ), - GameState( - score: 0, - balls: 3, - activatedBonusLetters: [0, 1], - activatedDashNests: {}, - bonusHistory: [], - ), - GameState( - score: 0, - balls: 3, - activatedBonusLetters: [0, 1, 2], - activatedDashNests: {}, - bonusHistory: [], - ), - GameState( - score: 0, - balls: 3, - activatedBonusLetters: [0, 1, 2, 3], - activatedDashNests: {}, - bonusHistory: [], - ), - GameState( - score: 0, - balls: 3, - activatedBonusLetters: [0, 1, 2, 3, 4], - activatedDashNests: {}, - bonusHistory: [], - ), - GameState( - score: 0, - balls: 3, - activatedBonusLetters: [], - activatedDashNests: {}, - bonusHistory: [GameBonus.word], - ), - GameState( - score: GameBloc.bonusWordScore, - balls: 3, - activatedBonusLetters: [], - activatedDashNests: {}, - bonusHistory: [GameBonus.word], - ), - ], - ); - }); - group('DashNestActivated', () { blocTest( 'adds the bonus when all nests are activated', @@ -200,21 +97,18 @@ void main() { GameState( score: 0, balls: 3, - activatedBonusLetters: [], activatedDashNests: {'0'}, bonusHistory: [], ), GameState( score: 0, balls: 3, - activatedBonusLetters: [], activatedDashNests: {'0', '1'}, bonusHistory: [], ), GameState( score: 0, balls: 4, - activatedBonusLetters: [], activatedDashNests: {}, bonusHistory: [GameBonus.dashNest], ), @@ -231,7 +125,6 @@ void main() { GameState( score: 0, balls: 3, - activatedBonusLetters: [], activatedDashNests: {}, bonusHistory: [GameBonus.sparkyTurboCharge], ), diff --git a/test/game/bloc/game_event_test.dart b/test/game/bloc/game_event_test.dart index 68530aae..7f67daa8 100644 --- a/test/game/bloc/game_event_test.dart +++ b/test/game/bloc/game_event_test.dart @@ -41,61 +41,51 @@ void main() { }); }); - group('BonusLetterActivated', () { + group('BonusActivated', () { test('can be instantiated', () { - expect(const BonusLetterActivated(0), isNotNull); + expect(const BonusActivated(GameBonus.dashNest), isNotNull); }); test('supports value equality', () { expect( - BonusLetterActivated(0), - equals(BonusLetterActivated(0)), + BonusActivated(GameBonus.word), + equals(const BonusActivated(GameBonus.word)), ); expect( - BonusLetterActivated(0), - isNot(equals(BonusLetterActivated(1))), + const BonusActivated(GameBonus.word), + isNot(equals(const BonusActivated(GameBonus.dashNest))), ); }); - - test( - 'throws assertion error if index is bigger than the word length', - () { - expect( - () => BonusLetterActivated(8), - throwsAssertionError, - ); - }, - ); }); + }); - group('DashNestActivated', () { - test('can be instantiated', () { - expect(const DashNestActivated('0'), isNotNull); - }); + 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'))), - ); - }); + test('supports value equality', () { + expect( + DashNestActivated('0'), + equals(DashNestActivated('0')), + ); + expect( + DashNestActivated('0'), + isNot(equals(DashNestActivated('1'))), + ); }); + }); - group('SparkyTurboChargeActivated', () { - test('can be instantiated', () { - expect(const SparkyTurboChargeActivated(), isNotNull); - }); + group('SparkyTurboChargeActivated', () { + test('can be instantiated', () { + expect(const SparkyTurboChargeActivated(), isNotNull); + }); - test('supports value equality', () { - expect( - SparkyTurboChargeActivated(), - equals(SparkyTurboChargeActivated()), - ); - }); + test('supports value equality', () { + expect( + SparkyTurboChargeActivated(), + equals(SparkyTurboChargeActivated()), + ); }); }); } diff --git a/test/game/bloc/game_state_test.dart b/test/game/bloc/game_state_test.dart index ed80d192..fd97125c 100644 --- a/test/game/bloc/game_state_test.dart +++ b/test/game/bloc/game_state_test.dart @@ -10,7 +10,6 @@ void main() { GameState( score: 0, balls: 0, - activatedBonusLetters: const [], activatedDashNests: const {}, bonusHistory: const [], ), @@ -18,7 +17,6 @@ void main() { const GameState( score: 0, balls: 0, - activatedBonusLetters: [], activatedDashNests: {}, bonusHistory: [], ), @@ -32,7 +30,6 @@ void main() { const GameState( score: 0, balls: 0, - activatedBonusLetters: [], activatedDashNests: {}, bonusHistory: [], ), @@ -49,7 +46,6 @@ void main() { () => GameState( balls: -1, score: 0, - activatedBonusLetters: const [], activatedDashNests: const {}, bonusHistory: const [], ), @@ -66,7 +62,6 @@ void main() { () => GameState( balls: 0, score: -1, - activatedBonusLetters: const [], activatedDashNests: const {}, bonusHistory: const [], ), @@ -82,7 +77,6 @@ void main() { const gameState = GameState( balls: 0, score: 0, - activatedBonusLetters: [], activatedDashNests: {}, bonusHistory: [], ); @@ -95,7 +89,6 @@ void main() { const gameState = GameState( balls: 1, score: 0, - activatedBonusLetters: [], activatedDashNests: {}, bonusHistory: [], ); @@ -103,36 +96,6 @@ void main() { }); }); - group('isLetterActivated', () { - test( - 'is true when the letter is activated', - () { - const gameState = GameState( - balls: 3, - score: 0, - activatedBonusLetters: [1], - activatedDashNests: {}, - bonusHistory: [], - ); - expect(gameState.isLetterActivated(1), isTrue); - }, - ); - - test( - 'is false when the letter is not activated', - () { - const gameState = GameState( - balls: 3, - score: 0, - activatedBonusLetters: [1], - activatedDashNests: {}, - bonusHistory: [], - ); - expect(gameState.isLetterActivated(0), isFalse); - }, - ); - }); - group('copyWith', () { test( 'throws AssertionError ' @@ -141,7 +104,6 @@ void main() { const gameState = GameState( balls: 0, score: 2, - activatedBonusLetters: [], activatedDashNests: {}, bonusHistory: [], ); @@ -159,7 +121,6 @@ void main() { const gameState = GameState( balls: 0, score: 2, - activatedBonusLetters: [], activatedDashNests: {}, bonusHistory: [], ); @@ -177,14 +138,12 @@ void main() { const gameState = GameState( score: 2, balls: 0, - activatedBonusLetters: [], activatedDashNests: {}, bonusHistory: [], ); final otherGameState = GameState( score: gameState.score + 1, balls: gameState.balls + 1, - activatedBonusLetters: const [0], activatedDashNests: const {'1'}, bonusHistory: const [GameBonus.word], ); @@ -194,7 +153,6 @@ void main() { gameState.copyWith( score: otherGameState.score, balls: otherGameState.balls, - activatedBonusLetters: otherGameState.activatedBonusLetters, activatedDashNests: otherGameState.activatedDashNests, bonusHistory: otherGameState.bonusHistory, ), diff --git a/test/game/components/bonus_word_test.dart b/test/game/components/bonus_word_test.dart deleted file mode 100644 index f01fced9..00000000 --- a/test/game/components/bonus_word_test.dart +++ /dev/null @@ -1,376 +0,0 @@ -// ignore_for_file: cascade_invocations - -import 'package:bloc_test/bloc_test.dart'; -import 'package:flame/effects.dart'; -import 'package:flame_forge2d/flame_forge2d.dart'; -import 'package:flame_test/flame_test.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:mocktail/mocktail.dart'; -import 'package:pinball/game/game.dart'; -import 'package:pinball_audio/pinball_audio.dart'; - -import '../../helpers/helpers.dart'; - -void main() { - TestWidgetsFlutterBinding.ensureInitialized(); - final flameTester = FlameTester(EmptyPinballGameTest.new); - - group('BonusWord', () { - flameTester.test( - 'loads the letters correctly', - (game) async { - final bonusWord = BonusWord( - position: Vector2.zero(), - ); - await game.ensureAdd(bonusWord); - - final letters = bonusWord.descendants().whereType(); - expect(letters.length, equals(GameBloc.bonusWord.length)); - }, - ); - - group('listenWhen', () { - final previousState = MockGameState(); - final currentState = MockGameState(); - - test( - 'returns true when there is a new word bonus awarded', - () { - when(() => previousState.bonusHistory).thenReturn([]); - when(() => currentState.bonusHistory).thenReturn([GameBonus.word]); - - expect( - BonusWord(position: Vector2.zero()).listenWhen( - previousState, - currentState, - ), - isTrue, - ); - }, - ); - - test( - 'returns false when there is no new word bonus awarded', - () { - when(() => previousState.bonusHistory).thenReturn([GameBonus.word]); - when(() => currentState.bonusHistory).thenReturn([GameBonus.word]); - - expect( - BonusWord(position: Vector2.zero()).listenWhen( - previousState, - currentState, - ), - isFalse, - ); - }, - ); - }); - - group('onNewState', () { - final state = MockGameState(); - flameTester.test( - 'adds sequence effect to the letters when the player receives a bonus', - (game) async { - when(() => state.bonusHistory).thenReturn([GameBonus.word]); - - final bonusWord = BonusWord(position: Vector2.zero()); - await game.ensureAdd(bonusWord); - await game.ready(); - - bonusWord.onNewState(state); - game.update(0); // Run one frame so the effects are added - - final letters = bonusWord.children.whereType(); - expect(letters.length, equals(GameBloc.bonusWord.length)); - - for (final letter in letters) { - expect( - letter.children.whereType().length, - equals(1), - ); - } - }, - ); - - flameTester.test( - 'plays the google bonus sound', - (game) async { - when(() => state.bonusHistory).thenReturn([GameBonus.word]); - - final bonusWord = BonusWord(position: Vector2.zero()); - await game.ensureAdd(bonusWord); - await game.ready(); - - bonusWord.onNewState(state); - - verify(bonusWord.gameRef.audio.googleBonus).called(1); - }, - ); - - flameTester.test( - 'adds a color effect to reset the color when the sequence is finished', - (game) async { - when(() => state.bonusHistory).thenReturn([GameBonus.word]); - - final bonusWord = BonusWord(position: Vector2.zero()); - await game.ensureAdd(bonusWord); - await game.ready(); - - bonusWord.onNewState(state); - // Run the amount of time necessary for the animation to finish - game.update(3); - game.update(0); // Run one additional frame so the effects are added - - final letters = bonusWord.children.whereType(); - expect(letters.length, equals(GameBloc.bonusWord.length)); - - for (final letter in letters) { - expect( - letter.children.whereType().length, - equals(1), - ); - } - }, - ); - }); - }); - - group('BonusLetter', () { - final flameTester = FlameTester(EmptyPinballGameTest.new); - - flameTester.test( - 'loads correctly', - (game) async { - final bonusLetter = BonusLetter( - letter: 'G', - index: 0, - ); - await game.ensureAdd(bonusLetter); - await game.ready(); - - expect(game.contains(bonusLetter), isTrue); - }, - ); - - group('body', () { - flameTester.test( - 'is static', - (game) async { - final bonusLetter = BonusLetter( - letter: 'G', - index: 0, - ); - await game.ensureAdd(bonusLetter); - - expect(bonusLetter.body.bodyType, equals(BodyType.static)); - }, - ); - }); - - group('fixture', () { - flameTester.test( - 'exists', - (game) async { - final bonusLetter = BonusLetter( - letter: 'G', - index: 0, - ); - await game.ensureAdd(bonusLetter); - - expect(bonusLetter.body.fixtures[0], isA()); - }, - ); - - flameTester.test( - 'is sensor', - (game) async { - final bonusLetter = BonusLetter( - letter: 'G', - index: 0, - ); - await game.ensureAdd(bonusLetter); - - final fixture = bonusLetter.body.fixtures[0]; - expect(fixture.isSensor, isTrue); - }, - ); - - flameTester.test( - 'shape is circular', - (game) async { - final bonusLetter = BonusLetter( - letter: 'G', - index: 0, - ); - await game.ensureAdd(bonusLetter); - - final fixture = bonusLetter.body.fixtures[0]; - expect(fixture.shape.shapeType, equals(ShapeType.circle)); - expect(fixture.shape.radius, equals(1.85)); - }, - ); - }); - - group('bonus letter activation', () { - late GameBloc gameBloc; - late PinballAudio pinballAudio; - - final flameBlocTester = FlameBlocTester( - gameBuilder: EmptyPinballGameTest.new, - blocBuilder: () => gameBloc, - repositories: () => [ - RepositoryProvider.value(value: pinballAudio), - ], - ); - - setUp(() { - gameBloc = MockGameBloc(); - whenListen( - gameBloc, - const Stream.empty(), - initialState: const GameState.initial(), - ); - - pinballAudio = MockPinballAudio(); - when(pinballAudio.googleBonus).thenAnswer((_) {}); - }); - - flameBlocTester.testGameWidget( - 'adds BonusLetterActivated to GameBloc when not activated', - setUp: (game, tester) async { - final bonusWord = BonusWord( - position: Vector2.zero(), - ); - await game.ensureAdd(bonusWord); - - final bonusLetters = - game.descendants().whereType().toList(); - for (var index = 0; index < bonusLetters.length; index++) { - final bonusLetter = bonusLetters[index]; - bonusLetter.activate(); - await game.ready(); - - verify(() => gameBloc.add(BonusLetterActivated(index))).called(1); - } - }, - ); - - flameBlocTester.testGameWidget( - "doesn't add BonusLetterActivated to GameBloc when already activated", - setUp: (game, tester) async { - const state = GameState( - score: 0, - balls: 2, - activatedBonusLetters: [0], - activatedDashNests: {}, - bonusHistory: [], - ); - whenListen( - gameBloc, - Stream.value(state), - initialState: state, - ); - - final bonusLetter = BonusLetter(letter: '', index: 0); - await game.add(bonusLetter); - await game.ready(); - - bonusLetter.activate(); - await game.ready(); - }, - verify: (game, tester) async { - verifyNever(() => gameBloc.add(const BonusLetterActivated(0))); - }, - ); - - flameBlocTester.testGameWidget( - 'adds a ColorEffect', - setUp: (game, tester) async { - const state = GameState( - score: 0, - balls: 2, - activatedBonusLetters: [0], - activatedDashNests: {}, - bonusHistory: [], - ); - - final bonusLetter = BonusLetter(letter: '', index: 0); - await game.add(bonusLetter); - await game.ready(); - - bonusLetter.activate(); - - bonusLetter.onNewState(state); - await tester.pump(); - }, - verify: (game, tester) async { - // TODO(aleastiago): Look into making `testGameWidget` pass the - // subject. - final bonusLetter = game.descendants().whereType().last; - expect( - bonusLetter.children.whereType().length, - equals(1), - ); - }, - ); - - flameBlocTester.testGameWidget( - 'listens when there is a change on the letter status', - setUp: (game, tester) async { - final bonusWord = BonusWord( - position: Vector2.zero(), - ); - await game.ensureAdd(bonusWord); - - final bonusLetters = - game.descendants().whereType().toList(); - for (var index = 0; index < bonusLetters.length; index++) { - final bonusLetter = bonusLetters[index]; - bonusLetter.activate(); - await game.ready(); - - final state = GameState( - score: 0, - balls: 2, - activatedBonusLetters: [index], - activatedDashNests: const {}, - bonusHistory: const [], - ); - - expect( - bonusLetter.listenWhen(const GameState.initial(), state), - isTrue, - ); - } - }, - ); - }); - - group('BonusLetterBallContactCallback', () { - test('calls ball.activate', () { - final ball = MockBall(); - final bonusLetter = MockBonusLetter(); - final contactCallback = BonusLetterBallContactCallback(); - - when(() => bonusLetter.isEnabled).thenReturn(true); - - contactCallback.begin(ball, bonusLetter, MockContact()); - - verify(bonusLetter.activate).called(1); - }); - - test("doesn't call ball.activate when letter is disabled", () { - final ball = MockBall(); - final bonusLetter = MockBonusLetter(); - final contactCallback = BonusLetterBallContactCallback(); - - when(() => bonusLetter.isEnabled).thenReturn(false); - - contactCallback.begin(ball, bonusLetter, MockContact()); - - verifyNever(bonusLetter.activate); - }); - }); - }); -} diff --git a/test/game/components/flutter_forest_test.dart b/test/game/components/flutter_forest_test.dart index e9e58985..ac35e363 100644 --- a/test/game/components/flutter_forest_test.dart +++ b/test/game/components/flutter_forest_test.dart @@ -95,7 +95,6 @@ void main() { const state = GameState( score: 0, balls: 3, - activatedBonusLetters: [], activatedDashNests: {}, bonusHistory: [GameBonus.dashNest], ); diff --git a/test/game/components/game_flow_controller_test.dart b/test/game/components/game_flow_controller_test.dart index dc1d9ab8..615d1097 100644 --- a/test/game/components/game_flow_controller_test.dart +++ b/test/game/components/game_flow_controller_test.dart @@ -15,7 +15,6 @@ void main() { final state = GameState( score: 10, balls: 0, - activatedBonusLetters: const [], bonusHistory: const [], activatedDashNests: const {}, ); @@ -61,7 +60,6 @@ void main() { GameState( score: 10, balls: 0, - activatedBonusLetters: const [], bonusHistory: const [], activatedDashNests: const {}, ), diff --git a/test/game/components/google_word_test.dart b/test/game/components/google_word_test.dart new file mode 100644 index 00000000..73e555fe --- /dev/null +++ b/test/game/components/google_word_test.dart @@ -0,0 +1,35 @@ +// ignore_for_file: cascade_invocations + +import 'package:flame_forge2d/flame_forge2d.dart'; +import 'package:flame_test/flame_test.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:pinball/game/game.dart'; +import 'package:pinball_components/pinball_components.dart'; + +import '../../helpers/helpers.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + final flameTester = FlameTester(EmptyPinballGameTest.new); + + group('GoogleWord', () { + const googleWord = 'Google'; + + flameTester.test( + 'loads the letters correctly', + (game) async { + final bonusWord = GoogleWord( + position: Vector2.zero(), + ); + await game.ensureAdd(bonusWord); + + final letters = bonusWord.children.whereType(); + expect(letters, equals(googleWord.length)); + + for (var index = 0; index < googleWord.length; index++) { + expect(letters.elementAt(index).index, equals(index)); + } + }, + ); + }); +} diff --git a/test/game/components/score_effect_controller_test.dart b/test/game/components/score_effect_controller_test.dart index 241f040b..9d2b5310 100644 --- a/test/game/components/score_effect_controller_test.dart +++ b/test/game/components/score_effect_controller_test.dart @@ -30,7 +30,6 @@ void main() { const current = GameState( score: 10, balls: 3, - activatedBonusLetters: [], bonusHistory: [], activatedDashNests: {}, ); @@ -44,7 +43,6 @@ void main() { const current = GameState( score: 10, balls: 3, - activatedBonusLetters: [], bonusHistory: [], activatedDashNests: {}, ); @@ -70,7 +68,6 @@ void main() { const state = GameState( score: 10, balls: 3, - activatedBonusLetters: [], bonusHistory: [], activatedDashNests: {}, ); @@ -89,7 +86,6 @@ void main() { const GameState( score: 10, balls: 3, - activatedBonusLetters: [], bonusHistory: [], activatedDashNests: {}, ), @@ -99,7 +95,6 @@ void main() { const GameState( score: 14, balls: 3, - activatedBonusLetters: [], bonusHistory: [], activatedDashNests: {}, ), diff --git a/test/game/view/game_hud_test.dart b/test/game/view/game_hud_test.dart index 953b89eb..2d5f50d9 100644 --- a/test/game/view/game_hud_test.dart +++ b/test/game/view/game_hud_test.dart @@ -12,7 +12,6 @@ void main() { const initialState = GameState( score: 10, balls: 2, - activatedBonusLetters: [], activatedDashNests: {}, bonusHistory: [], ); diff --git a/test/helpers/mocks.dart b/test/helpers/mocks.dart index df6728cc..12e6d366 100644 --- a/test/helpers/mocks.dart +++ b/test/helpers/mocks.dart @@ -64,8 +64,6 @@ class MockTapUpInfo extends Mock implements TapUpInfo {} class MockEventPosition extends Mock implements EventPosition {} -class MockBonusLetter extends Mock implements BonusLetter {} - class MockFilter extends Mock implements Filter {} class MockFixture extends Mock implements Fixture {}