From bcb0035687a557374cb4af795820de78ebd02185 Mon Sep 17 00:00:00 2001 From: RuiAlonso Date: Fri, 22 Apr 2022 10:39:06 +0200 Subject: [PATCH] refactor: controlled spaceshipramp with new blueprint --- .../components/controlled_spaceship_ramp.dart | 94 +++++++------- .../lib/src/components/spaceship_ramp.dart | 38 ++++++ .../controlled_spaceship_ramp_test.dart | 116 ++++++++++++++++++ test/helpers/mocks.dart | 8 ++ 4 files changed, 209 insertions(+), 47 deletions(-) create mode 100644 test/game/components/controlled_spaceship_ramp_test.dart diff --git a/lib/game/components/controlled_spaceship_ramp.dart b/lib/game/components/controlled_spaceship_ramp.dart index 9f9d26a1..6784ffa0 100644 --- a/lib/game/components/controlled_spaceship_ramp.dart +++ b/lib/game/components/controlled_spaceship_ramp.dart @@ -1,5 +1,6 @@ // ignore_for_file: avoid_renaming_method_parameters +import 'dart:collection'; import 'dart:math' as math; import 'package:flame/components.dart'; @@ -10,13 +11,13 @@ import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_flame/pinball_flame.dart'; /// {@template controlled_spaceship_ramp} -/// [SpaceshipRamp] with a [_SpaceshipRampController] attached. +/// [SpaceshipRamp] with a [SpaceshipRampController] attached. /// {@endtemplate} class ControlledSpaceshipRamp extends Component - with Controls<_SpaceshipRampController>, HasGameRef { + with Controls, HasGameRef { /// {@macro controlled_spaceship_ramp} ControlledSpaceshipRamp() { - controller = _SpaceshipRampController(this); + controller = SpaceshipRampController(this); } late final SpaceshipRamp _spaceshipRamp; @@ -27,11 +28,13 @@ class ControlledSpaceshipRamp extends Component gameRef.addContactCallback(SpaceshipRampSensorBallContactCallback()); _spaceshipRamp = SpaceshipRamp(); - final spaceshipRampSensor = SpaceshipRampSensor() - ..initialPosition = Vector2(1.7, -20); - - await gameRef.addFromBlueprint(_spaceshipRamp); - await add(spaceshipRampSensor); + await addFromBlueprint(_spaceshipRamp); + await addAll([ + SpaceshipRampSensor(type: SpaceshipRampSensorType.door) + ..initialPosition = Vector2(1.7, -20), + SpaceshipRampSensor(type: SpaceshipRampSensorType.inside) + ..initialPosition = Vector2(1.7, -21.5), + ]); } } @@ -40,11 +43,11 @@ class ControlledSpaceshipRamp extends Component /// logic. /// {@endtemplate} -class _SpaceshipRampController +class SpaceshipRampController extends ComponentController with HasGameRef { /// {@macro spaceship_ramp_controller} - _SpaceshipRampController(ControlledSpaceshipRamp controlledSpaceshipRamp) + SpaceshipRampController(ControlledSpaceshipRamp controlledSpaceshipRamp) : super(controlledSpaceshipRamp); final int _oneMillionPointsTarget = 10; @@ -59,50 +62,27 @@ class _SpaceshipRampController // TODO(ruimiguel): increase score multiplier x1 . print('Multiplier x1'); + gameRef.read().add(const Scored(points: 100)); if (_hitsCounter % _scoreMultiplierTarget == 0) { // TODO(ruimiguel): reset score multiplier and multiply score x6 . print('Reset multiplier and multiply score x6'); } if (_hitsCounter % _oneMillionPointsTarget == 0) { - gameRef.read().add(const Scored(points: 1000000)); - } - } -} - -/// {@template spaceship_ramp_sensor} -/// Small sensor body used to detect when a ball has entered the -/// [SpaceshipRamp] with the [SpaceshipRampSensorBallContactCallback]. -/// {@endtemplate} -@visibleForTesting -class SpaceshipRampSensor extends BodyComponent with InitialPosition { - /// {@macro spaceship_ramp_sensor} - SpaceshipRampSensor() { - renderBody = true; - } - - @override - Body createBody() { - final shape = PolygonShape() - ..setAsBox( - 2, - .1, - initialPosition, - -5 * math.pi / 180, + const oneMillion = 1000000; + gameRef.read().add(const Scored(points: oneMillion)); + gameRef.add( + ScoreText( + text: oneMillion.toString(), + position: Vector2(1.7, -20), + ), ); - - final fixtureDef = FixtureDef(shape)..isSensor = true; - - final bodyDef = BodyDef() - ..position = initialPosition - ..userData = this; - - return world.createBody(bodyDef)..createFixture(fixtureDef); + } } } /// {@template spaceship_ramp_sensor_ball_contact_callback} -/// Turbo charges the [Ball] on contact with [SparkyTurboChargeSensor]. +/// Turbo charges the [Ball] on contact with [SpaceshipRampSensor]. /// {@endtemplate} @visibleForTesting class SpaceshipRampSensorBallContactCallback @@ -110,15 +90,35 @@ class SpaceshipRampSensorBallContactCallback /// {@macro spaceship_ramp_sensor_ball_contact_callback} SpaceshipRampSensorBallContactCallback(); + final Set _balls = HashSet(); + @override void begin( SpaceshipRampSensor spaceshipRampSensor, - _, + ControlledBall ball, __, ) { - final parent = spaceshipRampSensor.parent; - if (parent is ControlledSpaceshipRamp) { - parent.controller.shot(); + switch (spaceshipRampSensor.type) { + case SpaceshipRampSensorType.door: + print('door'); + if (!_balls.contains(ball)) { + print('add new ball'); + _balls.add(ball); + } + break; + case SpaceshipRampSensorType.inside: + print('inside'); + if (_balls.contains(ball)) { + print('ball is in'); + final parent = spaceshipRampSensor.parent; + print('parent $parent'); + if (parent is ControlledSpaceshipRamp) { + parent.controller.shot(); + } + print('remove ball'); + _balls.remove(ball); + } + break; } } } diff --git a/packages/pinball_components/lib/src/components/spaceship_ramp.dart b/packages/pinball_components/lib/src/components/spaceship_ramp.dart index 30211251..d0b9d9a3 100644 --- a/packages/pinball_components/lib/src/components/spaceship_ramp.dart +++ b/packages/pinball_components/lib/src/components/spaceship_ramp.dart @@ -382,3 +382,41 @@ class _SpaceshipRampOpening extends LayerSensor { ); } } + +enum SpaceshipRampSensorType { + door, + inside, +} + +/// {@template spaceship_ramp_sensor} +/// Small sensor body used to detect when a ball has entered the +/// [SpaceshipRamp]. +/// {@endtemplate} +class SpaceshipRampSensor extends BodyComponent with InitialPosition, Layered { + /// {@macro spaceship_ramp_sensor} + SpaceshipRampSensor({required this.type}) { + layer = Layer.spaceshipEntranceRamp; + renderBody = false; + } + + final SpaceshipRampSensorType type; + + @override + Body createBody() { + final shape = PolygonShape() + ..setAsBox( + 2, + .1, + initialPosition, + -5 * math.pi / 180, + ); + + final fixtureDef = FixtureDef(shape)..isSensor = true; + + final bodyDef = BodyDef() + ..position = initialPosition + ..userData = this; + + return world.createBody(bodyDef)..createFixture(fixtureDef); + } +} diff --git a/test/game/components/controlled_spaceship_ramp_test.dart b/test/game/components/controlled_spaceship_ramp_test.dart new file mode 100644 index 00000000..03f2baba --- /dev/null +++ b/test/game/components/controlled_spaceship_ramp_test.dart @@ -0,0 +1,116 @@ +// ignore_for_file: cascade_invocations + +import 'package:bloc_test/bloc_test.dart'; +import 'package:flame_test/flame_test.dart'; +import 'package:flutter/rendering.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.spaceship.ramp.boardOpening.keyName, + Assets.images.spaceship.ramp.railingForeground.keyName, + Assets.images.spaceship.ramp.railingBackground.keyName, + Assets.images.spaceship.ramp.main.keyName, + Assets.images.spaceship.ramp.arrow.inactive.keyName, + Assets.images.spaceship.ramp.arrow.active1.keyName, + Assets.images.spaceship.ramp.arrow.active2.keyName, + Assets.images.spaceship.ramp.arrow.active3.keyName, + Assets.images.spaceship.ramp.arrow.active4.keyName, + Assets.images.spaceship.ramp.arrow.active5.keyName, + ]; + final flameTester = FlameTester(() => EmptyPinballTestGame(assets)); + + group('ControlledSpaceshipRamp', () { + flameTester.test( + 'loads correctly', + (game) async { + final controlledSpaceshipRamp = ControlledSpaceshipRamp(); + await game.ensureAdd(controlledSpaceshipRamp); + + expect(game.contains(controlledSpaceshipRamp), isTrue); + }, + ); + + group('loads', () { + flameTester.test( + 'a SpaceshipRamp', + (game) async { + final controlledSpaceshipRamp = ControlledSpaceshipRamp(); + await game.ensureAdd(controlledSpaceshipRamp); + + expect( + controlledSpaceshipRamp + .descendants() + .whereType() + .length, + equals(1), + ); + }, + ); + + flameTester.test( + 'two SpaceshipRampSensor', + (game) async { + final controlledSpaceshipRamp = ControlledSpaceshipRamp(); + await game.ensureAdd(controlledSpaceshipRamp); + + expect( + controlledSpaceshipRamp + .descendants() + .whereType() + .length, + equals(2), + ); + }, + ); + }); + }); + + group('SpaceshipRampController', () { + TestWidgetsFlutterBinding.ensureInitialized(); + final flameTester = FlameTester(EmptyPinballTestGame.new); + + late ControlledSpaceshipRamp controlledSpaceshipRamp; + + setUp(() { + controlledSpaceshipRamp = ControlledSpaceshipRamp(); + }); + + test('can be instantiated', () { + expect( + SpaceshipRampController(controlledSpaceshipRamp), + isA(), + ); + }); + + group('shot', () {}); + + flameTester.testGameWidget( + 'SpaceshipRampSensorBallContactCallback turbo charges the ball', + setUp: (game, tester) async { + final controlledSpaceshipRamp = MockControlledSpaceshipRamp(); + final controller = MockSpaceshipRampController(); + final contactCallback = SpaceshipRampSensorBallContactCallback(); + final spaceshipRampSensor = MockSpaceshipRampSensor(); + final ball = MockControlledBall(); + + when(() => spaceshipRampSensor.type) + .thenReturn(SpaceshipRampSensorType.door); + when(() => spaceshipRampSensor.parent) + .thenReturn(controlledSpaceshipRamp); + when(() => controlledSpaceshipRamp.controller).thenReturn(controller); + when(controller.shot).thenAnswer((_) async {}); + + contactCallback.begin(spaceshipRampSensor, ball, MockContact()); + + verify(controller.shot).called(1); + }, + ); + }); +} diff --git a/test/helpers/mocks.dart b/test/helpers/mocks.dart index 9b0f67c9..fbd453fc 100644 --- a/test/helpers/mocks.dart +++ b/test/helpers/mocks.dart @@ -71,6 +71,14 @@ class MockPinballAudio extends Mock implements PinballAudio {} class MockSparkyComputerSensor extends Mock implements SparkyComputerSensor {} +class MockControlledSpaceshipRamp extends Mock + implements ControlledSpaceshipRamp {} + +class MockSpaceshipRampController extends Mock + implements SpaceshipRampController {} + +class MockSpaceshipRampSensor extends Mock implements SpaceshipRampSensor {} + class MockAssetsManagerCubit extends Mock implements AssetsManagerCubit {} class MockBackboard extends Mock implements Backboard {}