diff --git a/lib/game/components/components.dart b/lib/game/components/components.dart index f733cfcd..86fa3845 100644 --- a/lib/game/components/components.dart +++ b/lib/game/components/components.dart @@ -4,6 +4,7 @@ export 'board.dart'; export 'board_side.dart'; export 'bonus_word.dart'; export 'flipper.dart'; +export 'initial_position.dart'; export 'joint_anchor.dart'; export 'pathway.dart'; export 'plunger.dart'; diff --git a/lib/game/components/initial_position.dart b/lib/game/components/initial_position.dart new file mode 100644 index 00000000..aa4acb46 --- /dev/null +++ b/lib/game/components/initial_position.dart @@ -0,0 +1,17 @@ +import 'package:flame_forge2d/flame_forge2d.dart'; + +/// Forces a given [BodyComponent] to position their [body] to an +/// [initialPosition]. +mixin InitialPosition on BodyComponent { + /// The initial position of the [body]. + late final Vector2 initialPosition; + + @override + void onMount() { + super.onMount(); + assert( + body.position == initialPosition, + 'Body position is not equal to initial position.', + ); + } +} diff --git a/test/game/components/initial_position_test.dart b/test/game/components/initial_position_test.dart new file mode 100644 index 00000000..393d780a --- /dev/null +++ b/test/game/components/initial_position_test.dart @@ -0,0 +1,66 @@ +// 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'; + +class TestBodyComponent extends BodyComponent with InitialPosition { + @override + Body createBody() { + return world.createBody(BodyDef()); + } +} + +class TestPositionedBodyComponent extends BodyComponent with InitialPosition { + @override + Body createBody() { + return world.createBody(BodyDef()..position = initialPosition); + } +} + +void main() { + final flameTester = FlameTester(Forge2DGame.new); + group('InitialPosition', () { + test('correctly sets and gets', () { + final component = TestBodyComponent()..initialPosition = Vector2(1, 2); + expect(component.initialPosition, Vector2(1, 2)); + }); + + test('can only be set once', () { + final component = TestBodyComponent()..initialPosition = Vector2(1, 2); + expect( + () => component.initialPosition = Vector2(3, 4), + throwsA(isA()), + ); + }); + + flameTester.test( + 'returns normally ' + 'when the body sets the position to initial position', + (game) async { + final component = TestPositionedBodyComponent() + ..initialPosition = Vector2.zero(); + + await expectLater( + () async => game.ensureAdd(component), + returnsNormally, + ); + }, + ); + + flameTester.test( + 'throws AssertionError ' + 'when not setting initialPosition to body', + (game) async { + final component = TestBodyComponent()..initialPosition = Vector2.zero(); + await game.ensureAdd(component); + + await expectLater( + () async => game.ensureAdd(component), + throwsAssertionError, + ); + }, + ); + }); +}