Merge branch 'main' into release

release
Tom Arra 2 years ago
commit 7e439975f6

@ -0,0 +1,26 @@
import 'package:flame/components.dart';
import 'package:pinball_flame/pinball_flame.dart';
class AnimatronicLoopingBehavior extends TimerComponent
with ParentIsA<SpriteAnimationComponent> {
AnimatronicLoopingBehavior({
required double animationCoolDown,
}) : super(period: animationCoolDown);
@override
Future<void> onLoad() async {
await super.onLoad();
parent.animation?.onComplete = () {
parent.animation?.reset();
parent.playing = false;
timer
..reset()
..start();
};
}
@override
void onTick() {
parent.playing = true;
}
}

@ -1,3 +1,4 @@
export 'animatronic_looping_behavior.dart';
export 'ball_spawning_behavior.dart'; export 'ball_spawning_behavior.dart';
export 'bonus_ball_spawning_behavior.dart'; export 'bonus_ball_spawning_behavior.dart';
export 'bonus_noise_behavior.dart'; export 'bonus_noise_behavior.dart';

@ -21,7 +21,6 @@ class FlutterForestBonusBehavior extends Component
final bumpers = parent.children.whereType<DashBumper>(); final bumpers = parent.children.whereType<DashBumper>();
final signpost = parent.firstChild<Signpost>()!; final signpost = parent.firstChild<Signpost>()!;
final animatronic = parent.firstChild<DashAnimatronic>()!;
for (final bumper in bumpers) { for (final bumper in bumpers) {
bumper.bloc.stream.listen((state) { bumper.bloc.stream.listen((state) {
@ -38,7 +37,6 @@ class FlutterForestBonusBehavior extends Component
if (signpost.bloc.isFullyProgressed()) { if (signpost.bloc.isFullyProgressed()) {
bloc.add(const BonusActivated(GameBonus.dashNest)); bloc.add(const BonusActivated(GameBonus.dashNest));
add(BonusBallSpawningBehavior()); add(BonusBallSpawningBehavior());
animatronic.playing = true;
signpost.bloc.onProgressed(); signpost.bloc.onProgressed();
} }
} }

@ -40,7 +40,11 @@ class FlutterForest extends Component with ZIndex {
BumperNoiseBehavior(), BumperNoiseBehavior(),
], ],
)..initialPosition = Vector2(21.8, -46.75), )..initialPosition = Vector2(21.8, -46.75),
DashAnimatronic()..position = Vector2(20, -66), DashAnimatronic(
children: [
AnimatronicLoopingBehavior(animationCoolDown: 4),
],
)..position = Vector2(20, -66),
FlutterForestBonusBehavior(), FlutterForestBonusBehavior(),
], ],
) { ) {

@ -61,6 +61,11 @@ class GameBlocStatusListener extends Component
.single .single
.bloc .bloc
.onReset(); .onReset();
gameRef
.descendants()
.whereType<DashBumper>()
.forEach((bumper) => bumper.bloc.onReset());
gameRef.descendants().whereType<Signpost>().single.bloc.onReset();
} }
void _addPlungerBehaviors(Plunger plunger) { void _addPlungerBehaviors(Plunger plunger) {

@ -12,13 +12,11 @@ class SparkyComputerBonusBehavior extends Component
void onMount() { void onMount() {
super.onMount(); super.onMount();
final sparkyComputer = parent.firstChild<SparkyComputer>()!; final sparkyComputer = parent.firstChild<SparkyComputer>()!;
final animatronic = parent.firstChild<SparkyAnimatronic>()!;
sparkyComputer.bloc.stream.listen((state) async { sparkyComputer.bloc.stream.listen((state) async {
final listenWhen = state == SparkyComputerState.withBall; final listenWhen = state == SparkyComputerState.withBall;
if (!listenWhen) return; if (!listenWhen) return;
bloc.add(const BonusActivated(GameBonus.sparkyTurboCharge)); bloc.add(const BonusActivated(GameBonus.sparkyTurboCharge));
animatronic.playing = true;
}); });
} }
} }

@ -33,7 +33,11 @@ class SparkyScorch extends Component {
BumperNoiseBehavior(), BumperNoiseBehavior(),
], ],
)..initialPosition = Vector2(-3.3, -52.55), )..initialPosition = Vector2(-3.3, -52.55),
SparkyAnimatronic()..position = Vector2(-14, -58.2), SparkyAnimatronic(
children: [
AnimatronicLoopingBehavior(animationCoolDown: 3),
],
)..position = Vector2(-14, -58.2),
SparkyComputer( SparkyComputer(
children: [ children: [
ScoringContactBehavior(points: Points.twoHundredThousand) ScoringContactBehavior(points: Points.twoHundredThousand)

@ -20,6 +20,7 @@ class $AssetsSfxGen {
String get cowMoo => 'assets/sfx/cow_moo.mp3'; String get cowMoo => 'assets/sfx/cow_moo.mp3';
String get dash => 'assets/sfx/dash.mp3'; String get dash => 'assets/sfx/dash.mp3';
String get dino => 'assets/sfx/dino.mp3'; String get dino => 'assets/sfx/dino.mp3';
String get flipper => 'assets/sfx/flipper.mp3';
String get gameOverVoiceOver => 'assets/sfx/game_over_voice_over.mp3'; String get gameOverVoiceOver => 'assets/sfx/game_over_voice_over.mp3';
String get google => 'assets/sfx/google.mp3'; String get google => 'assets/sfx/google.mp3';
String get ioPinballVoiceOver => 'assets/sfx/io_pinball_voice_over.mp3'; String get ioPinballVoiceOver => 'assets/sfx/io_pinball_voice_over.mp3';

@ -39,14 +39,17 @@ enum PinballAudio {
/// Sparky. /// Sparky.
sparky, sparky,
/// Android /// Android.
android, android,
/// Dino /// Dino.
dino, dino,
/// Dash /// Dash.
dash, dash,
/// Flipper.
flipper,
} }
/// Defines the contract of the creation of an [AudioPool]. /// Defines the contract of the creation of an [AudioPool].
@ -147,6 +150,31 @@ class _SingleLoopAudio extends _LoopAudio {
} }
} }
class _SingleAudioPool extends _Audio {
_SingleAudioPool({
required this.path,
required this.createAudioPool,
required this.maxPlayers,
});
final String path;
final CreateAudioPool createAudioPool;
final int maxPlayers;
late AudioPool pool;
@override
Future<void> load() async {
pool = await createAudioPool(
prefixFile(path),
maxPlayers: maxPlayers,
prefix: '',
);
}
@override
void play() => pool.start();
}
class _RandomABAudio extends _Audio { class _RandomABAudio extends _Audio {
_RandomABAudio({ _RandomABAudio({
required this.createAudioPool, required this.createAudioPool,
@ -277,6 +305,11 @@ class PinballAudioPlayer {
path: Assets.sfx.rollover, path: Assets.sfx.rollover,
volume: 0.3, volume: 0.3,
), ),
PinballAudio.flipper: _SingleAudioPool(
path: Assets.sfx.flipper,
createAudioPool: _createAudioPool,
maxPlayers: 2,
),
PinballAudio.ioPinballVoiceOver: _SimplePlayAudio( PinballAudio.ioPinballVoiceOver: _SimplePlayAudio(
preCacheSingleAudio: _preCacheSingleAudio, preCacheSingleAudio: _preCacheSingleAudio,
playSingleAudio: _playSingleAudio, playSingleAudio: _playSingleAudio,

@ -145,6 +145,20 @@ void main() {
).called(1); ).called(1);
}); });
test('creates the flipper pool', () async {
await Future.wait(
audioPlayer.load().map((loadableBuilder) => loadableBuilder()),
);
verify(
() => createAudioPool.onCall(
'packages/pinball_audio/${Assets.sfx.flipper}',
maxPlayers: 2,
prefix: '',
),
).called(1);
});
test('configures the audio cache instance', () async { test('configures the audio cache instance', () async {
await Future.wait( await Future.wait(
audioPlayer.load().map((loadableBuilder) => loadableBuilder()), audioPlayer.load().map((loadableBuilder) => loadableBuilder()),
@ -327,6 +341,33 @@ void main() {
}); });
}); });
group('flipper', () {
late AudioPool pool;
setUp(() {
pool = _MockAudioPool();
when(() => pool.start(volume: any(named: 'volume')))
.thenAnswer((_) async => () {});
when(
() => createAudioPool.onCall(
'packages/pinball_audio/${Assets.sfx.flipper}',
maxPlayers: any(named: 'maxPlayers'),
prefix: any(named: 'prefix'),
),
).thenAnswer((_) async => pool);
});
test('plays the flipper sound pool', () async {
when(seed.nextBool).thenReturn(true);
await Future.wait(
audioPlayer.load().map((loadableBuilder) => loadableBuilder()),
);
audioPlayer.play(PinballAudio.flipper);
verify(() => pool.start()).called(1);
});
});
group('cow moo', () { group('cow moo', () {
test('plays the correct file', () async { test('plays the correct file', () async {
await Future.wait( await Future.wait(

@ -6,10 +6,11 @@ import 'package:pinball_components/pinball_components.dart';
/// {@endtemplate} /// {@endtemplate}
class DashAnimatronic extends SpriteAnimationComponent with HasGameRef { class DashAnimatronic extends SpriteAnimationComponent with HasGameRef {
/// {@macro dash_animatronic} /// {@macro dash_animatronic}
DashAnimatronic() DashAnimatronic({Iterable<Component>? children})
: super( : super(
anchor: Anchor.center, anchor: Anchor.center,
playing: false, playing: false,
children: children,
); );
@override @override
@ -37,9 +38,6 @@ class DashAnimatronic extends SpriteAnimationComponent with HasGameRef {
textureSize: textureSize, textureSize: textureSize,
loop: false, loop: false,
), ),
)..onComplete = () { );
animation?.reset();
playing = false;
};
} }
} }

@ -1,3 +1,4 @@
export 'flipper_jointing_behavior.dart'; export 'flipper_jointing_behavior.dart';
export 'flipper_key_controlling_behavior.dart'; export 'flipper_key_controlling_behavior.dart';
export 'flipper_moving_behavior.dart'; export 'flipper_moving_behavior.dart';
export 'flipper_noise_behavior.dart';

@ -15,7 +15,9 @@ class FlipperMovingBehavior extends Component
late final Flipper _flipper; late final Flipper _flipper;
void _moveUp() => _flipper.body.linearVelocity = Vector2(0, -_strength); void _moveUp() {
_flipper.body.linearVelocity = Vector2(0, -_strength);
}
void _moveDown() => _flipper.body.linearVelocity = Vector2(0, _strength); void _moveDown() => _flipper.body.linearVelocity = Vector2(0, _strength);

@ -0,0 +1,18 @@
import 'package:flame/components.dart';
import 'package:flame_bloc/flame_bloc.dart';
import 'package:pinball_audio/pinball_audio.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
class FlipperNoiseBehavior extends Component
with
FlameBlocListenable<FlipperCubit, FlipperState>,
FlameBlocReader<FlipperCubit, FlipperState> {
@override
void onNewState(FlipperState state) {
super.onNewState(state);
if (bloc.state.isMovingUp) {
readProvider<PinballAudioPlayer>().play(PinballAudio.flipper);
}
}
}

@ -25,7 +25,10 @@ class Flipper extends BodyComponent with KeyboardHandler, InitialPosition {
FlipperJointingBehavior(), FlipperJointingBehavior(),
FlameBlocProvider<FlipperCubit, FlipperState>( FlameBlocProvider<FlipperCubit, FlipperState>(
create: FlipperCubit.new, create: FlipperCubit.new,
children: [FlipperMovingBehavior(strength: 90)], children: [
FlipperMovingBehavior(strength: 90),
FlipperNoiseBehavior(),
],
), ),
], ],
); );

@ -12,5 +12,7 @@ class SignpostCubit extends Cubit<SignpostState> {
); );
} }
void onReset() => emit(SignpostState.inactive);
bool isFullyProgressed() => state == SignpostState.active3; bool isFullyProgressed() => state == SignpostState.active3;
} }

@ -8,10 +8,11 @@ import 'package:pinball_flame/pinball_flame.dart';
class SparkyAnimatronic extends SpriteAnimationComponent class SparkyAnimatronic extends SpriteAnimationComponent
with HasGameRef, ZIndex { with HasGameRef, ZIndex {
/// {@macro sparky_animatronic} /// {@macro sparky_animatronic}
SparkyAnimatronic() SparkyAnimatronic({Iterable<Component>? children})
: super( : super(
anchor: Anchor.center, anchor: Anchor.center,
playing: false, playing: false,
children: children,
) { ) {
zIndex = ZIndexes.sparkyAnimatronic; zIndex = ZIndexes.sparkyAnimatronic;
} }
@ -41,9 +42,6 @@ class SparkyAnimatronic extends SpriteAnimationComponent
textureSize: textureSize, textureSize: textureSize,
loop: false, loop: false,
), ),
)..onComplete = () { );
animation?.reset();
playing = false;
};
} }
} }

@ -1,6 +1,6 @@
// ignore_for_file: cascade_invocations // ignore_for_file: cascade_invocations
import 'package:flame/extensions.dart'; import 'package:flame/components.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:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
@ -56,17 +56,13 @@ void main() {
}, },
); );
flameTester.test( flameTester.test('adds new children', (game) async {
'stops animating after animation completes', final component = Component();
(game) async { final dashAnimatronic = DashAnimatronic(
final dashAnimatronic = DashAnimatronic(); children: [component],
await game.ensureAdd(dashAnimatronic); );
await game.ensureAdd(dashAnimatronic);
dashAnimatronic.playing = true; expect(dashAnimatronic.children, contains(component));
game.update(4); });
expect(dashAnimatronic.playing, isFalse);
},
);
}); });
} }

@ -8,12 +8,14 @@ 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_audio/pinball_audio.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
class _TestGame extends Forge2DGame { class _TestGame extends Forge2DGame {
Future<void> pump( Future<void> pump(
FlipperMovingBehavior behavior, { FlipperMovingBehavior behavior, {
FlipperCubit? flipperBloc, FlipperCubit? flipperBloc,
PinballAudioPlayer? audioPlayer,
}) async { }) async {
final flipper = Flipper.test(side: BoardSide.left); final flipper = Flipper.test(side: BoardSide.left);
await ensureAdd(flipper); await ensureAdd(flipper);

@ -0,0 +1,79 @@
// ignore_for_file: avoid_dynamic_calls, cascade_invocations
import 'dart:async';
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_audio/pinball_audio.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
class _TestGame extends Forge2DGame {
Future<void> pump(
FlipperNoiseBehavior behavior, {
FlipperCubit? flipperBloc,
PinballAudioPlayer? audioPlayer,
}) async {
final flipper = Flipper.test(side: BoardSide.left);
await ensureAdd(
FlameProvider<PinballAudioPlayer>.value(
audioPlayer ?? _MockPinballAudioPlayer(),
children: [
flipper,
],
),
);
await flipper.ensureAdd(
FlameBlocProvider<FlipperCubit, FlipperState>.value(
value: flipperBloc ?? FlipperCubit(),
children: [behavior],
),
);
}
}
class _MockPinballAudioPlayer extends Mock implements PinballAudioPlayer {}
class _MockFlipperCubit extends Mock implements FlipperCubit {}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final flameTester = FlameTester(_TestGame.new);
group('FlipperNoiseBehavior', () {
test('can be instantiated', () {
expect(
FlipperNoiseBehavior(),
isA<FlipperNoiseBehavior>(),
);
});
flameTester.test(
'plays the flipper sound when moving up',
(game) async {
final audioPlayer = _MockPinballAudioPlayer();
final bloc = _MockFlipperCubit();
whenListen(
bloc,
Stream.fromIterable([FlipperState.movingUp]),
initialState: FlipperState.movingUp,
);
final behavior = FlipperNoiseBehavior();
await game.pump(
behavior,
flipperBloc: bloc,
audioPlayer: audioPlayer,
);
behavior.onNewState(FlipperState.movingUp);
game.update(0);
verify(() => audioPlayer.play(PinballAudio.flipper)).called(1);
},
);
});
}

@ -22,6 +22,13 @@ void main() {
], ],
); );
blocTest<SignpostCubit, SignpostState>(
'onReset emits inactive',
build: SignpostCubit.new,
act: (bloc) => bloc.onReset(),
expect: () => [SignpostState.inactive],
);
test('isFullyProgressed when on active3', () { test('isFullyProgressed when on active3', () {
final bloc = SignpostCubit(); final bloc = SignpostCubit();
expect(bloc.isFullyProgressed(), isFalse); expect(bloc.isFullyProgressed(), isFalse);

@ -1,6 +1,6 @@
// ignore_for_file: cascade_invocations // ignore_for_file: cascade_invocations
import 'package:flame/extensions.dart'; import 'package:flame/components.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:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
@ -58,19 +58,13 @@ void main() {
}, },
); );
flameTester.test( flameTester.test('adds new children', (game) async {
'stops animating after animation completes', final component = Component();
(game) async { final sparkyAnimatronic = SparkyAnimatronic(
final sparkyAnimatronic = SparkyAnimatronic(); children: [component],
await game.ensureAdd(sparkyAnimatronic); );
await game.ensureAdd(sparkyAnimatronic);
sparkyAnimatronic.playing = true; expect(sparkyAnimatronic.children, contains(component));
final animationDuration = });
game.firstChild<SparkyAnimatronic>()!.animation!.totalDuration();
game.update(animationDuration);
expect(sparkyAnimatronic.playing, isFalse);
},
);
}); });
} }

@ -0,0 +1,105 @@
// ignore_for_file: cascade_invocations
import 'package:flame/components.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_components/pinball_components.dart';
class _TestGame extends Forge2DGame {
@override
Future<void> onLoad() async {
images.prefix = '';
await images.load(Assets.images.dash.animatronic.keyName);
}
}
class _TestSpriteAnimationComponent extends SpriteAnimationComponent {}
class _MockSpriteAnimation extends Mock implements SpriteAnimation {}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final flameTester = FlameTester(_TestGame.new);
group('AnimatronicLoopingBehavior', () {
test('can be instantiated', () {
expect(
AnimatronicLoopingBehavior(animationCoolDown: 1),
isA<AnimatronicLoopingBehavior>(),
);
});
flameTester.test(
'can be added',
(game) async {
final behavior = AnimatronicLoopingBehavior(animationCoolDown: 1);
final animation = _MockSpriteAnimation();
final spriteAnimationComponent = _TestSpriteAnimationComponent()
..animation = animation;
await game.ensureAdd(spriteAnimationComponent);
await spriteAnimationComponent.add(behavior);
await game.ready();
expect(game.contains(spriteAnimationComponent), isTrue);
expect(spriteAnimationComponent.contains(behavior), isTrue);
},
);
flameTester.test(
'onTick starts playing the animation',
(game) async {
final behavior = AnimatronicLoopingBehavior(animationCoolDown: 1);
final spriteAnimationComponent = _TestSpriteAnimationComponent();
await game.ensureAdd(spriteAnimationComponent);
await spriteAnimationComponent.add(behavior);
spriteAnimationComponent.playing = false;
game.update(behavior.timer.limit);
expect(spriteAnimationComponent.playing, isTrue);
},
);
flameTester.test(
'animation onComplete resets and stops playing the animation',
(game) async {
final behavior = AnimatronicLoopingBehavior(animationCoolDown: 1);
final spriteAnimationComponent = DashAnimatronic();
await game.ensureAdd(spriteAnimationComponent);
await spriteAnimationComponent.add(behavior);
game.update(1);
expect(spriteAnimationComponent.playing, isTrue);
spriteAnimationComponent.animation!.onComplete!.call();
expect(spriteAnimationComponent.playing, isFalse);
expect(spriteAnimationComponent.animation!.currentIndex, equals(0));
},
);
flameTester.test(
'animation onComplete resets and starts the timer',
(game) async {
final behavior = AnimatronicLoopingBehavior(animationCoolDown: 1);
final spriteAnimationComponent = DashAnimatronic();
await game.ensureAdd(spriteAnimationComponent);
await spriteAnimationComponent.add(behavior);
game.update(0.5);
expect(behavior.timer.current, equals(0.5));
spriteAnimationComponent.animation!.onComplete!.call();
expect(behavior.timer.current, equals(0));
expect(behavior.timer.isRunning(), isTrue);
},
);
});
}

@ -16,10 +16,7 @@ class _TestGame extends Forge2DGame {
@override @override
Future<void> onLoad() async { Future<void> onLoad() async {
images.prefix = ''; images.prefix = '';
await images.loadAll([ await images.load(theme.Assets.images.dash.ball.keyName);
Assets.images.dash.animatronic.keyName,
theme.Assets.images.dash.ball.keyName,
]);
} }
Future<void> pump( Future<void> pump(
@ -67,10 +64,9 @@ void main() {
DashBumper.test(bloc: DashBumperCubit()), DashBumper.test(bloc: DashBumperCubit()),
DashBumper.test(bloc: DashBumperCubit()), DashBumper.test(bloc: DashBumperCubit()),
]; ];
final animatronic = DashAnimatronic();
final signpost = Signpost.test(bloc: SignpostCubit()); final signpost = Signpost.test(bloc: SignpostCubit());
await game.pump(parent, gameBloc: gameBloc); await game.pump(parent, gameBloc: gameBloc);
await parent.ensureAddAll([...bumpers, animatronic, signpost]); await parent.ensureAddAll([...bumpers, signpost]);
await parent.ensureAdd(behavior); await parent.ensureAdd(behavior);
expect(game.descendants().whereType<DashBumper>(), equals(bumpers)); expect(game.descendants().whereType<DashBumper>(), equals(bumpers));
@ -99,10 +95,9 @@ void main() {
DashBumper.test(bloc: DashBumperCubit()), DashBumper.test(bloc: DashBumperCubit()),
DashBumper.test(bloc: DashBumperCubit()), DashBumper.test(bloc: DashBumperCubit()),
]; ];
final animatronic = DashAnimatronic();
final signpost = Signpost.test(bloc: SignpostCubit()); final signpost = Signpost.test(bloc: SignpostCubit());
await game.pump(parent, gameBloc: gameBloc); await game.pump(parent, gameBloc: gameBloc);
await parent.ensureAddAll([...bumpers, animatronic, signpost]); await parent.ensureAddAll([...bumpers, signpost]);
await parent.ensureAdd(behavior); await parent.ensureAdd(behavior);
expect(game.descendants().whereType<DashBumper>(), equals(bumpers)); expect(game.descendants().whereType<DashBumper>(), equals(bumpers));
@ -133,10 +128,9 @@ void main() {
DashBumper.test(bloc: DashBumperCubit()), DashBumper.test(bloc: DashBumperCubit()),
DashBumper.test(bloc: DashBumperCubit()), DashBumper.test(bloc: DashBumperCubit()),
]; ];
final animatronic = DashAnimatronic();
final signpost = Signpost.test(bloc: SignpostCubit()); final signpost = Signpost.test(bloc: SignpostCubit());
await game.pump(parent, gameBloc: gameBloc); await game.pump(parent, gameBloc: gameBloc);
await parent.ensureAddAll([...bumpers, animatronic, signpost]); await parent.ensureAddAll([...bumpers, signpost]);
await parent.ensureAdd(behavior); await parent.ensureAdd(behavior);
expect(game.descendants().whereType<DashBumper>(), equals(bumpers)); expect(game.descendants().whereType<DashBumper>(), equals(bumpers));

@ -86,6 +86,10 @@ class _MockPlungerCubit extends Mock implements PlungerCubit {}
class _MockGoogleWordCubit extends Mock implements GoogleWordCubit {} class _MockGoogleWordCubit extends Mock implements GoogleWordCubit {}
class _MockDashBumperCubit extends Mock implements DashBumperCubit {}
class _MockSignpostCubit extends Mock implements SignpostCubit {}
class _MockFlipperCubit extends Mock implements FlipperCubit {} class _MockFlipperCubit extends Mock implements FlipperCubit {}
class _MockAppLocalizations extends Mock implements AppLocalizations { class _MockAppLocalizations extends Mock implements AppLocalizations {
@ -332,7 +336,15 @@ void main() {
(game) async { (game) async {
final audioPlayer = _MockPinballAudioPlayer(); final audioPlayer = _MockPinballAudioPlayer();
final component = GameBlocStatusListener(); final component = GameBlocStatusListener();
await game.pump([component], pinballAudioPlayer: audioPlayer); await game.pump(
[
component,
Signpost.test(
bloc: _MockSignpostCubit(),
),
],
pinballAudioPlayer: audioPlayer,
);
expect(state.status, equals(GameStatus.playing)); expect(state.status, equals(GameStatus.playing));
component.onNewState(state); component.onNewState(state);
@ -350,7 +362,15 @@ void main() {
(game) async { (game) async {
final googleWordBloc = _MockGoogleWordCubit(); final googleWordBloc = _MockGoogleWordCubit();
final component = GameBlocStatusListener(); final component = GameBlocStatusListener();
await game.pump([component], googleWordBloc: googleWordBloc); await game.pump(
[
component,
Signpost.test(
bloc: _MockSignpostCubit(),
),
],
googleWordBloc: googleWordBloc,
);
expect(state.status, equals(GameStatus.playing)); expect(state.status, equals(GameStatus.playing));
component.onNewState(state); component.onNewState(state);
@ -359,6 +379,46 @@ void main() {
}, },
); );
flameTester.test(
'resets the DashBumperCubits',
(game) async {
final dashBumper1Bloc = _MockDashBumperCubit();
final dashBumper2Bloc = _MockDashBumperCubit();
final dashBumper1 = DashBumper.test(bloc: dashBumper1Bloc);
final dashBumper2 = DashBumper.test(bloc: dashBumper2Bloc);
final component = GameBlocStatusListener();
await game.pump([
component,
dashBumper1,
dashBumper2,
Signpost.test(
bloc: _MockSignpostCubit(),
),
]);
expect(state.status, equals(GameStatus.playing));
component.onNewState(state);
verify(dashBumper1Bloc.onReset).called(1);
verify(dashBumper2Bloc.onReset).called(1);
},
);
flameTester.test(
'resets the SignpostCubit',
(game) async {
final signpostBloc = _MockSignpostCubit();
final signpost = Signpost.test(bloc: signpostBloc);
final component = GameBlocStatusListener();
await game.pump([component, signpost]);
expect(state.status, equals(GameStatus.playing));
component.onNewState(state);
verify(signpostBloc.onReset).called(1);
},
);
flameTester.test( flameTester.test(
'adds FlipperKeyControllingBehavior to Flippers', 'adds FlipperKeyControllingBehavior to Flippers',
(game) async { (game) async {
@ -372,7 +432,14 @@ void main() {
); );
final flipper = Flipper.test(side: BoardSide.left); final flipper = Flipper.test(side: BoardSide.left);
await game.pump([component, backbox, flipper]); await game.pump([
component,
backbox,
flipper,
Signpost.test(
bloc: _MockSignpostCubit(),
),
]);
await flipper.ensureAdd( await flipper.ensureAdd(
FlameBlocProvider<FlipperCubit, FlipperState>( FlameBlocProvider<FlipperCubit, FlipperState>(
create: _MockFlipperCubit.new, create: _MockFlipperCubit.new,
@ -407,7 +474,14 @@ void main() {
); );
final plunger = Plunger.test(); final plunger = Plunger.test();
await game.pump( await game.pump(
[component, backbox, plunger], [
component,
backbox,
plunger,
Signpost.test(
bloc: _MockSignpostCubit(),
),
],
platformHelper: platformHelper, platformHelper: platformHelper,
); );
await plunger.ensureAdd( await plunger.ensureAdd(
@ -446,7 +520,14 @@ void main() {
); );
final plunger = Plunger.test(); final plunger = Plunger.test();
await game.pump( await game.pump(
[component, backbox, plunger], [
component,
backbox,
plunger,
Signpost.test(
bloc: _MockSignpostCubit(),
),
],
platformHelper: platformHelper, platformHelper: platformHelper,
); );
await plunger.ensureAdd( await plunger.ensureAdd(
@ -482,7 +563,14 @@ void main() {
); );
final plunger = Plunger.test(); final plunger = Plunger.test();
await game.pump( await game.pump(
[component, backbox, plunger], [
component,
backbox,
plunger,
Signpost.test(
bloc: _MockSignpostCubit(),
),
],
platformHelper: platformHelper, platformHelper: platformHelper,
); );
await plunger.ensureAdd( await plunger.ensureAdd(

@ -17,7 +17,6 @@ class _TestGame extends Forge2DGame {
Assets.images.sparky.computer.top.keyName, Assets.images.sparky.computer.top.keyName,
Assets.images.sparky.computer.base.keyName, Assets.images.sparky.computer.base.keyName,
Assets.images.sparky.computer.glow.keyName, Assets.images.sparky.computer.glow.keyName,
Assets.images.sparky.animatronic.keyName,
Assets.images.sparky.bumper.a.lit.keyName, Assets.images.sparky.bumper.a.lit.keyName,
Assets.images.sparky.bumper.a.dimmed.keyName, Assets.images.sparky.bumper.a.dimmed.keyName,
Assets.images.sparky.bumper.b.lit.keyName, Assets.images.sparky.bumper.b.lit.keyName,
@ -58,18 +57,14 @@ void main() {
final flameTester = FlameTester(_TestGame.new); final flameTester = FlameTester(_TestGame.new);
flameTester.testGameWidget( flameTester.testGameWidget(
'adds GameBonus.sparkyTurboCharge to the game and plays animatronic ' 'adds GameBonus.sparkyTurboCharge to the game '
'when SparkyComputerState.withBall is emitted', 'when SparkyComputerState.withBall is emitted',
setUp: (game, tester) async { setUp: (game, tester) async {
final behavior = SparkyComputerBonusBehavior(); final behavior = SparkyComputerBonusBehavior();
final parent = SparkyScorch.test(); final parent = SparkyScorch.test();
final sparkyComputer = SparkyComputer(); final sparkyComputer = SparkyComputer();
final animatronic = SparkyAnimatronic();
await parent.addAll([ await parent.add(sparkyComputer);
sparkyComputer,
animatronic,
]);
await game.pump(parent, gameBloc: gameBloc); await game.pump(parent, gameBloc: gameBloc);
await parent.ensureAdd(behavior); await parent.ensureAdd(behavior);
@ -79,7 +74,6 @@ void main() {
verify( verify(
() => gameBloc.add(const BonusActivated(GameBonus.sparkyTurboCharge)), () => gameBloc.add(const BonusActivated(GameBonus.sparkyTurboCharge)),
).called(1); ).called(1);
expect(animatronic.playing, isTrue);
}, },
); );
}); });

Loading…
Cancel
Save