feat: adding sparky sfx (#364)

* feat: adding sparky sfx

* Apply suggestions from code review

* lint

* feat: better bonus sound implementation

* lint
pull/358/head
Erick 2 years ago committed by alestiago
parent 8df797c2a0
commit 1ce3b374ed

@ -1,4 +1,5 @@
export 'ball_spawning_behavior.dart';
export 'bonus_noise_behavior.dart';
export 'bumper_noise_behavior.dart';
export 'camera_focusing_behavior.dart';
export 'scoring_behavior.dart';

@ -0,0 +1,41 @@
import 'package:flame/components.dart';
import 'package:flame_bloc/flame_bloc.dart';
import 'package:pinball/game/game.dart';
import 'package:pinball_audio/pinball_audio.dart';
import 'package:pinball_flame/pinball_flame.dart';
/// Behavior that handles playing a bonus sound effect
class BonusNoiseBehavior extends Component {
@override
Future<void> onLoad() async {
await add(
FlameBlocListener<GameBloc, GameState>(
listenWhen: (previous, current) {
return previous.bonusHistory.length != current.bonusHistory.length;
},
onNewState: (state) {
final bonus = state.bonusHistory.last;
final audioPlayer = readProvider<PinballPlayer>();
switch (bonus) {
case GameBonus.googleWord:
audioPlayer.play(PinballAudio.google);
break;
case GameBonus.sparkyTurboCharge:
audioPlayer.play(PinballAudio.sparky);
break;
case GameBonus.dinoChomp:
// TODO(erickzanardo): Add sound
break;
case GameBonus.androidSpaceship:
// TODO(erickzanardo): Add sound
break;
case GameBonus.dashNest:
// TODO(erickzanardo): Add sound
break;
}
},
),
);
}
}

@ -1,7 +1,6 @@
import 'package:flame/components.dart';
import 'package:flame_bloc/flame_bloc.dart';
import 'package:pinball/game/game.dart';
import 'package:pinball_audio/pinball_audio.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
@ -22,7 +21,6 @@ class GoogleWordBonusBehavior extends Component
.every((letter) => letter.bloc.state == GoogleLetterState.lit);
if (achievedBonus) {
readProvider<PinballPlayer>().play(PinballAudio.google);
bloc.add(const BonusActivated(GameBonus.googleWord));
for (final letter in googleLetters) {
letter.bloc.onReset();

@ -67,6 +67,7 @@ class PinballGame extends PinballForge2DGame
FlameProvider<AppLocalizations>.value(_l10n),
],
children: [
BonusNoiseBehavior(),
GameBlocStatusListener(),
BallSpawningBehavior(),
CameraFocusingBehavior(),

@ -14,13 +14,13 @@ class $AssetsMusicGen {
class $AssetsSfxGen {
const $AssetsSfxGen();
String get afterLaunch => 'assets/sfx/after_launch.mp3';
String get bumperA => 'assets/sfx/bumper_a.mp3';
String get bumperB => 'assets/sfx/bumper_b.mp3';
String get gameOverVoiceOver => 'assets/sfx/game_over_voice_over.mp3';
String get google => 'assets/sfx/google.mp3';
String get ioPinballVoiceOver => 'assets/sfx/io_pinball_voice_over.mp3';
String get launcher => 'assets/sfx/launcher.mp3';
String get sparky => 'assets/sfx/sparky.mp3';
}
class Assets {

@ -25,6 +25,9 @@ enum PinballAudio {
/// Launcher
launcher,
/// Sparky
sparky,
}
/// Defines the contract of the creation of an [AudioPool].
@ -161,6 +164,11 @@ class PinballPlayer {
playSingleAudio: _playSingleAudio,
path: Assets.sfx.google,
),
PinballAudio.sparky: _SimplePlayAudio(
preCacheSingleAudio: _preCacheSingleAudio,
playSingleAudio: _playSingleAudio,
path: Assets.sfx.sparky,
),
PinballAudio.launcher: _SimplePlayAudio(
preCacheSingleAudio: _preCacheSingleAudio,
playSingleAudio: _playSingleAudio,

@ -141,6 +141,10 @@ void main() {
() => preCacheSingleAudio
.onCall('packages/pinball_audio/assets/sfx/google.mp3'),
).called(1);
verify(
() => preCacheSingleAudio
.onCall('packages/pinball_audio/assets/sfx/sparky.mp3'),
).called(1);
verify(
() => preCacheSingleAudio.onCall(
'packages/pinball_audio/assets/sfx/io_pinball_voice_over.mp3',
@ -211,7 +215,7 @@ void main() {
});
});
group('googleBonus', () {
group('google', () {
test('plays the correct file', () async {
await Future.wait(player.load());
player.play(PinballAudio.google);
@ -223,6 +227,18 @@ void main() {
});
});
group('sparky', () {
test('plays the correct file', () async {
await Future.wait(player.load());
player.play(PinballAudio.sparky);
verify(
() => playSingleAudio
.onCall('packages/pinball_audio/${Assets.sfx.sparky}'),
).called(1);
});
});
group('launcher', () {
test('plays the correct file', () async {
await Future.wait(player.load());

@ -0,0 +1,186 @@
// ignore_for_file: cascade_invocations
import 'package:bloc_test/bloc_test.dart';
import 'package:flame_bloc/flame_bloc.dart';
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/game/game.dart';
import 'package:pinball_audio/pinball_audio.dart';
import 'package:pinball_flame/pinball_flame.dart';
class _TestGame extends Forge2DGame {
Future<void> pump(
BonusNoiseBehavior child, {
required PinballPlayer player,
required GameBloc bloc,
}) {
return ensureAdd(
FlameBlocProvider<GameBloc, GameState>.value(
value: bloc,
children: [
FlameProvider<PinballPlayer>.value(
player,
children: [
child,
],
),
],
),
);
}
}
class _MockPinballPlayer extends Mock implements PinballPlayer {}
class _MockGameBloc extends Mock implements GameBloc {}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group('BonusNoiseBehavior', () {
late PinballPlayer player;
late GameBloc bloc;
final flameTester = FlameTester(_TestGame.new);
setUpAll(() {
registerFallbackValue(PinballAudio.google);
});
setUp(() {
player = _MockPinballPlayer();
when(() => player.play(any())).thenAnswer((_) {});
bloc = _MockGameBloc();
});
flameTester.testGameWidget(
'plays google sound',
setUp: (game, _) async {
const state = GameState(
totalScore: 0,
roundScore: 0,
multiplier: 1,
rounds: 0,
bonusHistory: [GameBonus.googleWord],
status: GameStatus.playing,
);
const initialState = GameState.initial();
whenListen(
bloc,
Stream.fromIterable([initialState, state]),
initialState: initialState,
);
final behavior = BonusNoiseBehavior();
await game.pump(behavior, player: player, bloc: bloc);
},
verify: (_, __) async {
verify(() => player.play(PinballAudio.google)).called(1);
},
);
flameTester.testGameWidget(
'plays sparky sound',
setUp: (game, _) async {
const state = GameState(
totalScore: 0,
roundScore: 0,
multiplier: 1,
rounds: 0,
bonusHistory: [GameBonus.sparkyTurboCharge],
status: GameStatus.playing,
);
const initialState = GameState.initial();
whenListen(
bloc,
Stream.fromIterable([initialState, state]),
initialState: initialState,
);
final behavior = BonusNoiseBehavior();
await game.pump(behavior, player: player, bloc: bloc);
},
verify: (_, __) async {
verify(() => player.play(PinballAudio.sparky)).called(1);
},
);
flameTester.testGameWidget(
'plays dino chomp sound',
setUp: (game, _) async {
const state = GameState(
totalScore: 0,
roundScore: 0,
multiplier: 1,
rounds: 0,
bonusHistory: [GameBonus.dinoChomp],
status: GameStatus.playing,
);
const initialState = GameState.initial();
whenListen(
bloc,
Stream.fromIterable([initialState, state]),
initialState: initialState,
);
final behavior = BonusNoiseBehavior();
await game.pump(behavior, player: player, bloc: bloc);
},
verify: (_, __) async {
// TODO(erickzanardo): Change when the sound is implemented
verifyNever(() => player.play(any()));
},
);
flameTester.testGameWidget(
'plays android spaceship sound',
setUp: (game, _) async {
const state = GameState(
totalScore: 0,
roundScore: 0,
multiplier: 1,
rounds: 0,
bonusHistory: [GameBonus.androidSpaceship],
status: GameStatus.playing,
);
const initialState = GameState.initial();
whenListen(
bloc,
Stream.fromIterable([initialState, state]),
initialState: initialState,
);
final behavior = BonusNoiseBehavior();
await game.pump(behavior, player: player, bloc: bloc);
},
verify: (_, __) async {
// TODO(erickzanardo): Change when the sound is implemented
verifyNever(() => player.play(any()));
},
);
flameTester.testGameWidget(
'plays dash nest sound',
setUp: (game, _) async {
const state = GameState(
totalScore: 0,
roundScore: 0,
multiplier: 1,
rounds: 0,
bonusHistory: [GameBonus.dashNest],
status: GameStatus.playing,
);
const initialState = GameState.initial();
whenListen(
bloc,
Stream.fromIterable([initialState, state]),
initialState: initialState,
);
final behavior = BonusNoiseBehavior();
await game.pump(behavior, player: player, bloc: bloc);
},
verify: (_, __) async {
// TODO(erickzanardo): Change when the sound is implemented
verifyNever(() => player.play(any()));
},
);
});
}
Loading…
Cancel
Save