feat: add rollover sounds (#430)

* feat: rollover sounds

* style: trailing comma
pull/435/head
Allison Ryan 2 years ago committed by GitHub
parent bac790db95
commit 43beb3db39
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -6,4 +6,5 @@ export 'camera_focusing_behavior.dart';
export 'character_selection_behavior.dart';
export 'cow_bumper_noise_behavior.dart';
export 'kicker_noise_behavior.dart';
export 'rollover_noise_behavior.dart';
export 'scoring_behavior.dart';

@ -0,0 +1,13 @@
// ignore_for_file: public_member_api_docs
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:pinball_audio/pinball_audio.dart';
import 'package:pinball_flame/pinball_flame.dart';
class RolloverNoiseBehavior extends ContactBehavior {
@override
void beginContact(Object other, Contact contact) {
super.beginContact(other, contact);
readProvider<PinballAudioPlayer>().play(PinballAudio.rollover);
}
}

@ -22,12 +22,14 @@ class GoogleGallery extends Component with ZIndex {
side: BoardSide.right,
children: [
ScoringContactBehavior(points: Points.fiveThousand),
RolloverNoiseBehavior(),
],
),
GoogleRollover(
side: BoardSide.left,
children: [
ScoringContactBehavior(points: Points.fiveThousand),
RolloverNoiseBehavior(),
],
),
GoogleWord(position: Vector2(-4.45, 1.8)),

@ -125,6 +125,7 @@ class PinballGame extends PinballForge2DGame
SkillShot(
children: [
ScoringContactBehavior(points: Points.oneMillion),
RolloverNoiseBehavior(),
],
),
AndroidAcres(),

@ -26,6 +26,7 @@ class $AssetsSfxGen {
String get kickerA => 'assets/sfx/kicker_a.mp3';
String get kickerB => 'assets/sfx/kicker_b.mp3';
String get launcher => 'assets/sfx/launcher.mp3';
String get rollover => 'assets/sfx/rollover.mp3';
String get sparky => 'assets/sfx/sparky.mp3';
}

@ -33,6 +33,9 @@ enum PinballAudio {
/// Kicker.
kicker,
/// Rollover.
rollover,
/// Sparky.
sparky,
@ -56,7 +59,7 @@ typedef CreateAudioPool = Future<AudioPool> Function(
});
/// Defines the contract for playing a single audio.
typedef PlaySingleAudio = Future<void> Function(String);
typedef PlaySingleAudio = Future<void> Function(String, {double volume});
/// Defines the contract for looping a single audio.
typedef LoopSingleAudio = Future<void> Function(String, {double volume});
@ -81,18 +84,20 @@ class _SimplePlayAudio extends _Audio {
required this.preCacheSingleAudio,
required this.playSingleAudio,
required this.path,
this.volume,
});
final PreCacheSingleAudio preCacheSingleAudio;
final PlaySingleAudio playSingleAudio;
final String path;
final double? volume;
@override
Future<void> load() => preCacheSingleAudio(prefixFile(path));
@override
void play() {
playSingleAudio(prefixFile(path));
playSingleAudio(prefixFile(path), volume: volume ?? 1);
}
}
@ -266,6 +271,12 @@ class PinballAudioPlayer {
playSingleAudio: _playSingleAudio,
path: Assets.sfx.launcher,
),
PinballAudio.rollover: _SimplePlayAudio(
preCacheSingleAudio: _preCacheSingleAudio,
playSingleAudio: _playSingleAudio,
path: Assets.sfx.rollover,
volume: 0.3,
),
PinballAudio.ioPinballVoiceOver: _SimplePlayAudio(
preCacheSingleAudio: _preCacheSingleAudio,
playSingleAudio: _playSingleAudio,

@ -29,15 +29,15 @@ class _MockConfigureAudioCache extends Mock {
}
class _MockPlaySingleAudio extends Mock {
Future<void> onCall(String url);
Future<void> onCall(String path, {double volume});
}
class _MockLoopSingleAudio extends Mock {
Future<void> onCall(String url, {double volume});
Future<void> onCall(String path, {double volume});
}
abstract class _PreCacheSingleAudio {
Future<void> onCall(String url);
Future<void> onCall(String path);
}
class _MockPreCacheSingleAudio extends Mock implements _PreCacheSingleAudio {}
@ -74,7 +74,8 @@ void main() {
when(() => configureAudioCache.onCall(any())).thenAnswer((_) {});
playSingleAudio = _MockPlaySingleAudio();
when(() => playSingleAudio.onCall(any())).thenAnswer((_) async {});
when(() => playSingleAudio.onCall(any(), volume: any(named: 'volume')))
.thenAnswer((_) async {});
loopSingleAudio = _MockLoopSingleAudio();
when(() => loopSingleAudio.onCall(any(), volume: any(named: 'volume')))
@ -195,6 +196,10 @@ void main() {
() => preCacheSingleAudio
.onCall('packages/pinball_audio/assets/sfx/launcher.mp3'),
).called(1);
verify(
() => preCacheSingleAudio
.onCall('packages/pinball_audio/assets/sfx/rollover.mp3'),
).called(1);
verify(
() => preCacheSingleAudio
.onCall('packages/pinball_audio/assets/sfx/cow_moo.mp3'),
@ -346,8 +351,10 @@ void main() {
audioPlayer.play(PinballAudio.google);
verify(
() => playSingleAudio
.onCall('packages/pinball_audio/${Assets.sfx.google}'),
() => playSingleAudio.onCall(
'packages/pinball_audio/${Assets.sfx.google}',
volume: any(named: 'volume'),
),
).called(1);
});
});
@ -358,8 +365,10 @@ void main() {
audioPlayer.play(PinballAudio.sparky);
verify(
() => playSingleAudio
.onCall('packages/pinball_audio/${Assets.sfx.sparky}'),
() => playSingleAudio.onCall(
'packages/pinball_audio/${Assets.sfx.sparky}',
volume: any(named: 'volume'),
),
).called(1);
});
});
@ -370,8 +379,10 @@ void main() {
audioPlayer.play(PinballAudio.dino);
verify(
() => playSingleAudio
.onCall('packages/pinball_audio/${Assets.sfx.dino}'),
() => playSingleAudio.onCall(
'packages/pinball_audio/${Assets.sfx.dino}',
volume: any(named: 'volume'),
),
).called(1);
});
});
@ -382,8 +393,10 @@ void main() {
audioPlayer.play(PinballAudio.android);
verify(
() => playSingleAudio
.onCall('packages/pinball_audio/${Assets.sfx.android}'),
() => playSingleAudio.onCall(
'packages/pinball_audio/${Assets.sfx.android}',
volume: any(named: 'volume'),
),
).called(1);
});
});
@ -394,8 +407,10 @@ void main() {
audioPlayer.play(PinballAudio.dash);
verify(
() => playSingleAudio
.onCall('packages/pinball_audio/${Assets.sfx.dash}'),
() => playSingleAudio.onCall(
'packages/pinball_audio/${Assets.sfx.dash}',
volume: any(named: 'volume'),
),
).called(1);
});
});
@ -406,8 +421,24 @@ void main() {
audioPlayer.play(PinballAudio.launcher);
verify(
() => playSingleAudio
.onCall('packages/pinball_audio/${Assets.sfx.launcher}'),
() => playSingleAudio.onCall(
'packages/pinball_audio/${Assets.sfx.launcher}',
volume: any(named: 'volume'),
),
).called(1);
});
});
group('rollover', () {
test('plays the correct file', () async {
await Future.wait(audioPlayer.load());
audioPlayer.play(PinballAudio.rollover);
verify(
() => playSingleAudio.onCall(
'packages/pinball_audio/${Assets.sfx.rollover}',
volume: .3,
),
).called(1);
});
});
@ -420,6 +451,7 @@ void main() {
verify(
() => playSingleAudio.onCall(
'packages/pinball_audio/${Assets.sfx.ioPinballVoiceOver}',
volume: any(named: 'volume'),
),
).called(1);
});
@ -433,6 +465,7 @@ void main() {
verify(
() => playSingleAudio.onCall(
'packages/pinball_audio/${Assets.sfx.gameOverVoiceOver}',
volume: any(named: 'volume'),
),
).called(1);
});

@ -0,0 +1,58 @@
// 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 'package:pinball_flame/pinball_flame.dart';
class _TestGame extends Forge2DGame {
Future<void> pump(
_TestBodyComponent child, {
required PinballAudioPlayer audioPlayer,
}) {
return ensureAdd(
FlameProvider<PinballAudioPlayer>.value(
audioPlayer,
children: [child],
),
);
}
}
class _TestBodyComponent extends BodyComponent {
@override
Body createBody() => world.createBody(BodyDef());
}
class _MockPinballAudioPlayer extends Mock implements PinballAudioPlayer {}
class _MockContact extends Mock implements Contact {}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group('RolloverNoiseBehavior', () {
late PinballAudioPlayer audioPlayer;
final flameTester = FlameTester(_TestGame.new);
setUp(() {
audioPlayer = _MockPinballAudioPlayer();
});
flameTester.testGameWidget(
'plays rollover sound on contact',
setUp: (game, _) async {
final behavior = RolloverNoiseBehavior();
final parent = _TestBodyComponent();
await game.pump(parent, audioPlayer: audioPlayer);
await parent.ensureAdd(behavior);
behavior.beginContact(Object(), _MockContact());
},
verify: (_, __) async {
verify(() => audioPlayer.play(PinballAudio.rollover)).called(1);
},
);
});
}

@ -97,6 +97,20 @@ void main() {
},
);
flameTester.test(
'RolloverNoiseBehavior to GoogleRollovers',
(game) async {
await game.pump(GoogleGallery());
game.descendants().whereType<GoogleRollover>().forEach(
(rollover) => expect(
rollover.firstChild<RolloverNoiseBehavior>(),
isNotNull,
),
);
},
);
flameTester.test('a GoogleWordBonusBehavior', (game) async {
final component = GoogleGallery();
await game.pump(component);

Loading…
Cancel
Save