feat: improving pinball audio code and loading (#325)

* feat: improving pinball audio code and loading

* fix: some errors

* refactoring the solution

* Apply suggestions from code review

Co-authored-by: Alejandro Santiago <dev@alestiago.com>

* fix: tests

* fix rebase

Co-authored-by: Alejandro Santiago <dev@alestiago.com>
Co-authored-by: Tom Arra <tarra3@gmail.com>
pull/320/head
Erick 3 years ago committed by GitHub
parent 9d98ff37fb
commit 34d0e7d65a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -17,15 +17,15 @@ class App extends StatelessWidget {
Key? key, Key? key,
required AuthenticationRepository authenticationRepository, required AuthenticationRepository authenticationRepository,
required LeaderboardRepository leaderboardRepository, required LeaderboardRepository leaderboardRepository,
required PinballAudio pinballAudio, required PinballPlayer pinballPlayer,
}) : _authenticationRepository = authenticationRepository, }) : _authenticationRepository = authenticationRepository,
_leaderboardRepository = leaderboardRepository, _leaderboardRepository = leaderboardRepository,
_pinballAudio = pinballAudio, _pinballPlayer = pinballPlayer,
super(key: key); super(key: key);
final AuthenticationRepository _authenticationRepository; final AuthenticationRepository _authenticationRepository;
final LeaderboardRepository _leaderboardRepository; final LeaderboardRepository _leaderboardRepository;
final PinballAudio _pinballAudio; final PinballPlayer _pinballPlayer;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -33,7 +33,7 @@ class App extends StatelessWidget {
providers: [ providers: [
RepositoryProvider.value(value: _authenticationRepository), RepositoryProvider.value(value: _authenticationRepository),
RepositoryProvider.value(value: _leaderboardRepository), RepositoryProvider.value(value: _leaderboardRepository),
RepositoryProvider.value(value: _pinballAudio), RepositoryProvider.value(value: _pinballPlayer),
], ],
child: MultiBlocProvider( child: MultiBlocProvider(
providers: [ providers: [

@ -3,12 +3,13 @@
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/pinball_game.dart'; import 'package:pinball/game/pinball_game.dart';
import 'package:pinball_audio/pinball_audio.dart';
import 'package:pinball_flame/pinball_flame.dart'; import 'package:pinball_flame/pinball_flame.dart';
class BumperNoisyBehavior extends ContactBehavior with HasGameRef<PinballGame> { class BumperNoisyBehavior extends ContactBehavior with HasGameRef<PinballGame> {
@override @override
void beginContact(Object other, Contact contact) { void beginContact(Object other, Contact contact) {
super.beginContact(other, contact); super.beginContact(other, contact);
gameRef.audio.bumper(); gameRef.player.play(PinballAudio.bumper);
} }
} }

@ -1,6 +1,7 @@
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:flame_bloc/flame_bloc.dart'; import 'package:flame_bloc/flame_bloc.dart';
import 'package:pinball/game/game.dart'; import 'package:pinball/game/game.dart';
import 'package:pinball_audio/pinball_audio.dart';
import 'package:pinball_flame/pinball_flame.dart'; import 'package:pinball_flame/pinball_flame.dart';
/// {@template game_flow_controller} /// {@template game_flow_controller}
@ -38,7 +39,7 @@ class GameFlowController extends ComponentController<PinballGame>
/// Puts the game in the playing state. /// Puts the game in the playing state.
void start() { void start() {
component.audio.backgroundMusic(); component.player.play(PinballAudio.backgroundMusic);
component.firstChild<CameraController>()?.focusOnGame(); component.firstChild<CameraController>()?.focusOnGame();
component.overlays.remove(PinballGame.playButtonOverlay); component.overlays.remove(PinballGame.playButtonOverlay);
} }

@ -1,5 +1,6 @@
import 'package:flame/components.dart'; import 'package:flame/components.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';
@ -20,7 +21,7 @@ class GoogleWordBonusBehavior extends Component
.every((letter) => letter.bloc.state == GoogleLetterState.lit); .every((letter) => letter.bloc.state == GoogleLetterState.lit);
if (achievedBonus) { if (achievedBonus) {
gameRef.audio.googleBonus(); gameRef.player.play(PinballAudio.google);
gameRef gameRef
.read<GameBloc>() .read<GameBloc>()
.add(const BonusActivated(GameBonus.googleWord)); .add(const BonusActivated(GameBonus.googleWord));

@ -23,8 +23,8 @@ class PinballGame extends PinballForge2DGame
MultiTouchTapDetector { MultiTouchTapDetector {
PinballGame({ PinballGame({
required this.characterTheme, required this.characterTheme,
required this.audio,
required this.l10n, required this.l10n,
required this.player,
}) : super(gravity: Vector2(0, 30)) { }) : super(gravity: Vector2(0, 30)) {
images.prefix = ''; images.prefix = '';
controller = _GameBallsController(this); controller = _GameBallsController(this);
@ -38,7 +38,7 @@ class PinballGame extends PinballForge2DGame
final CharacterTheme characterTheme; final CharacterTheme characterTheme;
final PinballAudio audio; final PinballPlayer player;
final AppLocalizations l10n; final AppLocalizations l10n;
@ -186,11 +186,11 @@ class _GameBallsController extends ComponentController<PinballGame>
class DebugPinballGame extends PinballGame with FPSCounter, PanDetector { class DebugPinballGame extends PinballGame with FPSCounter, PanDetector {
DebugPinballGame({ DebugPinballGame({
required CharacterTheme characterTheme, required CharacterTheme characterTheme,
required PinballAudio audio,
required AppLocalizations l10n, required AppLocalizations l10n,
required PinballPlayer player,
}) : super( }) : super(
characterTheme: characterTheme, characterTheme: characterTheme,
audio: audio, player: player,
l10n: l10n, l10n: l10n,
) { ) {
controller = _GameBallsController(this); controller = _GameBallsController(this);

@ -36,24 +36,24 @@ class PinballGamePage extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final characterTheme = final characterTheme =
context.read<CharacterThemeCubit>().state.characterTheme; context.read<CharacterThemeCubit>().state.characterTheme;
final audio = context.read<PinballAudio>(); final player = context.read<PinballPlayer>();
final pinballAudio = context.read<PinballAudio>(); final pinballAudio = context.read<PinballPlayer>();
final game = isDebugMode final game = isDebugMode
? DebugPinballGame( ? DebugPinballGame(
characterTheme: characterTheme, characterTheme: characterTheme,
audio: audio, player: player,
l10n: context.l10n, l10n: context.l10n,
) )
: PinballGame( : PinballGame(
characterTheme: characterTheme, characterTheme: characterTheme,
audio: audio, player: player,
l10n: context.l10n, l10n: context.l10n,
); );
final loadables = [ final loadables = [
...game.preLoadAssets(), ...game.preLoadAssets(),
pinballAudio.load(), ...pinballAudio.load(),
...BonusAnimation.loadAssets(), ...BonusAnimation.loadAssets(),
...SelectedCharacter.loadAssets(), ...SelectedCharacter.loadAssets(),
]; ];

@ -3,8 +3,10 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:pinball/gen/gen.dart'; import 'package:pinball/gen/gen.dart';
import 'package:pinball/l10n/l10n.dart'; import 'package:pinball/l10n/l10n.dart';
import 'package:pinball_audio/pinball_audio.dart';
import 'package:pinball_ui/pinball_ui.dart'; import 'package:pinball_ui/pinball_ui.dart';
import 'package:platform_helper/platform_helper.dart'; import 'package:platform_helper/platform_helper.dart';
@ -91,6 +93,7 @@ class _HowToPlayDialogState extends State<HowToPlayDialog> {
return WillPopScope( return WillPopScope(
onWillPop: () { onWillPop: () {
widget.onDismissCallback.call(); widget.onDismissCallback.call();
context.read<PinballPlayer>().play(PinballAudio.ioPinballVoiceOver);
return Future.value(true); return Future.value(true);
}, },
child: PinballDialog( child: PinballDialog(

@ -11,7 +11,7 @@ void main() {
bootstrap((firestore, firebaseAuth) async { bootstrap((firestore, firebaseAuth) async {
final leaderboardRepository = LeaderboardRepository(firestore); final leaderboardRepository = LeaderboardRepository(firestore);
final authenticationRepository = AuthenticationRepository(firebaseAuth); final authenticationRepository = AuthenticationRepository(firebaseAuth);
final pinballAudio = PinballAudio(); final pinballPlayer = PinballPlayer();
unawaited( unawaited(
Firebase.initializeApp().then( Firebase.initializeApp().then(
(_) => authenticationRepository.authenticateAnonymously(), (_) => authenticationRepository.authenticateAnonymously(),
@ -20,7 +20,7 @@ void main() {
return App( return App(
authenticationRepository: authenticationRepository, authenticationRepository: authenticationRepository,
leaderboardRepository: leaderboardRepository, leaderboardRepository: leaderboardRepository,
pinballAudio: pinballAudio, pinballPlayer: pinballPlayer,
); );
}); });
} }

@ -11,7 +11,7 @@ void main() {
bootstrap((firestore, firebaseAuth) async { bootstrap((firestore, firebaseAuth) async {
final leaderboardRepository = LeaderboardRepository(firestore); final leaderboardRepository = LeaderboardRepository(firestore);
final authenticationRepository = AuthenticationRepository(firebaseAuth); final authenticationRepository = AuthenticationRepository(firebaseAuth);
final pinballAudio = PinballAudio(); final pinballPlayer = PinballPlayer();
unawaited( unawaited(
Firebase.initializeApp().then( Firebase.initializeApp().then(
(_) => authenticationRepository.authenticateAnonymously(), (_) => authenticationRepository.authenticateAnonymously(),
@ -20,7 +20,7 @@ void main() {
return App( return App(
authenticationRepository: authenticationRepository, authenticationRepository: authenticationRepository,
leaderboardRepository: leaderboardRepository, leaderboardRepository: leaderboardRepository,
pinballAudio: pinballAudio, pinballPlayer: pinballPlayer,
); );
}); });
} }

@ -11,7 +11,7 @@ void main() {
bootstrap((firestore, firebaseAuth) async { bootstrap((firestore, firebaseAuth) async {
final leaderboardRepository = LeaderboardRepository(firestore); final leaderboardRepository = LeaderboardRepository(firestore);
final authenticationRepository = AuthenticationRepository(firebaseAuth); final authenticationRepository = AuthenticationRepository(firebaseAuth);
final pinballAudio = PinballAudio(); final pinballPlayer = PinballPlayer();
unawaited( unawaited(
Firebase.initializeApp().then( Firebase.initializeApp().then(
(_) => authenticationRepository.authenticateAnonymously(), (_) => authenticationRepository.authenticateAnonymously(),
@ -20,7 +20,7 @@ void main() {
return App( return App(
authenticationRepository: authenticationRepository, authenticationRepository: authenticationRepository,
leaderboardRepository: leaderboardRepository, leaderboardRepository: leaderboardRepository,
pinballAudio: pinballAudio, pinballPlayer: pinballPlayer,
); );
}); });
} }

@ -4,7 +4,6 @@ import 'package:pinball/game/game.dart';
import 'package:pinball/how_to_play/how_to_play.dart'; import 'package:pinball/how_to_play/how_to_play.dart';
import 'package:pinball/select_character/select_character.dart'; import 'package:pinball/select_character/select_character.dart';
import 'package:pinball/start_game/start_game.dart'; import 'package:pinball/start_game/start_game.dart';
import 'package:pinball_audio/pinball_audio.dart';
import 'package:pinball_ui/pinball_ui.dart'; import 'package:pinball_ui/pinball_ui.dart';
/// {@template start_game_listener} /// {@template start_game_listener}
@ -57,14 +56,11 @@ class StartGameListener extends StatelessWidget {
} }
void _onHowToPlay(BuildContext context) { void _onHowToPlay(BuildContext context) {
final audio = context.read<PinballAudio>();
_showPinballDialog( _showPinballDialog(
context: context, context: context,
child: HowToPlayDialog( child: HowToPlayDialog(
onDismissCallback: () { onDismissCallback: () {
context.read<StartGameBloc>().add(const HowToPlayFinished()); context.read<StartGameBloc>().add(const HowToPlayFinished());
audio.ioPinballVoiceOver();
}, },
), ),
); );

@ -3,10 +3,25 @@ import 'dart:math';
import 'package:audioplayers/audioplayers.dart'; import 'package:audioplayers/audioplayers.dart';
import 'package:flame_audio/audio_pool.dart'; import 'package:flame_audio/audio_pool.dart';
import 'package:flame_audio/flame_audio.dart'; import 'package:flame_audio/flame_audio.dart';
import 'package:flutter/material.dart';
import 'package:pinball_audio/gen/assets.gen.dart'; import 'package:pinball_audio/gen/assets.gen.dart';
/// Function that defines the contract of the creation /// Sounds available for play
/// of an [AudioPool] enum PinballAudio {
/// Google
google,
/// Bumper
bumper,
/// Background music
backgroundMusic,
/// IO Pinball voice over
ioPinballVoiceOver
}
/// Defines the contract of the creation of an [AudioPool].
typedef CreateAudioPool = Future<AudioPool> Function( typedef CreateAudioPool = Future<AudioPool> Function(
String sound, { String sound, {
bool? repeating, bool? repeating,
@ -31,12 +46,97 @@ typedef PreCacheSingleAudio = Future<void> Function(String);
/// an [AudioCache] instance /// an [AudioCache] instance
typedef ConfigureAudioCache = void Function(AudioCache); typedef ConfigureAudioCache = void Function(AudioCache);
/// {@template pinball_audio} abstract class _Audio {
void play();
Future<void> load();
String prefixFile(String file) {
return 'packages/pinball_audio/$file';
}
}
class _SimplePlayAudio extends _Audio {
_SimplePlayAudio({
required this.preCacheSingleAudio,
required this.playSingleAudio,
required this.path,
});
final PreCacheSingleAudio preCacheSingleAudio;
final PlaySingleAudio playSingleAudio;
final String path;
@override
Future<void> load() => preCacheSingleAudio(prefixFile(path));
@override
void play() {
playSingleAudio(prefixFile(path));
}
}
class _LoopAudio extends _Audio {
_LoopAudio({
required this.preCacheSingleAudio,
required this.loopSingleAudio,
required this.path,
});
final PreCacheSingleAudio preCacheSingleAudio;
final LoopSingleAudio loopSingleAudio;
final String path;
@override
Future<void> load() => preCacheSingleAudio(prefixFile(path));
@override
void play() {
loopSingleAudio(prefixFile(path));
}
}
class _BumperAudio extends _Audio {
_BumperAudio({
required this.createAudioPool,
required this.seed,
});
final CreateAudioPool createAudioPool;
final Random seed;
late AudioPool bumperA;
late AudioPool bumperB;
@override
Future<void> load() async {
await Future.wait(
[
createAudioPool(
prefixFile(Assets.sfx.bumperA),
maxPlayers: 4,
prefix: '',
).then((pool) => bumperA = pool),
createAudioPool(
prefixFile(Assets.sfx.bumperB),
maxPlayers: 4,
prefix: '',
).then((pool) => bumperB = pool),
],
);
}
@override
void play() {
(seed.nextBool() ? bumperA : bumperB).start(volume: 0.6);
}
}
/// {@template pinball_player}
/// Sound manager for the pinball game /// Sound manager for the pinball game
/// {@endtemplate} /// {@endtemplate}
class PinballAudio { class PinballPlayer {
/// {@macro pinball_audio} /// {@macro pinball_player}
PinballAudio({ PinballPlayer({
CreateAudioPool? createAudioPool, CreateAudioPool? createAudioPool,
PlaySingleAudio? playSingleAudio, PlaySingleAudio? playSingleAudio,
LoopSingleAudio? loopSingleAudio, LoopSingleAudio? loopSingleAudio,
@ -52,7 +152,29 @@ class PinballAudio {
((AudioCache a) { ((AudioCache a) {
a.prefix = ''; a.prefix = '';
}), }),
_seed = seed ?? Random(); _seed = seed ?? Random() {
audios = {
PinballAudio.google: _SimplePlayAudio(
preCacheSingleAudio: _preCacheSingleAudio,
playSingleAudio: _playSingleAudio,
path: Assets.sfx.google,
),
PinballAudio.ioPinballVoiceOver: _SimplePlayAudio(
preCacheSingleAudio: _preCacheSingleAudio,
playSingleAudio: _playSingleAudio,
path: Assets.sfx.ioPinballVoiceOver,
),
PinballAudio.bumper: _BumperAudio(
createAudioPool: _createAudioPool,
seed: _seed,
),
PinballAudio.backgroundMusic: _LoopAudio(
preCacheSingleAudio: _preCacheSingleAudio,
loopSingleAudio: _loopSingleAudio,
path: Assets.music.background,
),
};
}
final CreateAudioPool _createAudioPool; final CreateAudioPool _createAudioPool;
@ -66,54 +188,24 @@ class PinballAudio {
final Random _seed; final Random _seed;
late AudioPool _bumperAPool; /// Registered audios on the Player
@visibleForTesting
late AudioPool _bumperBPool; // ignore: library_private_types_in_public_api
late final Map<PinballAudio, _Audio> audios;
/// Loads the sounds effects into the memory /// Loads the sounds effects into the memory
Future<void> load() async { List<Future<void>> load() {
_configureAudioCache(FlameAudio.audioCache); _configureAudioCache(FlameAudio.audioCache);
_bumperAPool = await _createAudioPool( return audios.values.map((a) => a.load()).toList();
_prefixFile(Assets.sfx.bumperA),
maxPlayers: 4,
prefix: '',
);
_bumperBPool = await _createAudioPool(
_prefixFile(Assets.sfx.bumperB),
maxPlayers: 4,
prefix: '',
);
await Future.wait([
_preCacheSingleAudio(_prefixFile(Assets.sfx.google)),
_preCacheSingleAudio(_prefixFile(Assets.sfx.ioPinballVoiceOver)),
_preCacheSingleAudio(_prefixFile(Assets.music.background)),
]);
}
/// Plays a random bumper sfx.
void bumper() {
(_seed.nextBool() ? _bumperAPool : _bumperBPool).start(volume: 0.6);
} }
/// Plays the google word bonus /// Plays the received auido
void googleBonus() { void play(PinballAudio audio) {
_playSingleAudio(_prefixFile(Assets.sfx.google)); assert(
} audios.containsKey(audio),
'Tried to play unregistered audio $audio',
/// Plays the I/O Pinball voice over audio. );
void ioPinballVoiceOver() { audios[audio]?.play();
_playSingleAudio(_prefixFile(Assets.sfx.ioPinballVoiceOver));
}
/// Plays the background music
void backgroundMusic() {
_loopSingleAudio(_prefixFile(Assets.music.background));
}
String _prefixFile(String file) {
return 'packages/pinball_audio/$file';
} }
} }

@ -51,7 +51,7 @@ void main() {
late _MockLoopSingleAudio loopSingleAudio; late _MockLoopSingleAudio loopSingleAudio;
late _PreCacheSingleAudio preCacheSingleAudio; late _PreCacheSingleAudio preCacheSingleAudio;
late Random seed; late Random seed;
late PinballAudio audio; late PinballPlayer player;
setUpAll(() { setUpAll(() {
registerFallbackValue(_MockAudioCache()); registerFallbackValue(_MockAudioCache());
@ -81,7 +81,7 @@ void main() {
seed = _MockRandom(); seed = _MockRandom();
audio = PinballAudio( player = PinballPlayer(
configureAudioCache: configureAudioCache.onCall, configureAudioCache: configureAudioCache.onCall,
createAudioPool: createAudioPool.onCall, createAudioPool: createAudioPool.onCall,
playSingleAudio: playSingleAudio.onCall, playSingleAudio: playSingleAudio.onCall,
@ -92,12 +92,12 @@ void main() {
}); });
test('can be instantiated', () { test('can be instantiated', () {
expect(PinballAudio(), isNotNull); expect(PinballPlayer(), isNotNull);
}); });
group('load', () { group('load', () {
test('creates the bumpers pools', () async { test('creates the bumpers pools', () async {
await audio.load(); await Future.wait(player.load());
verify( verify(
() => createAudioPool.onCall( () => createAudioPool.onCall(
@ -117,25 +117,25 @@ void main() {
}); });
test('configures the audio cache instance', () async { test('configures the audio cache instance', () async {
await audio.load(); await Future.wait(player.load());
verify(() => configureAudioCache.onCall(FlameAudio.audioCache)) verify(() => configureAudioCache.onCall(FlameAudio.audioCache))
.called(1); .called(1);
}); });
test('sets the correct prefix', () async { test('sets the correct prefix', () async {
audio = PinballAudio( player = PinballPlayer(
createAudioPool: createAudioPool.onCall, createAudioPool: createAudioPool.onCall,
playSingleAudio: playSingleAudio.onCall, playSingleAudio: playSingleAudio.onCall,
preCacheSingleAudio: preCacheSingleAudio.onCall, preCacheSingleAudio: preCacheSingleAudio.onCall,
); );
await audio.load(); await Future.wait(player.load());
expect(FlameAudio.audioCache.prefix, equals('')); expect(FlameAudio.audioCache.prefix, equals(''));
}); });
test('pre cache the assets', () async { test('pre cache the assets', () async {
await audio.load(); await Future.wait(player.load());
verify( verify(
() => preCacheSingleAudio () => preCacheSingleAudio
@ -184,8 +184,8 @@ void main() {
group('when seed is true', () { group('when seed is true', () {
test('plays the bumper A sound pool', () async { test('plays the bumper A sound pool', () async {
when(seed.nextBool).thenReturn(true); when(seed.nextBool).thenReturn(true);
await audio.load(); await Future.wait(player.load());
audio.bumper(); player.play(PinballAudio.bumper);
verify(() => bumperAPool.start(volume: 0.6)).called(1); verify(() => bumperAPool.start(volume: 0.6)).called(1);
}); });
@ -194,8 +194,8 @@ void main() {
group('when seed is false', () { group('when seed is false', () {
test('plays the bumper B sound pool', () async { test('plays the bumper B sound pool', () async {
when(seed.nextBool).thenReturn(false); when(seed.nextBool).thenReturn(false);
await audio.load(); await Future.wait(player.load());
audio.bumper(); player.play(PinballAudio.bumper);
verify(() => bumperBPool.start(volume: 0.6)).called(1); verify(() => bumperBPool.start(volume: 0.6)).called(1);
}); });
@ -204,8 +204,8 @@ void main() {
group('googleBonus', () { group('googleBonus', () {
test('plays the correct file', () async { test('plays the correct file', () async {
await audio.load(); await Future.wait(player.load());
audio.googleBonus(); player.play(PinballAudio.google);
verify( verify(
() => playSingleAudio () => playSingleAudio
@ -216,8 +216,8 @@ void main() {
group('ioPinballVoiceOver', () { group('ioPinballVoiceOver', () {
test('plays the correct file', () async { test('plays the correct file', () async {
await audio.load(); await Future.wait(player.load());
audio.ioPinballVoiceOver(); player.play(PinballAudio.ioPinballVoiceOver);
verify( verify(
() => playSingleAudio.onCall( () => playSingleAudio.onCall(
@ -229,8 +229,8 @@ void main() {
group('backgroundMusic', () { group('backgroundMusic', () {
test('plays the correct file', () async { test('plays the correct file', () async {
await audio.load(); await Future.wait(player.load());
audio.backgroundMusic(); player.play(PinballAudio.backgroundMusic);
verify( verify(
() => loopSingleAudio () => loopSingleAudio
@ -238,5 +238,15 @@ void main() {
).called(1); ).called(1);
}); });
}); });
test(
'throws assertions error when playing an unregistered audio',
() async {
player.audios.remove(PinballAudio.google);
await Future.wait(player.load());
expect(() => player.play(PinballAudio.google), throwsAssertionError);
},
);
}); });
} }

@ -9,7 +9,7 @@ import 'package:pinball_audio/pinball_audio.dart';
class _MockAuthenticationRepository extends Mock class _MockAuthenticationRepository extends Mock
implements AuthenticationRepository {} implements AuthenticationRepository {}
class _MockPinballAudio extends Mock implements PinballAudio {} class _MockPinballPlayer extends Mock implements PinballPlayer {}
class _MockLeaderboardRepository extends Mock implements LeaderboardRepository { class _MockLeaderboardRepository extends Mock implements LeaderboardRepository {
} }
@ -18,13 +18,13 @@ void main() {
group('App', () { group('App', () {
late AuthenticationRepository authenticationRepository; late AuthenticationRepository authenticationRepository;
late LeaderboardRepository leaderboardRepository; late LeaderboardRepository leaderboardRepository;
late PinballAudio pinballAudio; late PinballPlayer pinballPlayer;
setUp(() { setUp(() {
authenticationRepository = _MockAuthenticationRepository(); authenticationRepository = _MockAuthenticationRepository();
leaderboardRepository = _MockLeaderboardRepository(); leaderboardRepository = _MockLeaderboardRepository();
pinballAudio = _MockPinballAudio(); pinballPlayer = _MockPinballPlayer();
when(pinballAudio.load).thenAnswer((_) => Future.value()); when(pinballPlayer.load).thenAnswer((_) => [Future.value()]);
}); });
testWidgets('renders PinballGamePage', (tester) async { testWidgets('renders PinballGamePage', (tester) async {
@ -32,7 +32,7 @@ void main() {
App( App(
authenticationRepository: authenticationRepository, authenticationRepository: authenticationRepository,
leaderboardRepository: leaderboardRepository, leaderboardRepository: leaderboardRepository,
pinballAudio: pinballAudio, pinballPlayer: pinballPlayer,
), ),
); );
expect(find.byType(PinballGamePage), findsOneWidget); expect(find.byType(PinballGamePage), findsOneWidget);

@ -16,7 +16,7 @@ class _TestBodyComponent extends BodyComponent {
} }
} }
class _MockPinballAudio extends Mock implements PinballAudio {} class _MockPinballPlayer extends Mock implements PinballPlayer {}
class _MockContact extends Mock implements Contact {} class _MockContact extends Mock implements Contact {}
@ -25,13 +25,13 @@ void main() {
group('BumperNoisyBehavior', () {}); group('BumperNoisyBehavior', () {});
late PinballAudio audio; late PinballPlayer player;
final flameTester = FlameTester( final flameTester = FlameTester(
() => EmptyPinballTestGame(audio: audio), () => EmptyPinballTestGame(player: player),
); );
setUp(() { setUp(() {
audio = _MockPinballAudio(); player = _MockPinballPlayer();
}); });
flameTester.testGameWidget( flameTester.testGameWidget(
@ -44,7 +44,7 @@ void main() {
behavior.beginContact(Object(), _MockContact()); behavior.beginContact(Object(), _MockContact());
}, },
verify: (_, __) async { verify: (_, __) async {
verify(audio.bumper).called(1); verify(() => player.play(PinballAudio.bumper)).called(1);
}, },
); );
} }

@ -16,7 +16,7 @@ class _MockCameraController extends Mock implements CameraController {}
class _MockActiveOverlaysNotifier extends Mock class _MockActiveOverlaysNotifier extends Mock
implements ActiveOverlaysNotifier {} implements ActiveOverlaysNotifier {}
class _MockPinballAudio extends Mock implements PinballAudio {} class _MockPinballPlayer extends Mock implements PinballPlayer {}
void main() { void main() {
group('GameFlowController', () { group('GameFlowController', () {
@ -43,7 +43,7 @@ void main() {
late Backbox backbox; late Backbox backbox;
late CameraController cameraController; late CameraController cameraController;
late GameFlowController gameFlowController; late GameFlowController gameFlowController;
late PinballAudio pinballAudio; late PinballPlayer pinballPlayer;
late ActiveOverlaysNotifier overlays; late ActiveOverlaysNotifier overlays;
setUp(() { setUp(() {
@ -52,7 +52,7 @@ void main() {
cameraController = _MockCameraController(); cameraController = _MockCameraController();
gameFlowController = GameFlowController(game); gameFlowController = GameFlowController(game);
overlays = _MockActiveOverlaysNotifier(); overlays = _MockActiveOverlaysNotifier();
pinballAudio = _MockPinballAudio(); pinballPlayer = _MockPinballPlayer();
when( when(
() => backbox.initialsInput( () => backbox.initialsInput(
@ -71,7 +71,7 @@ void main() {
when(game.firstChild<CameraController>).thenReturn(cameraController); when(game.firstChild<CameraController>).thenReturn(cameraController);
when(() => game.overlays).thenReturn(overlays); when(() => game.overlays).thenReturn(overlays);
when(() => game.characterTheme).thenReturn(DashTheme()); when(() => game.characterTheme).thenReturn(DashTheme());
when(() => game.audio).thenReturn(pinballAudio); when(() => game.player).thenReturn(pinballPlayer);
}); });
test( test(
@ -115,7 +115,8 @@ void main() {
() { () {
gameFlowController.onNewState(GameState.initial()); gameFlowController.onNewState(GameState.initial());
verify(pinballAudio.backgroundMusic).called(1); verify(() => pinballPlayer.play(PinballAudio.backgroundMusic))
.called(1);
}, },
); );
}); });

@ -24,12 +24,12 @@ class _MockGameBloc extends Mock implements GameBloc {}
class _MockStartGameBloc extends Mock implements StartGameBloc {} class _MockStartGameBloc extends Mock implements StartGameBloc {}
class _MockPinballAudio extends Mock implements PinballAudio {} class _MockPinballPlayer extends Mock implements PinballPlayer {}
PinballAudio _buildDefaultPinballAudio() { PinballPlayer _buildDefaultPinballPlayer() {
final audio = _MockPinballAudio(); final player = _MockPinballPlayer();
when(audio.load).thenAnswer((_) => Future.value()); when(player.load).thenAnswer((_) => [Future.value()]);
return audio; return player;
} }
AssetsManagerCubit _buildDefaultAssetsManagerCubit() { AssetsManagerCubit _buildDefaultAssetsManagerCubit() {
@ -55,7 +55,7 @@ extension PumpApp on WidgetTester {
AssetsManagerCubit? assetsManagerCubit, AssetsManagerCubit? assetsManagerCubit,
CharacterThemeCubit? characterThemeCubit, CharacterThemeCubit? characterThemeCubit,
LeaderboardRepository? leaderboardRepository, LeaderboardRepository? leaderboardRepository,
PinballAudio? pinballAudio, PinballPlayer? pinballPlayer,
}) { }) {
return runAsync(() { return runAsync(() {
return pumpWidget( return pumpWidget(
@ -65,7 +65,7 @@ extension PumpApp on WidgetTester {
value: leaderboardRepository ?? _MockLeaderboardRepository(), value: leaderboardRepository ?? _MockLeaderboardRepository(),
), ),
RepositoryProvider.value( RepositoryProvider.value(
value: pinballAudio ?? _buildDefaultPinballAudio(), value: pinballPlayer ?? _buildDefaultPinballPlayer(),
), ),
], ],
child: MultiBlocProvider( child: MultiBlocProvider(

@ -11,7 +11,7 @@ import 'package:pinball/l10n/l10n.dart';
import 'package:pinball_audio/pinball_audio.dart'; import 'package:pinball_audio/pinball_audio.dart';
import 'package:pinball_theme/pinball_theme.dart'; import 'package:pinball_theme/pinball_theme.dart';
class _MockPinballAudio extends Mock implements PinballAudio {} class _MockPinballPlayer extends Mock implements PinballPlayer {}
class _MockAppLocalizations extends Mock implements AppLocalizations {} class _MockAppLocalizations extends Mock implements AppLocalizations {}
@ -24,12 +24,12 @@ class TestGame extends Forge2DGame with FlameBloc {
class PinballTestGame extends PinballGame { class PinballTestGame extends PinballGame {
PinballTestGame({ PinballTestGame({
List<String>? assets, List<String>? assets,
PinballAudio? audio, PinballPlayer? player,
CharacterTheme? theme, CharacterTheme? theme,
AppLocalizations? l10n, AppLocalizations? l10n,
}) : _assets = assets, }) : _assets = assets,
super( super(
audio: audio ?? _MockPinballAudio(), player: player ?? _MockPinballPlayer(),
characterTheme: theme ?? const DashTheme(), characterTheme: theme ?? const DashTheme(),
l10n: l10n ?? _MockAppLocalizations(), l10n: l10n ?? _MockAppLocalizations(),
); );
@ -47,12 +47,12 @@ class PinballTestGame extends PinballGame {
class DebugPinballTestGame extends DebugPinballGame { class DebugPinballTestGame extends DebugPinballGame {
DebugPinballTestGame({ DebugPinballTestGame({
List<String>? assets, List<String>? assets,
PinballAudio? audio, PinballPlayer? player,
CharacterTheme? theme, CharacterTheme? theme,
AppLocalizations? l10n, AppLocalizations? l10n,
}) : _assets = assets, }) : _assets = assets,
super( super(
audio: audio ?? _MockPinballAudio(), player: player ?? _MockPinballPlayer(),
characterTheme: theme ?? const DashTheme(), characterTheme: theme ?? const DashTheme(),
l10n: l10n ?? _MockAppLocalizations(), l10n: l10n ?? _MockAppLocalizations(),
); );
@ -71,12 +71,12 @@ class DebugPinballTestGame extends DebugPinballGame {
class EmptyPinballTestGame extends PinballTestGame { class EmptyPinballTestGame extends PinballTestGame {
EmptyPinballTestGame({ EmptyPinballTestGame({
List<String>? assets, List<String>? assets,
PinballAudio? audio, PinballPlayer? player,
CharacterTheme? theme, CharacterTheme? theme,
AppLocalizations? l10n, AppLocalizations? l10n,
}) : super( }) : super(
assets: assets, assets: assets,
audio: audio, player: player,
theme: theme, theme: theme,
l10n: l10n ?? _MockAppLocalizations(), l10n: l10n ?? _MockAppLocalizations(),
); );
@ -93,12 +93,12 @@ class EmptyKeyboardPinballTestGame extends PinballTestGame
with HasKeyboardHandlerComponents { with HasKeyboardHandlerComponents {
EmptyKeyboardPinballTestGame({ EmptyKeyboardPinballTestGame({
List<String>? assets, List<String>? assets,
PinballAudio? audio, PinballPlayer? player,
CharacterTheme? theme, CharacterTheme? theme,
AppLocalizations? l10n, AppLocalizations? l10n,
}) : super( }) : super(
assets: assets, assets: assets,
audio: audio, player: player,
theme: theme, theme: theme,
l10n: l10n ?? _MockAppLocalizations(), l10n: l10n ?? _MockAppLocalizations(),
); );

@ -18,12 +18,12 @@ class _MockPinballGame extends Mock implements PinballGame {}
class _MockGameFlowController extends Mock implements GameFlowController {} class _MockGameFlowController extends Mock implements GameFlowController {}
class _MockPinballAudio extends Mock implements PinballAudio {} class _MockPinballPlayer extends Mock implements PinballPlayer {}
void main() { void main() {
late StartGameBloc startGameBloc; late StartGameBloc startGameBloc;
late PinballGame pinballGame; late PinballGame pinballGame;
late PinballAudio pinballAudio; late PinballPlayer pinballPlayer;
late CharacterThemeCubit characterThemeCubit; late CharacterThemeCubit characterThemeCubit;
group('StartGameListener', () { group('StartGameListener', () {
@ -32,7 +32,7 @@ void main() {
startGameBloc = _MockStartGameBloc(); startGameBloc = _MockStartGameBloc();
pinballGame = _MockPinballGame(); pinballGame = _MockPinballGame();
pinballAudio = _MockPinballAudio(); pinballPlayer = _MockPinballPlayer();
characterThemeCubit = _MockCharacterThemeCubit(); characterThemeCubit = _MockCharacterThemeCubit();
}); });
@ -244,7 +244,7 @@ void main() {
child: const SizedBox.shrink(), child: const SizedBox.shrink(),
), ),
startGameBloc: startGameBloc, startGameBloc: startGameBloc,
pinballAudio: pinballAudio, pinballPlayer: pinballPlayer,
); );
await tester.pumpAndSettle(); await tester.pumpAndSettle();
@ -261,7 +261,8 @@ void main() {
); );
await tester.pumpAndSettle(); await tester.pumpAndSettle();
verify(pinballAudio.ioPinballVoiceOver).called(1); verify(() => pinballPlayer.play(PinballAudio.ioPinballVoiceOver))
.called(1);
}, },
); );
}); });

Loading…
Cancel
Save