From 2efa1107182437558b7399d4e20e1125b2ed7aa5 Mon Sep 17 00:00:00 2001 From: RuiAlonso Date: Tue, 26 Apr 2022 20:09:50 +0200 Subject: [PATCH] feat: added controller for multiball --- lib/game/components/components.dart | 1 + lib/game/components/controlled_multiball.dart | 52 ++++++++ lib/game/pinball_game.dart | 1 + .../components/controlled_multiball_test.dart | 111 ++++++++++++++++++ test/game/pinball_game_test.dart | 8 ++ 5 files changed, 173 insertions(+) create mode 100644 lib/game/components/controlled_multiball.dart create mode 100644 test/game/components/controlled_multiball_test.dart diff --git a/lib/game/components/components.dart b/lib/game/components/components.dart index 7d4b23f7..00ae4a36 100644 --- a/lib/game/components/components.dart +++ b/lib/game/components/components.dart @@ -3,6 +3,7 @@ export 'board.dart'; export 'camera_controller.dart'; export 'controlled_ball.dart'; export 'controlled_flipper.dart'; +export 'controlled_multiball.dart'; export 'controlled_plunger.dart'; export 'flutter_forest.dart'; export 'game_flow_controller.dart'; diff --git a/lib/game/components/controlled_multiball.dart b/lib/game/components/controlled_multiball.dart new file mode 100644 index 00000000..cdebea24 --- /dev/null +++ b/lib/game/components/controlled_multiball.dart @@ -0,0 +1,52 @@ +import 'package:flame/components.dart'; +import 'package:flame_bloc/flame_bloc.dart'; +import 'package:flutter/material.dart'; +import 'package:pinball/game/game.dart'; +import 'package:pinball_components/pinball_components.dart'; +import 'package:pinball_flame/pinball_flame.dart'; + +/// {@template multiball_group_component} +/// A [SpriteGroupComponent] for the multiball over the board. +/// {@endtemplate} +class MultiballGroup extends Component + with Controls, HasGameRef { + /// {@macro multiball_group_component} + MultiballGroup() + : super( + children: [ + Multiball.a(), + Multiball.b(), + Multiball.c(), + Multiball.d(), + ], + ) { + controller = MultiballController(this); + } +} + +/// {@template multiball_controller} +/// Controller attached to a [MultiballGroup] that handles its game related +/// logic. +/// {@endtemplate} +@visibleForTesting +class MultiballController extends ComponentController + with BlocComponent, HasGameRef { + /// {@macro multiball_controller} + MultiballController(MultiballGroup multiballGroup) : super(multiballGroup); + + @override + bool listenWhen(GameState? previousState, GameState newState) { + return previousState?.bonusHistory != newState.bonusHistory; + } + + @override + void onNewState(GameState state) { + final isMultiball = state.bonusHistory.contains(GameBonus.dashNest); + + if (isMultiball) { + component.children.whereType().forEach((element) { + element.animate(); + }); + } + } +} diff --git a/lib/game/pinball_game.dart b/lib/game/pinball_game.dart index 55a6b23a..464543c5 100644 --- a/lib/game/pinball_game.dart +++ b/lib/game/pinball_game.dart @@ -55,6 +55,7 @@ class PinballGame extends Forge2DGame final launcher = Launcher(); unawaited(addFromBlueprint(launcher)); unawaited(add(Board())); + unawaited(add(MultiballGroup())); unawaited(add(AlienZone())); await addFromBlueprint(SparkyFireZone()); unawaited(addFromBlueprint(Slingshots())); diff --git a/test/game/components/controlled_multiball_test.dart b/test/game/components/controlled_multiball_test.dart new file mode 100644 index 00000000..49768a7d --- /dev/null +++ b/test/game/components/controlled_multiball_test.dart @@ -0,0 +1,111 @@ +// ignore_for_file: cascade_invocations + +import 'package:flame_test/flame_test.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:pinball/game/game.dart'; +import 'package:pinball_components/pinball_components.dart'; + +import '../../helpers/helpers.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + final assets = [ + Assets.images.multiball.a.active.keyName, + Assets.images.multiball.a.inactive.keyName, + Assets.images.multiball.b.active.keyName, + Assets.images.multiball.b.inactive.keyName, + Assets.images.multiball.c.active.keyName, + Assets.images.multiball.c.inactive.keyName, + Assets.images.multiball.d.active.keyName, + Assets.images.multiball.d.inactive.keyName, + ]; + final flameTester = FlameTester(() => EmptyPinballTestGame(assets)); + + group('MultiballGroup', () { + flameTester.test( + 'loads correctly', + (game) async { + final multiballGroup = MultiballGroup(); + await game.ensureAdd(multiballGroup); + + expect(game.contains(multiballGroup), isTrue); + }, + ); + + group('loads', () { + flameTester.test( + 'four Multiball', + (game) async { + final multiballGroup = MultiballGroup(); + await game.ensureAdd(multiballGroup); + + expect( + multiballGroup.descendants().whereType().length, + equals(4), + ); + }, + ); + }); + }); + group('MultiballController', () { + group('controller', () { + group('listenWhen', () { + flameTester.test( + 'listens when obtain a multiball bonus', + (game) async { + const previous = GameState.initial(); + final state = previous.copyWith(bonusHistory: [GameBonus.dashNest]); + + final multiballGroup = MultiballGroup(); + await game.ensureAdd(multiballGroup); + + expect( + multiballGroup.controller.listenWhen(previous, state), + isTrue, + ); + }, + ); + + flameTester.test( + "doesn't listen when bonus is the same", + (game) async { + const previous = GameState.initial(); + + final multiballGroup = MultiballGroup(); + await game.ensureAdd(multiballGroup); + + expect( + multiballGroup.controller.listenWhen(previous, previous), + isFalse, + ); + }, + ); + }); + + /* + group( + 'onNewState', + () { + flameTester.test( + 'blink multiballs when state changes', + (game) async { + final multiballGroup = MockMultiballGroup(); + final x2multiplier = MockMultiplier(); + final controller = MultiballController(multiballGroup); + when(() => multiballGroup.x2multiplier).thenReturn(x2multiplier); + + controller.onNewState( + const GameState.initial() + .copyWith(bonusHistory: [GameBonus.dashNest]), + ); + + verify(() => x2multiplier.toggle(any())).called(1); + }, + ); + }, + ); + */ + }); + }); +} diff --git a/test/game/pinball_game_test.dart b/test/game/pinball_game_test.dart index d6bbb099..e4035afe 100644 --- a/test/game/pinball_game_test.dart +++ b/test/game/pinball_game_test.dart @@ -56,6 +56,14 @@ void main() { Assets.images.slingshot.lower.keyName, Assets.images.dino.dinoLandTop.keyName, Assets.images.dino.dinoLandBottom.keyName, + Assets.images.multiball.a.active.keyName, + Assets.images.multiball.a.inactive.keyName, + Assets.images.multiball.b.active.keyName, + Assets.images.multiball.b.inactive.keyName, + Assets.images.multiball.c.active.keyName, + Assets.images.multiball.c.inactive.keyName, + Assets.images.multiball.d.active.keyName, + Assets.images.multiball.d.inactive.keyName, ]; final flameTester = FlameTester(() => PinballTestGame(assets)); final debugModeFlameTester = FlameTester(() => DebugPinballTestGame(assets));