From 78a616ccd115eda413f66331dc3f9d6073a6bca8 Mon Sep 17 00:00:00 2001 From: Erick Date: Mon, 14 Mar 2022 16:52:13 -0300 Subject: [PATCH 1/6] feat: adding effect on completing bonus word (#44) * feat: adding effect on completing bonus word * Apply suggestions from code review Co-authored-by: Allison Ryan <77211884+allisonryan0002@users.noreply.github.com> * feat: pr suggestions Co-authored-by: Allison Ryan <77211884+allisonryan0002@users.noreply.github.com> --- lib/game/components/bonus_word.dart | 49 ++++++++++++- test/game/components/bonus_word_test.dart | 89 +++++++++++++++++++++++ test/helpers/mocks.dart | 2 + 3 files changed, 139 insertions(+), 1 deletion(-) diff --git a/lib/game/components/bonus_word.dart b/lib/game/components/bonus_word.dart index 35412ecf..49a1da1d 100644 --- a/lib/game/components/bonus_word.dart +++ b/lib/game/components/bonus_word.dart @@ -12,12 +12,59 @@ import 'package:pinball/game/game.dart'; /// {@template bonus_word} /// Loads all [BonusLetter]s to compose a [BonusWord]. /// {@endtemplate} -class BonusWord extends Component { +class BonusWord extends Component with BlocComponent { /// {@macro bonus_word} BonusWord({required Vector2 position}) : _position = position; final Vector2 _position; + @override + bool listenWhen(GameState? previousState, GameState newState) { + if ((previousState?.bonusHistory.length ?? 0) < + newState.bonusHistory.length && + newState.bonusHistory.last == GameBonus.word) { + return true; + } + + return false; + } + + @override + void onNewState(GameState state) { + if (state.bonusHistory.last == GameBonus.word) { + final letters = children.whereType().toList(); + + for (var i = 0; i < letters.length; i++) { + final letter = letters[i]; + letter.add( + SequenceEffect( + [ + ColorEffect( + i.isOdd ? BonusLetter._activeColor : BonusLetter._disableColor, + const Offset(0, 1), + EffectController(duration: 0.25), + ), + ColorEffect( + i.isOdd ? BonusLetter._disableColor : BonusLetter._activeColor, + const Offset(0, 1), + EffectController(duration: 0.25), + ), + ], + repeatCount: 4, + )..onFinishCallback = () { + letter.add( + ColorEffect( + BonusLetter._disableColor, + const Offset(0, 1), + EffectController(duration: 0.25), + ), + ); + }, + ); + } + } + } + @override Future onLoad() async { await super.onLoad(); diff --git a/test/game/components/bonus_word_test.dart b/test/game/components/bonus_word_test.dart index 129f68d1..012ef2d8 100644 --- a/test/game/components/bonus_word_test.dart +++ b/test/game/components/bonus_word_test.dart @@ -26,6 +26,95 @@ void main() { 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( + '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', () { diff --git a/test/helpers/mocks.dart b/test/helpers/mocks.dart index c1c59377..80820c1b 100644 --- a/test/helpers/mocks.dart +++ b/test/helpers/mocks.dart @@ -18,6 +18,8 @@ class MockContact extends Mock implements Contact {} class MockGameBloc extends Mock implements GameBloc {} +class MockGameState extends Mock implements GameState {} + class MockThemeCubit extends Mock implements ThemeCubit {} class MockRawKeyDownEvent extends Mock implements RawKeyDownEvent { From 45f1c6e48bf09ee8529ce762c3a70721abf9363a Mon Sep 17 00:00:00 2001 From: Allison Ryan <77211884+allisonryan0002@users.noreply.github.com> Date: Mon, 14 Mar 2022 15:27:03 -0500 Subject: [PATCH 2/6] feat: add how to play dialog (#45) * feat: add how to play dialog * style: comma for readability --- lib/l10n/arb/app_en.arb | 12 ++ lib/landing/view/landing_page.dart | 178 ++++++++++++++++++++++- test/landing/view/landing_page_test.dart | 58 ++++++-- 3 files changed, 234 insertions(+), 14 deletions(-) diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index f12ccf7d..a118501e 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -4,6 +4,18 @@ "@play": { "description": "Text displayed on the landing page play button" }, + "howToPlay": "How to Play", + "@howToPlay": { + "description": "Text displayed on the landing page how to play button" + }, + "launchControls": "Launch Controls", + "@launchControls": { + "description": "Text displayed on the how to play dialog with the launch controls" + }, + "flipperControls": "Flipper Controls", + "@flipperControls": { + "description": "Text displayed on the how to play dialog with the flipper controls" + }, "start": "Start", "@start": { "description": "Text displayed on the character selection page start button" diff --git a/lib/landing/view/landing_page.dart b/lib/landing/view/landing_page.dart index 38951da6..5b0474b6 100644 --- a/lib/landing/view/landing_page.dart +++ b/lib/landing/view/landing_page.dart @@ -13,12 +13,182 @@ class LandingPage extends StatelessWidget { return Scaffold( body: Center( - child: TextButton( - onPressed: () => - Navigator.of(context).push(CharacterSelectionPage.route()), - child: Text(l10n.play), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + TextButton( + onPressed: () => Navigator.of(context).push( + CharacterSelectionPage.route(), + ), + child: Text(l10n.play), + ), + TextButton( + onPressed: () => showDialog( + context: context, + builder: (_) => const _HowToPlayDialog(), + ), + child: Text(l10n.howToPlay), + ), + ], ), ), ); } } + +class _HowToPlayDialog extends StatelessWidget { + const _HowToPlayDialog({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final l10n = context.l10n; + const spacing = SizedBox(height: 16); + + return Dialog( + child: Padding( + padding: const EdgeInsets.all(20), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text(l10n.howToPlay), + spacing, + const _LaunchControls(), + spacing, + const _FlipperControls(), + ], + ), + ), + ); + } +} + +class _LaunchControls extends StatelessWidget { + const _LaunchControls({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final l10n = context.l10n; + const spacing = SizedBox(width: 10); + + return Column( + children: [ + Text(l10n.launchControls), + const SizedBox(height: 10), + Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: const [ + KeyIndicator.fromIcon(keyIcon: Icons.keyboard_arrow_down), + spacing, + KeyIndicator.fromKeyName(keyName: 'SPACE'), + spacing, + KeyIndicator.fromKeyName(keyName: 'S'), + ], + ) + ], + ); + } +} + +class _FlipperControls extends StatelessWidget { + const _FlipperControls({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final l10n = context.l10n; + const rowSpacing = SizedBox(width: 20); + + return Column( + children: [ + Text(l10n.flipperControls), + const SizedBox(height: 10), + Column( + children: [ + Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: const [ + KeyIndicator.fromIcon(keyIcon: Icons.keyboard_arrow_left), + rowSpacing, + KeyIndicator.fromIcon(keyIcon: Icons.keyboard_arrow_right), + ], + ), + const SizedBox(height: 8), + Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: const [ + KeyIndicator.fromKeyName(keyName: 'A'), + rowSpacing, + KeyIndicator.fromKeyName(keyName: 'D'), + ], + ) + ], + ) + ], + ); + } +} + +// TODO(allisonryan0002): remove visibility when adding final UI. +@visibleForTesting +class KeyIndicator extends StatelessWidget { + const KeyIndicator._({ + Key? key, + required String keyName, + required IconData keyIcon, + required bool fromIcon, + }) : _keyName = keyName, + _keyIcon = keyIcon, + _fromIcon = fromIcon, + super(key: key); + + const KeyIndicator.fromKeyName({Key? key, required String keyName}) + : this._( + key: key, + keyName: keyName, + keyIcon: Icons.keyboard_arrow_down, + fromIcon: false, + ); + + const KeyIndicator.fromIcon({Key? key, required IconData keyIcon}) + : this._( + key: key, + keyName: '', + keyIcon: keyIcon, + fromIcon: true, + ); + + final String _keyName; + + final IconData _keyIcon; + + final bool _fromIcon; + + @override + Widget build(BuildContext context) { + const iconPadding = EdgeInsets.all(15); + const textPadding = EdgeInsets.symmetric(vertical: 20, horizontal: 22); + final boarderColor = Colors.blue.withOpacity(0.5); + final color = Colors.blue.withOpacity(0.7); + + return DecoratedBox( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(5), + border: Border.all( + color: boarderColor, + width: 3, + ), + ), + child: _fromIcon + ? Padding( + padding: iconPadding, + child: Icon(_keyIcon, color: color), + ) + : Padding( + padding: textPadding, + child: Text(_keyName, style: TextStyle(color: color)), + ), + ); + } +} diff --git a/test/landing/view/landing_page_test.dart b/test/landing/view/landing_page_test.dart index ab036f9c..369f8cab 100644 --- a/test/landing/view/landing_page_test.dart +++ b/test/landing/view/landing_page_test.dart @@ -1,33 +1,71 @@ +// ignore_for_file: prefer_const_constructors + import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockingjay/mockingjay.dart'; +import 'package:pinball/l10n/l10n.dart'; import 'package:pinball/landing/landing.dart'; import '../../helpers/helpers.dart'; void main() { group('LandingPage', () { - testWidgets('renders TextButton', (tester) async { - await tester.pumpApp(const LandingPage()); - expect(find.byType(TextButton), findsOneWidget); + testWidgets('renders correctly', (tester) async { + final l10n = await AppLocalizations.delegate.load(Locale('en')); + await tester.pumpApp(LandingPage()); + + expect(find.byType(TextButton), findsNWidgets(2)); + expect(find.text(l10n.play), findsOneWidget); + expect(find.text(l10n.howToPlay), findsOneWidget); }); - testWidgets('tapping on TextButton navigates to CharacterSelectionPage', + testWidgets('tapping on play button navigates to CharacterSelectionPage', (tester) async { + final l10n = await AppLocalizations.delegate.load(Locale('en')); final navigator = MockNavigator(); when(() => navigator.push(any())).thenAnswer((_) async {}); await tester.pumpApp( - const LandingPage(), + LandingPage(), navigator: navigator, ); - await tester.tap( - find.byType( - TextButton, - ), - ); + + await tester.tap(find.widgetWithText(TextButton, l10n.play)); verify(() => navigator.push(any())).called(1); }); + + testWidgets('tapping on how to play button displays dialog with controls', + (tester) async { + final l10n = await AppLocalizations.delegate.load(Locale('en')); + await tester.pumpApp(LandingPage()); + + await tester.tap(find.widgetWithText(TextButton, l10n.howToPlay)); + await tester.pump(); + + expect(find.byType(Dialog), findsOneWidget); + }); + }); + + group('KeyIndicator', () { + testWidgets('fromKeyName renders correctly', (tester) async { + const keyName = 'A'; + + await tester.pumpApp( + KeyIndicator.fromKeyName(keyName: keyName), + ); + + expect(find.text(keyName), findsOneWidget); + }); + + testWidgets('fromIcon renders correctly', (tester) async { + const keyIcon = Icons.keyboard_arrow_down; + + await tester.pumpApp( + KeyIndicator.fromIcon(keyIcon: keyIcon), + ); + + expect(find.byIcon(keyIcon), findsOneWidget); + }); }); } From 902aacce2c5d6672dcff254b308f5315cc5bb6a9 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 15 Mar 2022 06:34:35 +0000 Subject: [PATCH 3/6] feat: geometric centroid (#38) * docs: rephrased description * feat: included geometry method * feat: simplified centroid * Update packages/geometry/test/src/geometry_test.dart Co-authored-by: Allison Ryan <77211884+allisonryan0002@users.noreply.github.com> * chore: rebase * refactor: removed throwsAssertionError for throwsA matcher * docs: rephrased doc comment Co-authored-by: Allison Ryan <77211884+allisonryan0002@users.noreply.github.com> --- packages/geometry/README.md | 2 +- packages/geometry/lib/src/geometry.dart | 9 +++++++ packages/geometry/pubspec.yaml | 2 +- packages/geometry/test/src/geometry_test.dart | 25 +++++++++++++++++++ 4 files changed, 36 insertions(+), 2 deletions(-) diff --git a/packages/geometry/README.md b/packages/geometry/README.md index f0841d82..ad11d280 100644 --- a/packages/geometry/README.md +++ b/packages/geometry/README.md @@ -3,7 +3,7 @@ [![style: very good analysis][very_good_analysis_badge]][very_good_analysis_link] [![License: MIT][license_badge]][license_link] -Helper package to calculate points of lines, arcs and curves for the pathways of the ball. +Provides a set of helpers for working with 2D geometry. [license_badge]: https://img.shields.io/badge/license-MIT-blue.svg [license_link]: https://opensource.org/licenses/MIT diff --git a/packages/geometry/lib/src/geometry.dart b/packages/geometry/lib/src/geometry.dart index 6ada92e0..8574bc73 100644 --- a/packages/geometry/lib/src/geometry.dart +++ b/packages/geometry/lib/src/geometry.dart @@ -106,3 +106,12 @@ num factorial(num n) { return n * factorial(n - 1); } } + +/// Arithmetic mean position of all the [Vector2]s in a polygon. +/// +/// For more information read: https://en.wikipedia.org/wiki/Centroid +Vector2 centroid(List vertices) { + assert(vertices.isNotEmpty, 'Vertices must not be empty'); + final sum = vertices.reduce((a, b) => a + b); + return sum / vertices.length.toDouble(); +} diff --git a/packages/geometry/pubspec.yaml b/packages/geometry/pubspec.yaml index 8fffb8b3..da305129 100644 --- a/packages/geometry/pubspec.yaml +++ b/packages/geometry/pubspec.yaml @@ -1,5 +1,5 @@ name: geometry -description: Helper package to calculate points of lines, arcs and curves for the pathways of the ball +description: Provides a set of helpers for working with 2D geometry. version: 1.0.0+1 publish_to: none diff --git a/packages/geometry/test/src/geometry_test.dart b/packages/geometry/test/src/geometry_test.dart index 2a5f9169..5c33d70f 100644 --- a/packages/geometry/test/src/geometry_test.dart +++ b/packages/geometry/test/src/geometry_test.dart @@ -166,4 +166,29 @@ void main() { }); }); }); + + group('centroid', () { + test('throws AssertionError when vertices are empty', () { + expect(() => centroid([]), throwsA(isA())); + }); + + test('is correct when one vertex is given', () { + expect(centroid([Vector2.zero()]), Vector2.zero()); + }); + + test('is correct when two vertex are given', () { + expect(centroid([Vector2.zero(), Vector2(1, 1)]), Vector2(0.5, 0.5)); + }); + + test('is correct when three vertex are given', () { + expect( + centroid([ + Vector2.zero(), + Vector2(1, 1), + Vector2(2, 2), + ]), + Vector2(1, 1), + ); + }); + }); } From b0932799eb434ff015e952392ad6086b02465dc8 Mon Sep 17 00:00:00 2001 From: alestiago Date: Tue, 15 Mar 2022 06:52:41 +0000 Subject: [PATCH 4/6] refactor: used Forge2DGame where possible --- test/game/components/ball_test.dart | 3 +-- test/game/components/baseboard_test.dart | 4 +--- test/game/components/bonus_word_test.dart | 3 +-- test/game/components/flipper_test.dart | 1 + test/game/components/joint_anchor_test.dart | 5 +---- test/game/components/pathway_test.dart | 4 +--- test/game/components/plunger_test.dart | 2 +- test/game/components/wall_test.dart | 2 +- 8 files changed, 8 insertions(+), 16 deletions(-) diff --git a/test/game/components/ball_test.dart b/test/game/components/ball_test.dart index 8ac32212..e83dd619 100644 --- a/test/game/components/ball_test.dart +++ b/test/game/components/ball_test.dart @@ -11,10 +11,9 @@ import '../../helpers/helpers.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); + final flameTester = FlameTester(PinballGameTest.create); group('Ball', () { - final flameTester = FlameTester(PinballGameTest.create); - flameTester.test( 'loads correctly', (game) async { diff --git a/test/game/components/baseboard_test.dart b/test/game/components/baseboard_test.dart index 51002cef..bc9f68af 100644 --- a/test/game/components/baseboard_test.dart +++ b/test/game/components/baseboard_test.dart @@ -5,12 +5,10 @@ import 'package:flame_test/flame_test.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:pinball/game/game.dart'; -import '../../helpers/helpers.dart'; - void main() { group('Baseboard', () { TestWidgetsFlutterBinding.ensureInitialized(); - final flameTester = FlameTester(PinballGameTest.create); + final flameTester = FlameTester(Forge2DGame.new); flameTester.test( 'loads correctly', diff --git a/test/game/components/bonus_word_test.dart b/test/game/components/bonus_word_test.dart index 012ef2d8..b45bd61a 100644 --- a/test/game/components/bonus_word_test.dart +++ b/test/game/components/bonus_word_test.dart @@ -12,10 +12,9 @@ import '../../helpers/helpers.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); + final flameTester = FlameTester(PinballGameTest.create); group('BonusWord', () { - final flameTester = FlameTester(PinballGameTest.create); - flameTester.test( 'loads the letters correctly', (game) async { diff --git a/test/game/components/flipper_test.dart b/test/game/components/flipper_test.dart index ead927bf..0e281d07 100644 --- a/test/game/components/flipper_test.dart +++ b/test/game/components/flipper_test.dart @@ -176,6 +176,7 @@ void main() { final flipper = Flipper.left(position: Vector2.zero()); final ball = Ball(position: Vector2.zero()); + await game.ready(); await game.ensureAddAll([flipper, ball]); expect( diff --git a/test/game/components/joint_anchor_test.dart b/test/game/components/joint_anchor_test.dart index a65f9e1a..8278d43a 100644 --- a/test/game/components/joint_anchor_test.dart +++ b/test/game/components/joint_anchor_test.dart @@ -5,14 +5,11 @@ import 'package:flame_test/flame_test.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:pinball/game/game.dart'; -import '../../helpers/helpers.dart'; - void main() { TestWidgetsFlutterBinding.ensureInitialized(); + final flameTester = FlameTester(Forge2DGame.new); group('JointAnchor', () { - final flameTester = FlameTester(PinballGameTest.create); - flameTester.test( 'loads correctly', (game) async { diff --git a/test/game/components/pathway_test.dart b/test/game/components/pathway_test.dart index 43af9b77..80c968d8 100644 --- a/test/game/components/pathway_test.dart +++ b/test/game/components/pathway_test.dart @@ -6,11 +6,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:pinball/game/game.dart'; -import '../../helpers/helpers.dart'; - void main() { TestWidgetsFlutterBinding.ensureInitialized(); - final flameTester = FlameTester(PinballGameTest.create); + final flameTester = FlameTester(Forge2DGame.new); group('Pathway', () { const width = 50.0; diff --git a/test/game/components/plunger_test.dart b/test/game/components/plunger_test.dart index 1ca29e85..ecc4265e 100644 --- a/test/game/components/plunger_test.dart +++ b/test/game/components/plunger_test.dart @@ -13,7 +13,7 @@ import '../../helpers/helpers.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); - final flameTester = FlameTester(PinballGameTest.create); + final flameTester = FlameTester(Forge2DGame.new); group('Plunger', () { const compressionDistance = 0.0; diff --git a/test/game/components/wall_test.dart b/test/game/components/wall_test.dart index e60046ad..774cd675 100644 --- a/test/game/components/wall_test.dart +++ b/test/game/components/wall_test.dart @@ -10,6 +10,7 @@ import '../../helpers/helpers.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); + final flameTester = FlameTester(Forge2DGame.new); group('Wall', () { group('BottomWallBallContactCallback', () { @@ -32,7 +33,6 @@ void main() { }, ); }); - final flameTester = FlameTester(PinballGameTest.create); flameTester.test( 'loads correctly', From 963b400c413f990511abb95f399c4e410d3bcb18 Mon Sep 17 00:00:00 2001 From: alestiago Date: Tue, 15 Mar 2022 06:57:55 +0000 Subject: [PATCH 5/6] refactor: simplified testing for components in tree --- test/game/pinball_game_test.dart | 33 ++++++++++---------------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/test/game/pinball_game_test.dart b/test/game/pinball_game_test.dart index a992a471..f79d19d5 100644 --- a/test/game/pinball_game_test.dart +++ b/test/game/pinball_game_test.dart @@ -18,18 +18,13 @@ void main() { // [BallScorePointsCallback] once the following issue is resolved: // https://github.com/flame-engine/flame/issues/1416 group('components', () { - bool Function(Component) componentSelector() => - (component) => component is T; - flameTester.test( 'has three Walls', (game) async { await game.ready(); - final walls = game.children - .where( - (component) => component is Wall && component is! BottomWall, - ) - .toList(); + final walls = game.children.where( + (component) => component is Wall && component is! BottomWall, + ); // TODO(allisonryan0002): expect 3 when launch track is added and // temporary wall is removed. expect(walls.length, 4); @@ -42,10 +37,8 @@ void main() { await game.ready(); expect( - () => game.children.singleWhere( - componentSelector(), - ), - returnsNormally, + game.children.whereType().length, + equals(1), ); }, ); @@ -54,24 +47,18 @@ void main() { 'has only one Plunger', (game) async { await game.ready(); - expect( - () => game.children.singleWhere( - (component) => component is Plunger, - ), - returnsNormally, + game.children.whereType().length, + equals(1), ); }, ); flameTester.test('has only one FlipperGroup', (game) async { await game.ready(); - expect( - () => game.children.singleWhere( - (component) => component is FlipperGroup, - ), - returnsNormally, + game.children.whereType().length, + equals(1), ); }); @@ -79,7 +66,7 @@ void main() { 'has two Baseboards', (game) async { await game.ready(); - final baseboards = game.children.whereType().toList(); + final baseboards = game.children.whereType(); expect(baseboards.length, 2); }, ); From b93e104b0818964d0d7eed0af5a8c9d3b28393b8 Mon Sep 17 00:00:00 2001 From: Alejandro Santiago Date: Tue, 15 Mar 2022 12:17:49 +0000 Subject: [PATCH 6/6] feat: include boardSide.direction (#46) * feat: implemented BoardSide.direction * docs: included doc comment --- lib/game/components/board_side.dart | 5 +++++ test/game/components/board_side_test.dart | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/lib/game/components/board_side.dart b/lib/game/components/board_side.dart index 611f70b8..ea8fb1cf 100644 --- a/lib/game/components/board_side.dart +++ b/lib/game/components/board_side.dart @@ -19,4 +19,9 @@ extension BoardSideX on BoardSide { /// Whether this side is [BoardSide.right]. bool get isRight => this == BoardSide.right; + + /// Direction of the [BoardSide]. + /// + /// Represents the path which the [BoardSide] moves along. + int get direction => isLeft ? -1 : 1; } diff --git a/test/game/components/board_side_test.dart b/test/game/components/board_side_test.dart index 3d6d3fa1..ba201065 100644 --- a/test/game/components/board_side_test.dart +++ b/test/game/components/board_side_test.dart @@ -23,5 +23,12 @@ void main() { expect(side.isLeft, isFalse); expect(side.isRight, isTrue); }); + + test('direction is correct', () { + const side = BoardSide.left; + expect(side.direction, equals(-1)); + const side2 = BoardSide.right; + expect(side2.direction, equals(1)); + }); }); }