refactor: moved noise logic to `BumperNoisyBehavior` (#326)

pull/328/head
Alejandro Santiago 3 years ago committed by GitHub
parent 44566bcbf0
commit f38f18d60a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,2 @@
export 'bumper_noisy_behavior.dart';
export 'scoring_behavior.dart';

@ -0,0 +1,14 @@
// ignore_for_file: public_member_api_docs
import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:pinball/game/pinball_game.dart';
import 'package:pinball_flame/pinball_flame.dart';
class BumperNoisyBehavior extends ContactBehavior with HasGameRef<PinballGame> {
@override
void beginContact(Object other, Contact contact) {
super.beginContact(other, contact);
gameRef.audio.bumper();
}
}

@ -7,7 +7,7 @@ import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart'; import 'package:pinball_flame/pinball_flame.dart';
/// {@template scoring_behavior} /// {@template scoring_behavior}
/// Adds points to the score when the ball contacts the [parent]. /// Adds points to the score when the [Ball] contacts the [parent].
/// {@endtemplate} /// {@endtemplate}
class ScoringBehavior extends ContactBehavior with HasGameRef<PinballGame> { class ScoringBehavior extends ContactBehavior with HasGameRef<PinballGame> {
/// {@macro scoring_behavior} /// {@macro scoring_behavior}
@ -31,23 +31,3 @@ class ScoringBehavior extends ContactBehavior with HasGameRef<PinballGame> {
); );
} }
} }
/// {@template bumper_scoring_behavior}
/// A specific [ScoringBehavior] used for Bumpers.
/// In addition to its parent logic, also plays the
/// SFX for bumpers
/// {@endtemplate}
class BumperScoringBehavior extends ScoringBehavior {
/// {@macro bumper_scoring_behavior}
BumperScoringBehavior({
required Points points,
}) : super(points: points);
@override
void beginContact(Object other, Contact contact) {
super.beginContact(other, contact);
if (other is! Ball) return;
gameRef.audio.bumper();
}
}

@ -2,8 +2,8 @@
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:pinball/game/behaviors/behaviors.dart';
import 'package:pinball/game/components/android_acres/behaviors/behaviors.dart'; import 'package:pinball/game/components/android_acres/behaviors/behaviors.dart';
import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
/// {@template android_acres} /// {@template android_acres}
@ -25,17 +25,20 @@ class AndroidAcres extends Component {
)..initialPosition = Vector2(-26, -28.25), )..initialPosition = Vector2(-26, -28.25),
AndroidBumper.a( AndroidBumper.a(
children: [ children: [
BumperScoringBehavior(points: Points.twentyThousand), ScoringBehavior(points: Points.twentyThousand),
BumperNoisyBehavior(),
], ],
)..initialPosition = Vector2(-25, 1.3), )..initialPosition = Vector2(-25, 1.3),
AndroidBumper.b( AndroidBumper.b(
children: [ children: [
BumperScoringBehavior(points: Points.twentyThousand), ScoringBehavior(points: Points.twentyThousand),
BumperNoisyBehavior(),
], ],
)..initialPosition = Vector2(-32.8, -9.2), )..initialPosition = Vector2(-32.8, -9.2),
AndroidBumper.cow( AndroidBumper.cow(
children: [ children: [
BumperScoringBehavior(points: Points.twentyThousand), ScoringBehavior(points: Points.twentyThousand),
BumperNoisyBehavior(),
], ],
)..initialPosition = Vector2(-20.5, -13.8), )..initialPosition = Vector2(-20.5, -13.8),
AndroidSpaceshipBonusBehavior(), AndroidSpaceshipBonusBehavior(),

@ -1,4 +1,5 @@
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:pinball/game/behaviors/behaviors.dart';
import 'package:pinball/game/game.dart'; import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart'; import 'package:pinball_flame/pinball_flame.dart';

@ -12,5 +12,4 @@ export 'google_word/google_word.dart';
export 'launcher.dart'; export 'launcher.dart';
export 'multiballs/multiballs.dart'; export 'multiballs/multiballs.dart';
export 'multipliers/multipliers.dart'; export 'multipliers/multipliers.dart';
export 'scoring_behavior.dart';
export 'sparky_scorch.dart'; export 'sparky_scorch.dart';

@ -1,6 +1,7 @@
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart'; import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:pinball/game/behaviors/behaviors.dart';
import 'package:pinball/game/components/dino_desert/behaviors/behaviors.dart'; import 'package:pinball/game/components/dino_desert/behaviors/behaviors.dart';
import 'package:pinball/game/game.dart'; import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';

@ -2,8 +2,8 @@
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:pinball/game/behaviors/behaviors.dart';
import 'package:pinball/game/components/flutter_forest/behaviors/behaviors.dart'; import 'package:pinball/game/components/flutter_forest/behaviors/behaviors.dart';
import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart'; import 'package:pinball_flame/pinball_flame.dart';
@ -18,22 +18,26 @@ class FlutterForest extends Component with ZIndex {
children: [ children: [
Signpost( Signpost(
children: [ children: [
BumperScoringBehavior(points: Points.fiveThousand), ScoringBehavior(points: Points.fiveThousand),
BumperNoisyBehavior(),
], ],
)..initialPosition = Vector2(8.35, -58.3), )..initialPosition = Vector2(8.35, -58.3),
DashNestBumper.main( DashNestBumper.main(
children: [ children: [
BumperScoringBehavior(points: Points.twoHundredThousand), ScoringBehavior(points: Points.twoHundredThousand),
BumperNoisyBehavior(),
], ],
)..initialPosition = Vector2(18.55, -59.35), )..initialPosition = Vector2(18.55, -59.35),
DashNestBumper.a( DashNestBumper.a(
children: [ children: [
BumperScoringBehavior(points: Points.twentyThousand), ScoringBehavior(points: Points.twentyThousand),
BumperNoisyBehavior(),
], ],
)..initialPosition = Vector2(8.95, -51.95), )..initialPosition = Vector2(8.95, -51.95),
DashNestBumper.b( DashNestBumper.b(
children: [ children: [
BumperScoringBehavior(points: Points.twentyThousand), ScoringBehavior(points: Points.twentyThousand),
BumperNoisyBehavior(),
], ],
)..initialPosition = Vector2(22.3, -46.75), )..initialPosition = Vector2(22.3, -46.75),
DashAnimatronic()..position = Vector2(20, -66), DashAnimatronic()..position = Vector2(20, -66),

@ -1,7 +1,7 @@
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:pinball/game/behaviors/scoring_behavior.dart';
import 'package:pinball/game/components/google_word/behaviors/behaviors.dart'; import 'package:pinball/game/components/google_word/behaviors/behaviors.dart';
import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart'; import 'package:pinball_flame/pinball_flame.dart';

@ -2,7 +2,8 @@
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart'; import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:pinball/game/game.dart'; import 'package:pinball/game/behaviors/behaviors.dart';
import 'package:pinball/game/components/components.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
/// {@template sparky_scorch} /// {@template sparky_scorch}
@ -16,17 +17,20 @@ class SparkyScorch extends Component {
children: [ children: [
SparkyBumper.a( SparkyBumper.a(
children: [ children: [
BumperScoringBehavior(points: Points.twentyThousand), ScoringBehavior(points: Points.twentyThousand),
BumperNoisyBehavior(),
], ],
)..initialPosition = Vector2(-22.9, -41.65), )..initialPosition = Vector2(-22.9, -41.65),
SparkyBumper.b( SparkyBumper.b(
children: [ children: [
BumperScoringBehavior(points: Points.twentyThousand), ScoringBehavior(points: Points.twentyThousand),
BumperNoisyBehavior(),
], ],
)..initialPosition = Vector2(-21.25, -57.9), )..initialPosition = Vector2(-21.25, -57.9),
SparkyBumper.c( SparkyBumper.c(
children: [ children: [
BumperScoringBehavior(points: Points.twentyThousand), ScoringBehavior(points: Points.twentyThousand),
BumperNoisyBehavior(),
], ],
)..initialPosition = Vector2(-3.3, -52.55), )..initialPosition = Vector2(-3.3, -52.55),
SparkyComputerSensor()..initialPosition = Vector2(-13, -49.9), SparkyComputerSensor()..initialPosition = Vector2(-13, -49.9),

@ -49,17 +49,13 @@ class Ball extends BodyComponent with Layered, InitialPosition, ZIndex {
@override @override
Body createBody() { Body createBody() {
final shape = CircleShape()..radius = size.x / 2; final shape = CircleShape()..radius = size.x / 2;
final fixtureDef = FixtureDef(
shape,
density: 1,
);
final bodyDef = BodyDef( final bodyDef = BodyDef(
position: initialPosition, position: initialPosition,
userData: this,
type: BodyType.dynamic, type: BodyType.dynamic,
userData: this,
); );
return world.createBody(bodyDef)..createFixture(fixtureDef); return world.createBody(bodyDef)..createFixtureFromShape(shape, 1);
} }
/// Immediatly and completly [stop]s the ball. /// Immediatly and completly [stop]s the ball.

@ -0,0 +1,50 @@
// 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:mocktail/mocktail.dart';
import 'package:pinball/game/behaviors/behaviors.dart';
import 'package:pinball_audio/pinball_audio.dart';
import '../../helpers/helpers.dart';
class _TestBodyComponent extends BodyComponent {
@override
Body createBody() {
return world.createBody(BodyDef());
}
}
class _MockPinballAudio extends Mock implements PinballAudio {}
class _MockContact extends Mock implements Contact {}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group('BumperNoisyBehavior', () {});
late PinballAudio audio;
final flameTester = FlameTester(
() => EmptyPinballTestGame(audio: audio),
);
setUp(() {
audio = _MockPinballAudio();
});
flameTester.testGameWidget(
'plays bumper sound',
setUp: (game, _) async {
final behavior = BumperNoisyBehavior();
final parent = _TestBodyComponent();
await game.ensureAdd(parent);
await parent.ensureAdd(behavior);
behavior.beginContact(Object(), _MockContact());
},
verify: (_, __) async {
verify(audio.bumper).called(1);
},
);
}

@ -5,8 +5,8 @@ import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flame_test/flame_test.dart'; import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart'; import 'package:mocktail/mocktail.dart';
import 'package:pinball/game/behaviors/behaviors.dart';
import 'package:pinball/game/game.dart'; import 'package:pinball/game/game.dart';
import 'package:pinball_audio/pinball_audio.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart'; import 'package:pinball_flame/pinball_flame.dart';
@ -17,8 +17,6 @@ class _TestBodyComponent extends BodyComponent {
Body createBody() => world.createBody(BodyDef()); Body createBody() => world.createBody(BodyDef());
} }
class _MockPinballAudio extends Mock implements PinballAudio {}
class _MockBall extends Mock implements Ball {} class _MockBall extends Mock implements Ball {}
class _MockBody extends Mock implements Body {} class _MockBody extends Mock implements Body {}
@ -39,12 +37,10 @@ void main() {
group('ScoringBehavior', () { group('ScoringBehavior', () {
group('beginContact', () { group('beginContact', () {
late GameBloc bloc; late GameBloc bloc;
late PinballAudio audio;
late Ball ball; late Ball ball;
late BodyComponent parent; late BodyComponent parent;
setUp(() { setUp(() {
audio = _MockPinballAudio();
ball = _MockBall(); ball = _MockBall();
final ballBody = _MockBody(); final ballBody = _MockBody();
when(() => ball.body).thenReturn(ballBody); when(() => ball.body).thenReturn(ballBody);
@ -54,9 +50,7 @@ void main() {
}); });
final flameBlocTester = FlameBlocTester<EmptyPinballTestGame, GameBloc>( final flameBlocTester = FlameBlocTester<EmptyPinballTestGame, GameBloc>(
gameBuilder: () => EmptyPinballTestGame( gameBuilder: EmptyPinballTestGame.new,
audio: audio,
),
blocBuilder: () { blocBuilder: () {
bloc = _MockGameBloc(); bloc = _MockGameBloc();
const state = GameState( const state = GameState(
@ -116,57 +110,4 @@ void main() {
); );
}); });
}); });
group('BumperScoringBehavior', () {
group('beginContact', () {
late GameBloc bloc;
late PinballAudio audio;
late Ball ball;
late BodyComponent parent;
setUp(() {
audio = _MockPinballAudio();
ball = _MockBall();
final ballBody = _MockBody();
when(() => ball.body).thenReturn(ballBody);
when(() => ballBody.position).thenReturn(Vector2.all(4));
parent = _TestBodyComponent();
});
final flameBlocTester = FlameBlocTester<EmptyPinballTestGame, GameBloc>(
gameBuilder: () => EmptyPinballTestGame(
audio: audio,
),
blocBuilder: () {
bloc = _MockGameBloc();
const state = GameState(
score: 0,
multiplier: 1,
rounds: 3,
bonusHistory: [],
);
whenListen(bloc, Stream.value(state), initialState: state);
return bloc;
},
assets: assets,
);
flameBlocTester.testGameWidget(
'plays bumper sound',
setUp: (game, tester) async {
final scoringBehavior = BumperScoringBehavior(
points: Points.oneMillion,
);
await parent.add(scoringBehavior);
final canvas = ZCanvasComponent(children: [parent]);
await game.ensureAdd(canvas);
scoringBehavior.beginContact(ball, _MockContact());
verify(audio.bumper).called(1);
},
);
});
});
} }

@ -2,6 +2,7 @@
import 'package:flame_test/flame_test.dart'; import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:pinball/game/behaviors/bumper_noisy_behavior.dart';
import 'package:pinball/game/components/android_acres/behaviors/behaviors.dart'; import 'package:pinball/game/components/android_acres/behaviors/behaviors.dart';
import 'package:pinball/game/game.dart'; import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
@ -33,11 +34,12 @@ void main() {
Assets.images.android.bumper.cow.lit.keyName, Assets.images.android.bumper.cow.lit.keyName,
Assets.images.android.bumper.cow.dimmed.keyName, Assets.images.android.bumper.cow.dimmed.keyName,
]; ];
final flameTester = FlameTester(
() => EmptyPinballTestGame(assets: assets),
);
group('AndroidAcres', () { group('AndroidAcres', () {
final flameTester = FlameTester(
() => EmptyPinballTestGame(assets: assets),
);
flameTester.test('loads correctly', (game) async { flameTester.test('loads correctly', (game) async {
final component = AndroidAcres(); final component = AndroidAcres();
await game.ensureAdd(component); await game.ensureAdd(component);
@ -99,6 +101,20 @@ void main() {
); );
}, },
); );
flameTester.test(
'three AndroidBumpers with BumperNoisyBehavior',
(game) async {
await game.ensureAdd(AndroidAcres());
final bumpers = game.descendants().whereType<AndroidBumper>();
for (final bumper in bumpers) {
expect(
bumper.firstChild<BumperNoisyBehavior>(),
isNotNull,
);
}
},
);
}); });
flameTester.test('adds an AndroidSpaceshipBonusBehavior', (game) async { flameTester.test('adds an AndroidSpaceshipBonusBehavior', (game) async {

@ -2,6 +2,7 @@
import 'package:flame_test/flame_test.dart'; import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:pinball/game/behaviors/behaviors.dart';
import 'package:pinball/game/components/dino_desert/behaviors/behaviors.dart'; import 'package:pinball/game/components/dino_desert/behaviors/behaviors.dart';
import 'package:pinball/game/game.dart'; import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';

@ -2,6 +2,7 @@
import 'package:flame_test/flame_test.dart'; import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:pinball/game/behaviors/behaviors.dart';
import 'package:pinball/game/game.dart'; import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart'; import 'package:pinball_flame/pinball_flame.dart';
@ -73,6 +74,21 @@ void main() {
); );
}, },
); );
flameTester.test(
'three DashNestBumpers with BumperNoisyBehavior',
(game) async {
final flutterForest = FlutterForest();
await game.ensureAdd(ZCanvasComponent(children: [flutterForest]));
final bumpers = game.descendants().whereType<DashNestBumper>();
for (final bumper in bumpers) {
expect(
bumper.firstChild<BumperNoisyBehavior>(),
isNotNull,
);
}
},
);
}); });
}); });
} }

@ -4,6 +4,7 @@ import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flame_test/flame_test.dart'; import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart'; import 'package:mocktail/mocktail.dart';
import 'package:pinball/game/behaviors/behaviors.dart';
import 'package:pinball/game/game.dart'; import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
@ -74,6 +75,20 @@ void main() {
); );
}, },
); );
flameTester.test(
'three SparkyBumpers with BumperNoisyBehavior',
(game) async {
await game.ensureAdd(SparkyScorch());
final bumpers = game.descendants().whereType<SparkyBumper>();
for (final bumper in bumpers) {
expect(
bumper.firstChild<BumperNoisyBehavior>(),
isNotNull,
);
}
},
);
}); });
}); });

@ -140,19 +140,16 @@ void main() {
); );
}); });
final flameTester = FlameTester(
() => PinballTestGame(assets: assets),
);
final debugModeFlameTester = FlameTester(
() => DebugPinballTestGame(assets: assets),
);
final flameBlocTester = FlameBlocTester<PinballGame, GameBloc>(
gameBuilder: () => PinballTestGame(assets: assets),
blocBuilder: () => gameBloc,
);
group('PinballGame', () { group('PinballGame', () {
final flameTester = FlameTester(
() => PinballTestGame(assets: assets),
);
final flameBlocTester = FlameBlocTester<PinballGame, GameBloc>(
gameBuilder: () => PinballTestGame(assets: assets),
blocBuilder: () => gameBloc,
);
group('components', () { group('components', () {
// TODO(alestiago): tests that Blueprints get added once the Blueprint // TODO(alestiago): tests that Blueprints get added once the Blueprint
// class is removed. // class is removed.
@ -247,6 +244,8 @@ void main() {
final newState = _MockGameState(); final newState = _MockGameState();
when(() => newState.isGameOver).thenReturn(false); when(() => newState.isGameOver).thenReturn(false);
await game.ready();
expect( expect(
game.descendants().whereType<ControlledBall>().length, game.descendants().whereType<ControlledBall>().length,
greaterThan(0), greaterThan(0),
@ -439,6 +438,10 @@ void main() {
}); });
group('DebugPinballGame', () { group('DebugPinballGame', () {
final debugModeFlameTester = FlameTester(
() => DebugPinballTestGame(assets: assets),
);
debugModeFlameTester.test( debugModeFlameTester.test(
'adds a ball on tap up', 'adds a ball on tap up',
(game) async { (game) async {
@ -452,6 +455,7 @@ void main() {
when(() => tapUpEvent.eventPosition).thenReturn(eventPosition); when(() => tapUpEvent.eventPosition).thenReturn(eventPosition);
when(() => tapUpEvent.raw).thenReturn(raw); when(() => tapUpEvent.raw).thenReturn(raw);
await game.ready();
final previousBalls = final previousBalls =
game.descendants().whereType<ControlledBall>().toList(); game.descendants().whereType<ControlledBall>().toList();

Loading…
Cancel
Save