mirror of https://github.com/flutter/pinball.git
parent
fdb9075738
commit
f0428d74bc
@ -0,0 +1 @@
|
||||
export 'blinking_behavior.dart';
|
@ -0,0 +1,111 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flame/components.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// {@template blinking_behavior}
|
||||
/// Looping behavior that performs an action at the end of each loop.
|
||||
/// {@endtemplate}
|
||||
class BlinkingBehavior<T> extends Component {
|
||||
/// {@macro blinking_behavior}
|
||||
BlinkingBehavior({
|
||||
required double loopDuration,
|
||||
int loops = 1,
|
||||
VoidCallback? onLoop,
|
||||
VoidCallback? onFinished,
|
||||
Stream<T>? stream,
|
||||
bool Function(T? previousState, T newState)? listenWhen,
|
||||
}) : _loopDuration = loopDuration,
|
||||
_loops = loops,
|
||||
_onLoop = onLoop,
|
||||
_onFinished = onFinished,
|
||||
_stream = stream,
|
||||
_listenWhen = listenWhen;
|
||||
|
||||
final double _loopDuration;
|
||||
final int _loops;
|
||||
final VoidCallback? _onLoop;
|
||||
final VoidCallback? _onFinished;
|
||||
final Stream<T>? _stream;
|
||||
final bool Function(T? previousState, T newState)? _listenWhen;
|
||||
|
||||
T? _previousState;
|
||||
StreamSubscription<T>? _subscription;
|
||||
|
||||
@override
|
||||
Future<void> onLoad() async {
|
||||
await super.onLoad();
|
||||
if (_stream == null && _listenWhen == null) {
|
||||
await add(
|
||||
LoopableTimerComponent(
|
||||
period: _loopDuration,
|
||||
loops: _loops,
|
||||
onLoop: _onLoop,
|
||||
onFinished: _onFinished,
|
||||
)..start(),
|
||||
);
|
||||
return;
|
||||
}
|
||||
_subscription = _stream!.listen((newState) async {
|
||||
if (_listenWhen!(_previousState, newState)) {
|
||||
await add(
|
||||
LoopableTimerComponent(
|
||||
period: _loopDuration,
|
||||
loops: _loops,
|
||||
onLoop: _onLoop,
|
||||
onFinished: _onFinished,
|
||||
)..start(),
|
||||
);
|
||||
}
|
||||
_previousState = newState;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void onRemove() {
|
||||
_subscription?.cancel();
|
||||
super.onRemove();
|
||||
}
|
||||
}
|
||||
|
||||
/// {@template loopable_timer_component}
|
||||
/// Timer that performs an action at the end of each loop.
|
||||
/// {@endtemplate}
|
||||
@visibleForTesting
|
||||
class LoopableTimerComponent extends TimerComponent {
|
||||
/// {@macro loopable_timer_component}
|
||||
LoopableTimerComponent({
|
||||
required double period,
|
||||
int loops = 1,
|
||||
VoidCallback? onLoop,
|
||||
VoidCallback? onFinished,
|
||||
}) : _periods = loops,
|
||||
_onFinished = onFinished,
|
||||
super(
|
||||
period: period,
|
||||
repeat: true,
|
||||
onTick: onLoop,
|
||||
autoStart: false,
|
||||
);
|
||||
|
||||
final int _periods;
|
||||
|
||||
final VoidCallback? _onFinished;
|
||||
|
||||
int _currentLoop = 0;
|
||||
|
||||
/// Begin the looping.
|
||||
void start() => timer.start();
|
||||
|
||||
@override
|
||||
void onTick() {
|
||||
super.onTick();
|
||||
|
||||
_currentLoop++;
|
||||
if (_currentLoop == _periods) {
|
||||
timer.stop();
|
||||
_onFinished?.call();
|
||||
shouldRemove = true;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
import 'package:flame/components.dart';
|
||||
import 'package:pinball_components/pinball_components.dart';
|
||||
import 'package:pinball_flame/pinball_flame.dart';
|
||||
|
||||
/// {@template android_bumper_blinking_behavior}
|
||||
/// Makes an [AndroidBumper] blink back to [AndroidBumperState.lit] when
|
||||
/// [AndroidBumperState.dimmed].
|
||||
/// {@endtemplate}
|
||||
class AndroidBumperBlinkingBehavior extends TimerComponent
|
||||
with ParentIsA<AndroidBumper> {
|
||||
/// {@macro android_bumper_blinking_behavior}
|
||||
AndroidBumperBlinkingBehavior() : super(period: 0.05);
|
||||
|
||||
void _onNewState(AndroidBumperState state) {
|
||||
switch (state) {
|
||||
case AndroidBumperState.lit:
|
||||
break;
|
||||
case AndroidBumperState.dimmed:
|
||||
timer
|
||||
..reset()
|
||||
..start();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> onLoad() async {
|
||||
await super.onLoad();
|
||||
timer.stop();
|
||||
parent.bloc.stream.listen(_onNewState);
|
||||
}
|
||||
|
||||
@override
|
||||
void onTick() {
|
||||
super.onTick();
|
||||
timer.stop();
|
||||
parent.bloc.onBlinked();
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
import 'package:flame/components.dart';
|
||||
import 'package:pinball_components/pinball_components.dart';
|
||||
import 'package:pinball_flame/pinball_flame.dart';
|
||||
|
||||
/// {@template kicker_blinking_behavior}
|
||||
/// Makes a [Kicker] blink back to [KickerState.lit] when [KickerState.dimmed].
|
||||
/// {@endtemplate}
|
||||
class KickerBlinkingBehavior extends TimerComponent with ParentIsA<Kicker> {
|
||||
/// {@macro kicker_blinking_behavior}
|
||||
KickerBlinkingBehavior() : super(period: 0.05);
|
||||
|
||||
void _onNewState(KickerState state) {
|
||||
switch (state) {
|
||||
case KickerState.lit:
|
||||
break;
|
||||
case KickerState.dimmed:
|
||||
timer
|
||||
..reset()
|
||||
..start();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> onLoad() async {
|
||||
await super.onLoad();
|
||||
timer.stop();
|
||||
parent.bloc.stream.listen(_onNewState);
|
||||
}
|
||||
|
||||
@override
|
||||
void onTick() {
|
||||
super.onTick();
|
||||
timer.stop();
|
||||
parent.bloc.onBlinked();
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
export 'multiball_blinking_behavior.dart';
|
@ -1,78 +0,0 @@
|
||||
import 'package:flame/components.dart';
|
||||
import 'package:pinball_components/pinball_components.dart';
|
||||
import 'package:pinball_flame/pinball_flame.dart';
|
||||
|
||||
/// {@template multiball_blinking_behavior}
|
||||
/// Makes a [Multiball] blink back to [MultiballLightState.lit] when
|
||||
/// [MultiballLightState.dimmed].
|
||||
/// {@endtemplate}
|
||||
class MultiballBlinkingBehavior extends TimerComponent
|
||||
with ParentIsA<Multiball> {
|
||||
/// {@macro multiball_blinking_behavior}
|
||||
MultiballBlinkingBehavior() : super(period: 0.1);
|
||||
|
||||
final _maxBlinks = 10;
|
||||
|
||||
int _blinksCounter = 0;
|
||||
|
||||
bool _isAnimating = false;
|
||||
|
||||
void _onNewState(MultiballState state) {
|
||||
final animationEnabled =
|
||||
state.animationState == MultiballAnimationState.blinking;
|
||||
final canBlink = _blinksCounter < _maxBlinks;
|
||||
|
||||
if (animationEnabled && canBlink) {
|
||||
_start();
|
||||
} else {
|
||||
_stop();
|
||||
}
|
||||
}
|
||||
|
||||
void _start() {
|
||||
if (!_isAnimating) {
|
||||
_isAnimating = true;
|
||||
timer
|
||||
..reset()
|
||||
..start();
|
||||
_animate();
|
||||
}
|
||||
}
|
||||
|
||||
void _animate() {
|
||||
parent.bloc.onBlink();
|
||||
_blinksCounter++;
|
||||
}
|
||||
|
||||
void _stop() {
|
||||
if (_isAnimating) {
|
||||
_isAnimating = false;
|
||||
timer.stop();
|
||||
_blinksCounter = 0;
|
||||
parent.bloc.onStop();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> onLoad() async {
|
||||
await super.onLoad();
|
||||
parent.bloc.stream.listen(_onNewState);
|
||||
}
|
||||
|
||||
@override
|
||||
void onTick() {
|
||||
super.onTick();
|
||||
if (!_isAnimating) {
|
||||
timer.stop();
|
||||
} else {
|
||||
if (_blinksCounter < _maxBlinks) {
|
||||
_animate();
|
||||
timer
|
||||
..reset()
|
||||
..start();
|
||||
} else {
|
||||
timer.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,41 +1,35 @@
|
||||
part of 'multiball_cubit.dart';
|
||||
|
||||
enum MultiballLightState {
|
||||
enum MultiballSpriteState {
|
||||
lit,
|
||||
dimmed,
|
||||
}
|
||||
|
||||
// Indicates if the blinking animation is running.
|
||||
enum MultiballAnimationState {
|
||||
idle,
|
||||
blinking,
|
||||
}
|
||||
|
||||
class MultiballState extends Equatable {
|
||||
const MultiballState({
|
||||
required this.lightState,
|
||||
required this.animationState,
|
||||
required this.spriteState,
|
||||
required this.isAnimating,
|
||||
});
|
||||
|
||||
const MultiballState.initial()
|
||||
: this(
|
||||
lightState: MultiballLightState.dimmed,
|
||||
animationState: MultiballAnimationState.idle,
|
||||
spriteState: MultiballSpriteState.dimmed,
|
||||
isAnimating: false,
|
||||
);
|
||||
|
||||
final MultiballLightState lightState;
|
||||
final MultiballAnimationState animationState;
|
||||
final MultiballSpriteState spriteState;
|
||||
final bool isAnimating;
|
||||
|
||||
MultiballState copyWith({
|
||||
MultiballLightState? lightState,
|
||||
MultiballAnimationState? animationState,
|
||||
MultiballSpriteState? lightState,
|
||||
bool? isAnimating,
|
||||
}) {
|
||||
return MultiballState(
|
||||
lightState: lightState ?? this.lightState,
|
||||
animationState: animationState ?? this.animationState,
|
||||
spriteState: lightState ?? this.spriteState,
|
||||
isAnimating: isAnimating ?? this.isAnimating,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object> get props => [lightState, animationState];
|
||||
List<Object> get props => [spriteState, isAnimating];
|
||||
}
|
||||
|
@ -1,44 +0,0 @@
|
||||
import 'package:flame/components.dart';
|
||||
import 'package:pinball_components/pinball_components.dart';
|
||||
import 'package:pinball_flame/pinball_flame.dart';
|
||||
|
||||
/// {@template skill_shot_blinking_behavior}
|
||||
/// Makes a [SkillShot] blink between [SkillShotSpriteState.lit] and
|
||||
/// [SkillShotSpriteState.dimmed] for a set amount of blinks.
|
||||
/// {@endtemplate}
|
||||
class SkillShotBlinkingBehavior extends TimerComponent
|
||||
with ParentIsA<SkillShot> {
|
||||
/// {@macro skill_shot_blinking_behavior}
|
||||
SkillShotBlinkingBehavior() : super(period: 0.15);
|
||||
|
||||
final _maxBlinks = 4;
|
||||
int _blinks = 0;
|
||||
|
||||
void _onNewState(SkillShotState state) {
|
||||
if (state.isBlinking) {
|
||||
timer
|
||||
..reset()
|
||||
..start();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> onLoad() async {
|
||||
await super.onLoad();
|
||||
timer.stop();
|
||||
parent.bloc.stream.listen(_onNewState);
|
||||
}
|
||||
|
||||
@override
|
||||
void onTick() {
|
||||
super.onTick();
|
||||
if (_blinks != _maxBlinks * 2) {
|
||||
parent.bloc.switched();
|
||||
_blinks++;
|
||||
} else {
|
||||
_blinks = 0;
|
||||
timer.stop();
|
||||
parent.bloc.onBlinkingFinished();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
import 'package:flame/components.dart';
|
||||
import 'package:pinball_components/pinball_components.dart';
|
||||
import 'package:pinball_flame/pinball_flame.dart';
|
||||
|
||||
/// {@template sparky_bumper_blinking_behavior}
|
||||
/// Makes a [SparkyBumper] blink back to [SparkyBumperState.lit] when
|
||||
/// [SparkyBumperState.dimmed].
|
||||
/// {@endtemplate}
|
||||
class SparkyBumperBlinkingBehavior extends TimerComponent
|
||||
with ParentIsA<SparkyBumper> {
|
||||
/// {@macro sparky_bumper_blinking_behavior}
|
||||
SparkyBumperBlinkingBehavior() : super(period: 0.05);
|
||||
|
||||
void _onNewState(SparkyBumperState state) {
|
||||
switch (state) {
|
||||
case SparkyBumperState.lit:
|
||||
break;
|
||||
case SparkyBumperState.dimmed:
|
||||
timer
|
||||
..reset()
|
||||
..start();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> onLoad() async {
|
||||
await super.onLoad();
|
||||
timer.stop();
|
||||
parent.bloc.stream.listen(_onNewState);
|
||||
}
|
||||
|
||||
@override
|
||||
void onTick() {
|
||||
super.onTick();
|
||||
timer.stop();
|
||||
parent.bloc.onBlinked();
|
||||
}
|
||||
}
|
@ -1,2 +1,3 @@
|
||||
export 'behaviors/behaviors.dart';
|
||||
export 'components/components.dart';
|
||||
export 'extensions/extensions.dart';
|
||||
|
@ -0,0 +1,163 @@
|
||||
// ignore_for_file: prefer_const_constructors, cascade_invocations
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flame/components.dart';
|
||||
import 'package:flame_test/flame_test.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mocktail/mocktail.dart';
|
||||
import 'package:pinball_components/pinball_components.dart';
|
||||
|
||||
import '../../helpers/helpers.dart';
|
||||
|
||||
class _MockStream extends Mock implements Stream<void> {}
|
||||
|
||||
class _MockStreamSubscription extends Mock implements StreamSubscription<void> {
|
||||
}
|
||||
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
final flameTester = FlameTester(TestGame.new);
|
||||
|
||||
group('BlinkingBehavior', () {
|
||||
flameTester.testGameWidget(
|
||||
'loops for the given loops and loopDuration '
|
||||
'and calls onLoop after each loop',
|
||||
setUp: (game, tester) async {
|
||||
const loopDuration = 0.1;
|
||||
var loopCount = 0;
|
||||
final behavior = BlinkingBehavior<void>(
|
||||
loopDuration: loopDuration,
|
||||
loops: 2,
|
||||
onLoop: () => loopCount++,
|
||||
);
|
||||
final component = Component();
|
||||
await component.add(behavior);
|
||||
await game.ensureAdd(component);
|
||||
|
||||
await tester.pump();
|
||||
game.update(loopDuration);
|
||||
|
||||
expect(loopCount, equals(1));
|
||||
|
||||
await tester.pump();
|
||||
game.update(loopDuration);
|
||||
|
||||
expect(loopCount, equals(2));
|
||||
},
|
||||
);
|
||||
|
||||
flameTester.testGameWidget(
|
||||
'calls onFinished after all loops',
|
||||
setUp: (game, tester) async {
|
||||
const loopDuration = 0.1;
|
||||
var onFinishedCalled = false;
|
||||
final behavior = BlinkingBehavior<void>(
|
||||
loopDuration: loopDuration,
|
||||
loops: 2,
|
||||
onFinished: () => onFinishedCalled = true,
|
||||
);
|
||||
final component = Component();
|
||||
await component.add(behavior);
|
||||
await game.ensureAdd(component);
|
||||
|
||||
await tester.pump();
|
||||
game.update(loopDuration);
|
||||
|
||||
await tester.pump();
|
||||
game.update(loopDuration);
|
||||
|
||||
expect(onFinishedCalled, isTrue);
|
||||
},
|
||||
);
|
||||
|
||||
flameTester.test(
|
||||
'adds a LoopableTimerComponent when stream and listenWhen '
|
||||
'are not provided',
|
||||
(game) async {
|
||||
const loopDuration = 0.1;
|
||||
final behavior = BlinkingBehavior<void>(
|
||||
loopDuration: loopDuration,
|
||||
);
|
||||
final component = Component();
|
||||
await component.add(behavior);
|
||||
await game.ensureAdd(component);
|
||||
|
||||
expect(
|
||||
behavior.firstChild<LoopableTimerComponent>(),
|
||||
isA<LoopableTimerComponent>(),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
flameTester.testGameWidget(
|
||||
'adds a LoopableTimerComponent only when the stream emits '
|
||||
'a state satisfying listenWhen',
|
||||
setUp: (game, tester) async {
|
||||
const loopDuration = 0.1;
|
||||
final streamController = StreamController<bool>();
|
||||
final behavior = BlinkingBehavior<bool>(
|
||||
loopDuration: loopDuration,
|
||||
stream: streamController.stream,
|
||||
listenWhen: (previousState, newState) => previousState != newState,
|
||||
);
|
||||
final component = Component();
|
||||
await component.add(behavior);
|
||||
await game.ensureAdd(component);
|
||||
|
||||
streamController.add(true);
|
||||
await game.ready();
|
||||
await tester.pump();
|
||||
|
||||
expect(
|
||||
behavior.firstChild<LoopableTimerComponent>(),
|
||||
isA<LoopableTimerComponent>(),
|
||||
);
|
||||
|
||||
game.update(loopDuration);
|
||||
streamController.add(true);
|
||||
await game.ready();
|
||||
await tester.pump();
|
||||
|
||||
expect(
|
||||
behavior.firstChild<LoopableTimerComponent>(),
|
||||
isNull,
|
||||
);
|
||||
|
||||
streamController.add(false);
|
||||
await game.ready();
|
||||
await tester.pump();
|
||||
|
||||
expect(
|
||||
behavior.firstChild<LoopableTimerComponent>(),
|
||||
isA<LoopableTimerComponent>(),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
flameTester.testGameWidget(
|
||||
'closes stream subscription when behavior is removed',
|
||||
setUp: (game, tester) async {
|
||||
const loopDuration = 0.1;
|
||||
final stream = _MockStream();
|
||||
final streamSubscription = _MockStreamSubscription();
|
||||
when(() => stream.listen(any())).thenReturn(streamSubscription);
|
||||
when(streamSubscription.cancel).thenAnswer((_) async {});
|
||||
final behavior = BlinkingBehavior<void>(
|
||||
loopDuration: loopDuration,
|
||||
stream: stream,
|
||||
listenWhen: (_, __) => false,
|
||||
);
|
||||
final component = Component();
|
||||
await component.add(behavior);
|
||||
await game.ensureAdd(component);
|
||||
|
||||
behavior.shouldRemove = true;
|
||||
await tester.pump();
|
||||
|
||||
expect(component.contains(behavior), isFalse);
|
||||
verify(streamSubscription.cancel).called(1);
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:bloc_test/bloc_test.dart';
|
||||
import 'package:flame_test/flame_test.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mocktail/mocktail.dart';
|
||||
import 'package:pinball_components/pinball_components.dart';
|
||||
import 'package:pinball_components/src/components/android_bumper/behaviors/behaviors.dart';
|
||||
|
||||
import '../../../../helpers/helpers.dart';
|
||||
|
||||
class _MockAndroidBumperCubit extends Mock implements AndroidBumperCubit {}
|
||||
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
final flameTester = FlameTester(TestGame.new);
|
||||
|
||||
group(
|
||||
'AndroidBumperBlinkingBehavior',
|
||||
() {
|
||||
flameTester.testGameWidget(
|
||||
'calls onBlinked after 0.05 seconds when dimmed',
|
||||
setUp: (game, tester) async {
|
||||
final behavior = AndroidBumperBlinkingBehavior();
|
||||
final bloc = _MockAndroidBumperCubit();
|
||||
final streamController = StreamController<AndroidBumperState>();
|
||||
whenListen(
|
||||
bloc,
|
||||
streamController.stream,
|
||||
initialState: AndroidBumperState.lit,
|
||||
);
|
||||
|
||||
final androidBumper = AndroidBumper.test(bloc: bloc);
|
||||
await androidBumper.add(behavior);
|
||||
await game.ensureAdd(androidBumper);
|
||||
|
||||
streamController.add(AndroidBumperState.dimmed);
|
||||
await tester.pump();
|
||||
game.update(0.05);
|
||||
|
||||
await streamController.close();
|
||||
verify(bloc.onBlinked).called(1);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:bloc_test/bloc_test.dart';
|
||||
import 'package:flame_test/flame_test.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mocktail/mocktail.dart';
|
||||
import 'package:pinball_components/pinball_components.dart';
|
||||
import 'package:pinball_components/src/components/kicker/behaviors/behaviors.dart';
|
||||
|
||||
import '../../../../helpers/helpers.dart';
|
||||
|
||||
class _MockKickerCubit extends Mock implements KickerCubit {}
|
||||
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
final flameTester = FlameTester(TestGame.new);
|
||||
|
||||
group(
|
||||
'KickerBlinkingBehavior',
|
||||
() {
|
||||
flameTester.testGameWidget(
|
||||
'calls onBlinked after 0.05 seconds when dimmed',
|
||||
setUp: (game, tester) async {
|
||||
final behavior = KickerBlinkingBehavior();
|
||||
final bloc = _MockKickerCubit();
|
||||
final streamController = StreamController<KickerState>();
|
||||
whenListen(
|
||||
bloc,
|
||||
streamController.stream,
|
||||
initialState: KickerState.lit,
|
||||
);
|
||||
|
||||
final kicker = Kicker.test(
|
||||
side: BoardSide.left,
|
||||
bloc: bloc,
|
||||
);
|
||||
await kicker.add(behavior);
|
||||
await game.ensureAdd(kicker);
|
||||
|
||||
streamController.add(KickerState.dimmed);
|
||||
await tester.pump();
|
||||
game.update(0.05);
|
||||
|
||||
await streamController.close();
|
||||
verify(bloc.onBlinked).called(1);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
@ -1,160 +0,0 @@
|
||||
// ignore_for_file: prefer_const_constructors, cascade_invocations
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:bloc_test/bloc_test.dart';
|
||||
import 'package:flame_test/flame_test.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mocktail/mocktail.dart';
|
||||
import 'package:pinball_components/pinball_components.dart';
|
||||
import 'package:pinball_components/src/components/multiball/behaviors/behaviors.dart';
|
||||
|
||||
import '../../../../helpers/helpers.dart';
|
||||
|
||||
class _MockMultiballCubit extends Mock implements MultiballCubit {}
|
||||
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
final flameTester = FlameTester(TestGame.new);
|
||||
|
||||
group(
|
||||
'MultiballBlinkingBehavior',
|
||||
() {
|
||||
flameTester.testGameWidget(
|
||||
'calls onBlink every 0.1 seconds when animation state is animated',
|
||||
setUp: (game, tester) async {
|
||||
final behavior = MultiballBlinkingBehavior();
|
||||
final bloc = _MockMultiballCubit();
|
||||
final streamController = StreamController<MultiballState>();
|
||||
whenListen(
|
||||
bloc,
|
||||
streamController.stream,
|
||||
initialState: MultiballState.initial(),
|
||||
);
|
||||
|
||||
final multiball = Multiball.test(bloc: bloc);
|
||||
await multiball.add(behavior);
|
||||
await game.ensureAdd(multiball);
|
||||
|
||||
streamController.add(
|
||||
MultiballState(
|
||||
animationState: MultiballAnimationState.blinking,
|
||||
lightState: MultiballLightState.lit,
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
game.update(0);
|
||||
|
||||
verify(bloc.onBlink).called(1);
|
||||
|
||||
await tester.pump();
|
||||
game.update(0.1);
|
||||
|
||||
await streamController.close();
|
||||
verify(bloc.onBlink).called(1);
|
||||
},
|
||||
);
|
||||
|
||||
flameTester.testGameWidget(
|
||||
'calls onStop when animation state is stopped',
|
||||
setUp: (game, tester) async {
|
||||
final behavior = MultiballBlinkingBehavior();
|
||||
final bloc = _MockMultiballCubit();
|
||||
final streamController = StreamController<MultiballState>();
|
||||
whenListen(
|
||||
bloc,
|
||||
streamController.stream,
|
||||
initialState: MultiballState.initial(),
|
||||
);
|
||||
when(bloc.onBlink).thenAnswer((_) async {});
|
||||
|
||||
final multiball = Multiball.test(bloc: bloc);
|
||||
await multiball.add(behavior);
|
||||
await game.ensureAdd(multiball);
|
||||
|
||||
streamController.add(
|
||||
MultiballState(
|
||||
animationState: MultiballAnimationState.blinking,
|
||||
lightState: MultiballLightState.lit,
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
|
||||
streamController.add(
|
||||
MultiballState(
|
||||
animationState: MultiballAnimationState.idle,
|
||||
lightState: MultiballLightState.lit,
|
||||
),
|
||||
);
|
||||
|
||||
await streamController.close();
|
||||
verify(bloc.onStop).called(1);
|
||||
},
|
||||
);
|
||||
|
||||
flameTester.testGameWidget(
|
||||
'onTick stops when there is no animation',
|
||||
setUp: (game, tester) async {
|
||||
final behavior = MultiballBlinkingBehavior();
|
||||
final bloc = _MockMultiballCubit();
|
||||
final streamController = StreamController<MultiballState>();
|
||||
whenListen(
|
||||
bloc,
|
||||
streamController.stream,
|
||||
initialState: MultiballState.initial(),
|
||||
);
|
||||
when(bloc.onBlink).thenAnswer((_) async {});
|
||||
|
||||
final multiball = Multiball.test(bloc: bloc);
|
||||
await multiball.add(behavior);
|
||||
await game.ensureAdd(multiball);
|
||||
|
||||
streamController.add(
|
||||
MultiballState(
|
||||
animationState: MultiballAnimationState.idle,
|
||||
lightState: MultiballLightState.lit,
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
|
||||
behavior.onTick();
|
||||
|
||||
expect(behavior.timer.isRunning(), false);
|
||||
},
|
||||
);
|
||||
|
||||
flameTester.testGameWidget(
|
||||
'onTick stops after 10 blinks repetitions',
|
||||
setUp: (game, tester) async {
|
||||
final behavior = MultiballBlinkingBehavior();
|
||||
final bloc = _MockMultiballCubit();
|
||||
final streamController = StreamController<MultiballState>();
|
||||
whenListen(
|
||||
bloc,
|
||||
streamController.stream,
|
||||
initialState: MultiballState.initial(),
|
||||
);
|
||||
when(bloc.onBlink).thenAnswer((_) async {});
|
||||
|
||||
final multiball = Multiball.test(bloc: bloc);
|
||||
await multiball.add(behavior);
|
||||
await game.ensureAdd(multiball);
|
||||
|
||||
streamController.add(
|
||||
MultiballState(
|
||||
animationState: MultiballAnimationState.blinking,
|
||||
lightState: MultiballLightState.dimmed,
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
|
||||
for (var i = 0; i < 10; i++) {
|
||||
behavior.onTick();
|
||||
}
|
||||
|
||||
expect(behavior.timer.isRunning(), false);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
@ -1,125 +0,0 @@
|
||||
// ignore_for_file: cascade_invocations
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:bloc_test/bloc_test.dart';
|
||||
import 'package:flame_test/flame_test.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mocktail/mocktail.dart';
|
||||
import 'package:pinball_components/pinball_components.dart';
|
||||
import 'package:pinball_components/src/components/skill_shot/behaviors/behaviors.dart';
|
||||
|
||||
import '../../../../helpers/helpers.dart';
|
||||
|
||||
class _MockSkillShotCubit extends Mock implements SkillShotCubit {}
|
||||
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
final flameTester = FlameTester(TestGame.new);
|
||||
|
||||
group(
|
||||
'SkillShotBlinkingBehavior',
|
||||
() {
|
||||
flameTester.testGameWidget(
|
||||
'calls switched after 0.15 seconds when isBlinking and lit',
|
||||
setUp: (game, tester) async {
|
||||
final behavior = SkillShotBlinkingBehavior();
|
||||
final bloc = _MockSkillShotCubit();
|
||||
final streamController = StreamController<SkillShotState>();
|
||||
whenListen(
|
||||
bloc,
|
||||
streamController.stream,
|
||||
initialState: const SkillShotState.initial(),
|
||||
);
|
||||
|
||||
final skillShot = SkillShot.test(bloc: bloc);
|
||||
await skillShot.add(behavior);
|
||||
await game.ensureAdd(skillShot);
|
||||
|
||||
streamController.add(
|
||||
const SkillShotState(
|
||||
spriteState: SkillShotSpriteState.lit,
|
||||
isBlinking: true,
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
game.update(0.15);
|
||||
|
||||
await streamController.close();
|
||||
verify(bloc.switched).called(1);
|
||||
},
|
||||
);
|
||||
|
||||
flameTester.testGameWidget(
|
||||
'calls switched after 0.15 seconds when isBlinking and dimmed',
|
||||
setUp: (game, tester) async {
|
||||
final behavior = SkillShotBlinkingBehavior();
|
||||
final bloc = _MockSkillShotCubit();
|
||||
final streamController = StreamController<SkillShotState>();
|
||||
whenListen(
|
||||
bloc,
|
||||
streamController.stream,
|
||||
initialState: const SkillShotState.initial(),
|
||||
);
|
||||
|
||||
final skillShot = SkillShot.test(bloc: bloc);
|
||||
await skillShot.add(behavior);
|
||||
await game.ensureAdd(skillShot);
|
||||
|
||||
streamController.add(
|
||||
const SkillShotState(
|
||||
spriteState: SkillShotSpriteState.dimmed,
|
||||
isBlinking: true,
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
game.update(0.15);
|
||||
|
||||
await streamController.close();
|
||||
verify(bloc.switched).called(1);
|
||||
},
|
||||
);
|
||||
|
||||
flameTester.testGameWidget(
|
||||
'calls onBlinkingFinished after all blinks complete',
|
||||
setUp: (game, tester) async {
|
||||
final behavior = SkillShotBlinkingBehavior();
|
||||
final bloc = _MockSkillShotCubit();
|
||||
final streamController = StreamController<SkillShotState>();
|
||||
whenListen(
|
||||
bloc,
|
||||
streamController.stream,
|
||||
initialState: const SkillShotState.initial(),
|
||||
);
|
||||
|
||||
final skillShot = SkillShot.test(bloc: bloc);
|
||||
await skillShot.add(behavior);
|
||||
await game.ensureAdd(skillShot);
|
||||
|
||||
for (var i = 0; i <= 8; i++) {
|
||||
if (i.isEven) {
|
||||
streamController.add(
|
||||
const SkillShotState(
|
||||
spriteState: SkillShotSpriteState.lit,
|
||||
isBlinking: true,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
streamController.add(
|
||||
const SkillShotState(
|
||||
spriteState: SkillShotSpriteState.dimmed,
|
||||
isBlinking: true,
|
||||
),
|
||||
);
|
||||
}
|
||||
await tester.pump();
|
||||
game.update(0.15);
|
||||
}
|
||||
|
||||
await streamController.close();
|
||||
verify(bloc.onBlinkingFinished).called(1);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:bloc_test/bloc_test.dart';
|
||||
import 'package:flame_test/flame_test.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mocktail/mocktail.dart';
|
||||
import 'package:pinball_components/pinball_components.dart';
|
||||
import 'package:pinball_components/src/components/sparky_bumper/behaviors/behaviors.dart';
|
||||
|
||||
import '../../../../helpers/helpers.dart';
|
||||
|
||||
class _MockSparkyBumperCubit extends Mock implements SparkyBumperCubit {}
|
||||
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
final flameTester = FlameTester(TestGame.new);
|
||||
|
||||
group(
|
||||
'SparkyBumperBlinkingBehavior',
|
||||
() {
|
||||
flameTester.testGameWidget(
|
||||
'calls onBlinked after 0.05 seconds when dimmed',
|
||||
setUp: (game, tester) async {
|
||||
final behavior = SparkyBumperBlinkingBehavior();
|
||||
final bloc = _MockSparkyBumperCubit();
|
||||
final streamController = StreamController<SparkyBumperState>();
|
||||
whenListen(
|
||||
bloc,
|
||||
streamController.stream,
|
||||
initialState: SparkyBumperState.lit,
|
||||
);
|
||||
|
||||
final sparkyBumper = SparkyBumper.test(bloc: bloc);
|
||||
await sparkyBumper.add(behavior);
|
||||
await game.ensureAdd(sparkyBumper);
|
||||
|
||||
streamController.add(SparkyBumperState.dimmed);
|
||||
await tester.pump();
|
||||
game.update(0.05);
|
||||
|
||||
await streamController.close();
|
||||
verify(bloc.onBlinked).called(1);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
Loading…
Reference in new issue