feat: tested plunger behaviors

pull/434/head
alestiago 3 years ago
parent 552bf040c4
commit 73e9dc5fbc

@ -1,5 +1,4 @@
import 'package:flame/components.dart';
import 'package:flame_bloc/flame_bloc.dart';
import 'package:pinball_components/pinball_components.dart' hide Assets;
/// {@template launcher}
@ -13,10 +12,7 @@ class Launcher extends Component {
children: [
LaunchRamp(),
Flapper(),
FlameBlocProvider<PlungerCubit, PlungerState>(
create: PlungerCubit.new,
children: [Plunger()..initialPosition = Vector2(41, 43.7)],
),
Plunger()..initialPosition = Vector2(41, 43.7),
RocketSpriteComponent()..position = Vector2(42.8, 62.3),
],
);

@ -9,19 +9,11 @@ import 'package:pinball_flame/pinball_flame.dart';
/// It is attached when the plunger is released.
class PlungerNoiseBehavior extends Component
with FlameBlocListenable<PlungerCubit, PlungerState> {
late final PinballAudioPlayer _audioPlayer;
@override
void onNewState(PlungerState state) {
super.onNewState(state);
if (state.isReleasing) {
_audioPlayer.play(PinballAudio.launcher);
}
readProvider<PinballAudioPlayer>().play(PinballAudio.launcher);
}
@override
Future<void> onLoad() async {
await super.onLoad();
_audioPlayer = readProvider<PinballAudioPlayer>();
}
}

@ -2,20 +2,27 @@ import 'package:flame/components.dart';
import 'package:flame_bloc/flame_bloc.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
class PlungerPullingBehavior extends Component
with ParentIsA<Plunger>, FlameBlocReader<PlungerCubit, PlungerState> {
with FlameBlocReader<PlungerCubit, PlungerState> {
PlungerPullingBehavior({
required double strength,
}) : _strength = strength;
final double _strength;
late final Plunger _plunger;
@override
Future<void> onLoad() async {
await super.onLoad();
_plunger = parent!.parent! as Plunger;
}
@override
void update(double dt) {
if (bloc.state.isPulling) {
parent.body.linearVelocity = Vector2(0, _strength);
_plunger.body.linearVelocity = Vector2(0, _strength.abs());
}
}
}
@ -29,7 +36,7 @@ class PlungerAutoPullingBehavior extends PlungerPullingBehavior {
void update(double dt) {
super.update(dt);
final joint = parent.body.joints.whereType<PrismaticJoint>().single;
final joint = _plunger.body.joints.whereType<PrismaticJoint>().single;
final reachedBottom = joint.getJointTranslation() <= joint.getLowerLimit();
if (reachedBottom) {
bloc.released();

@ -1,23 +1,30 @@
import 'package:flame/components.dart';
import 'package:flame_bloc/flame_bloc.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
class PlungerReleasingBehavior extends Component
with ParentIsA<Plunger>, FlameBlocListenable<PlungerCubit, PlungerState> {
with FlameBlocListenable<PlungerCubit, PlungerState> {
PlungerReleasingBehavior({
required double strength,
}) : _strength = strength;
final double _strength; // 11
final double _strength;
late final Plunger _plunger;
@override
Future<void> onLoad() async {
await super.onLoad();
_plunger = parent!.parent! as Plunger;
}
@override
void onNewState(PlungerState state) {
super.onNewState(state);
if (state.isReleasing) {
final velocity =
(parent.initialPosition.y - parent.body.position.y) * _strength;
parent.body.linearVelocity = Vector2(0, velocity);
final velocity = (_plunger.initialPosition.y - _plunger.body.position.y) *
_strength.abs();
_plunger.body.linearVelocity = Vector2(0, velocity);
}
}
}

@ -12,18 +12,23 @@ export 'cubit/plunger_cubit.dart';
/// [Plunger] serves as a spring, that shoots the ball on the right side of the
/// play field.
///
/// [Plunger] ignores gravity so the player controls its downward [pull].
/// [Plunger] ignores gravity so the player controls its downward movement.
/// {@endtemplate}
class Plunger extends BodyComponent with InitialPosition, Layered, ZIndex {
/// {@macro plunger}
Plunger()
: super(
renderBody: false,
children: [
FlameBlocProvider<PlungerCubit, PlungerState>(
create: PlungerCubit.new,
children: [
_PlungerSpriteAnimationGroupComponent(),
PlungerPullingBehavior(strength: 7),
PlungerReleasingBehavior(strength: 11),
],
),
PlungerJointingBehavior(compressionDistance: 9.2),
PlungerAutoPullingBehavior(strength: 7),
PlungerReleasingBehavior(strength: 11)
],
) {
zIndex = ZIndexes.plunger;

@ -1,11 +1,10 @@
import 'package:flame/input.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/ball/basic_ball_game.dart';
class PlungerGame extends BallGame with KeyboardEvents, Traceable {
class PlungerGame extends BallGame
with HasKeyboardHandlerComponents, Traceable {
static const description = '''
Shows how Plunger is rendered.
@ -13,38 +12,16 @@ class PlungerGame extends BallGame with KeyboardEvents, Traceable {
- Tap anywhere on the screen to spawn a ball into the game.
''';
static const _downKeys = [
LogicalKeyboardKey.arrowDown,
LogicalKeyboardKey.space,
];
late Plunger plunger;
@override
Future<void> onLoad() async {
await super.onLoad();
final center = screenToWorld(camera.viewport.canvasSize! / 2);
await add(
plunger = Plunger()..initialPosition = Vector2(center.x - 8.8, center.y),
);
await traceAllBodies();
}
final plunger = Plunger()
..initialPosition = Vector2(center.x - 8.8, center.y);
await add(plunger);
await plunger.add(PlungerKeyControllingBehavior());
@override
KeyEventResult onKeyEvent(
RawKeyEvent event,
Set<LogicalKeyboardKey> keysPressed,
) {
final movedPlungerDown = _downKeys.contains(event.logicalKey);
if (movedPlungerDown) {
if (event is RawKeyDownEvent) {
plunger.pull();
} else if (event is RawKeyUpEvent) {
plunger.release();
}
return KeyEventResult.handled;
}
return KeyEventResult.ignored;
await traceAllBodies();
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

@ -25,14 +25,6 @@ void main() {
expect(parent.children, contains(behavior));
});
flameTester.test('can be loaded', (game) async {
final parent = Plunger.test();
final behavior = PlungerJointingBehavior(compressionDistance: 0);
await game.ensureAdd(parent);
await parent.ensureAdd(behavior);
expect(parent.children, contains(behavior));
});
flameTester.test('creates a joint', (game) async {
final behavior = PlungerJointingBehavior(compressionDistance: 0);
final parent = Plunger.test();
@ -41,141 +33,4 @@ void main() {
expect(parent.body.joints, isNotEmpty);
});
});
// group('PlungerAnchorPrismaticJointDef', () {
// const compressionDistance = 10.0;
// late Plunger plunger;
// setUp(() {
// plunger = Plunger(
// compressionDistance: compressionDistance,
// );
// anchor = PlungerAnchor(plunger: plunger);
// });
// group('initializes with', () {
// flameTester.test(
// 'plunger body as bodyA',
// (game) async {
// await game.ensureAdd(plunger);
// await game.ensureAdd(anchor);
// final jointDef = PlungerAnchorPrismaticJointDef(
// plunger: plunger,
// anchor: anchor,
// );
// expect(jointDef.bodyA, equals(plunger.body));
// },
// );
// flameTester.test(
// 'anchor body as bodyB',
// (game) async {
// await game.ensureAdd(plunger);
// await game.ensureAdd(anchor);
// final jointDef = PlungerAnchorPrismaticJointDef(
// plunger: plunger,
// anchor: anchor,
// );
// game.world.createJoint(PrismaticJoint(jointDef));
// expect(jointDef.bodyB, equals(anchor.body));
// },
// );
// flameTester.test(
// 'limits enabled',
// (game) async {
// await game.ensureAdd(plunger);
// await game.ensureAdd(anchor);
// final jointDef = PlungerAnchorPrismaticJointDef(
// plunger: plunger,
// anchor: anchor,
// );
// game.world.createJoint(PrismaticJoint(jointDef));
// expect(jointDef.enableLimit, isTrue);
// },
// );
// flameTester.test(
// 'lower translation limit as negative infinity',
// (game) async {
// await game.ensureAdd(plunger);
// await game.ensureAdd(anchor);
// final jointDef = PlungerAnchorPrismaticJointDef(
// plunger: plunger,
// anchor: anchor,
// );
// game.world.createJoint(PrismaticJoint(jointDef));
// expect(jointDef.lowerTranslation, equals(double.negativeInfinity));
// },
// );
// flameTester.test(
// 'connected body collision enabled',
// (game) async {
// await game.ensureAdd(plunger);
// await game.ensureAdd(anchor);
// final jointDef = PlungerAnchorPrismaticJointDef(
// plunger: plunger,
// anchor: anchor,
// );
// game.world.createJoint(PrismaticJoint(jointDef));
// expect(jointDef.collideConnected, isTrue);
// },
// );
// });
// flameTester.testGameWidget(
// 'plunger cannot go below anchor',
// setUp: (game, tester) async {
// await game.ensureAdd(plunger);
// await game.ensureAdd(anchor);
// // Giving anchor a shape for the plunger to collide with.
// anchor.body.createFixtureFromShape(PolygonShape()..setAsBoxXY(2, 1));
// final jointDef = PlungerAnchorPrismaticJointDef(
// plunger: plunger,
// anchor: anchor,
// );
// game.world.createJoint(PrismaticJoint(jointDef));
// await tester.pump(const Duration(seconds: 1));
// },
// verify: (game, tester) async {
// expect(plunger.body.position.y < anchor.body.position.y, isTrue);
// },
// );
// flameTester.testGameWidget(
// 'plunger cannot excessively exceed starting position',
// setUp: (game, tester) async {
// await game.ensureAdd(plunger);
// await game.ensureAdd(anchor);
// final jointDef = PlungerAnchorPrismaticJointDef(
// plunger: plunger,
// anchor: anchor,
// );
// game.world.createJoint(PrismaticJoint(jointDef));
// plunger.body.setTransform(Vector2(0, -1), 0);
// await tester.pump(const Duration(seconds: 1));
// },
// verify: (game, tester) async {
// expect(plunger.body.position.y < 1, isTrue);
// },
// );
// });
// }
}

@ -1,3 +1,6 @@
// ignore_for_file: cascade_invocations
import 'package:flame_bloc/flame_bloc.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flame_test/flame_test.dart';
import 'package:flutter/foundation.dart';
@ -6,6 +9,22 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:pinball_components/pinball_components.dart';
class _TestGame extends Forge2DGame {
Future<void> pump(
PlungerKeyControllingBehavior child, {
PlungerCubit? plugerBloc,
}) async {
final plunger = Plunger.test();
await ensureAdd(plunger);
return plunger.ensureAdd(
FlameBlocProvider<PlungerCubit, PlungerState>.value(
value: plugerBloc ?? _MockPlungerCubit(),
children: [child],
),
);
}
}
class _MockRawKeyDownEvent extends Mock implements RawKeyDownEvent {
@override
String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
@ -20,9 +39,11 @@ class _MockRawKeyUpEvent extends Mock implements RawKeyUpEvent {
}
}
class _MockPlungerCubit extends Mock implements PlungerCubit {}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final flameTester = FlameTester(Forge2DGame.new);
final flameTester = FlameTester(_TestGame.new);
group('PlungerKeyControllingBehavior', () {
test('can be instantiated', () {
@ -33,27 +54,27 @@ void main() {
});
flameTester.test('can be loaded', (game) async {
final parent = Plunger.test();
final behavior = PlungerKeyControllingBehavior();
await game.ensureAdd(parent);
await parent.ensureAdd(behavior);
expect(parent.children, contains(behavior));
await game.pump(behavior);
expect(game.descendants(), contains(behavior));
});
group('onKeyEvent', () {
late Plunger plunger;
late PlungerCubit plungerBloc;
setUp(() {
plunger = Plunger.test();
plungerBloc = _MockPlungerCubit();
});
group('pulls when', () {
flameTester.test(
'pulls when down arrow is pressed',
'down arrow is pressed',
(game) async {
final plunger = Plunger.test();
await game.ensureAdd(plunger);
final behavior = PlungerKeyControllingBehavior();
await plunger.ensureAdd(behavior);
await game.pump(
behavior,
plugerBloc: plungerBloc,
);
final event = _MockRawKeyDownEvent();
when(() => event.logicalKey).thenReturn(
@ -62,10 +83,112 @@ void main() {
behavior.onKeyEvent(event, {});
// expect(plunger.body.linearVelocity.y, isPositive);
// expect(plunger.body.linearVelocity.x, isZero);
verify(() => plungerBloc.pulled()).called(1);
},
);
flameTester.test(
'"s" is pressed',
(game) async {
final behavior = PlungerKeyControllingBehavior();
await game.pump(
behavior,
plugerBloc: plungerBloc,
);
final event = _MockRawKeyDownEvent();
when(() => event.logicalKey).thenReturn(
LogicalKeyboardKey.keyS,
);
behavior.onKeyEvent(event, {});
verify(() => plungerBloc.pulled()).called(1);
},
);
flameTester.test(
'space is pressed',
(game) async {
final behavior = PlungerKeyControllingBehavior();
await game.pump(
behavior,
plugerBloc: plungerBloc,
);
final event = _MockRawKeyDownEvent();
when(() => event.logicalKey).thenReturn(
LogicalKeyboardKey.space,
);
behavior.onKeyEvent(event, {});
verify(() => plungerBloc.pulled()).called(1);
},
);
});
group('releases when', () {
flameTester.test(
'down arrow is released',
(game) async {
final behavior = PlungerKeyControllingBehavior();
await game.pump(
behavior,
plugerBloc: plungerBloc,
);
final event = _MockRawKeyUpEvent();
when(() => event.logicalKey).thenReturn(
LogicalKeyboardKey.arrowDown,
);
behavior.onKeyEvent(event, {});
verify(() => plungerBloc.released()).called(1);
},
);
flameTester.test(
'"s" is released',
(game) async {
final behavior = PlungerKeyControllingBehavior();
await game.pump(
behavior,
plugerBloc: plungerBloc,
);
final event = _MockRawKeyUpEvent();
when(() => event.logicalKey).thenReturn(
LogicalKeyboardKey.keyS,
);
behavior.onKeyEvent(event, {});
verify(() => plungerBloc.released()).called(1);
},
);
flameTester.test(
'space is released',
(game) async {
final behavior = PlungerKeyControllingBehavior();
await game.pump(
behavior,
plugerBloc: plungerBloc,
);
final event = _MockRawKeyUpEvent();
when(() => event.logicalKey).thenReturn(
LogicalKeyboardKey.space,
);
behavior.onKeyEvent(event, {});
verify(() => plungerBloc.released()).called(1);
},
);
});
});
});
}

@ -1,5 +1,8 @@
// ignore_for_file: cascade_invocations
import 'dart:async';
import 'package:bloc_test/bloc_test.dart';
import 'package:flame/components.dart';
import 'package:flame_bloc/flame_bloc.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
@ -14,13 +17,16 @@ class _TestGame extends Forge2DGame {
Future<void> pump(
Component child, {
PinballAudioPlayer? pinballAudioPlayer,
}) {
return ensureAdd(
PlungerCubit? plungerBloc,
}) async {
final parent = Component();
await ensureAdd(parent);
return parent.ensureAdd(
FlameProvider<PinballAudioPlayer>.value(
pinballAudioPlayer ?? _MockPinballAudioPlayer(),
children: [
FlameBlocProvider<PlungerCubit, PlungerState>.value(
value: PlungerCubit(),
value: plungerBloc ?? PlungerCubit(),
children: [child],
),
],
@ -31,6 +37,8 @@ class _TestGame extends Forge2DGame {
class _MockPinballAudioPlayer extends Mock implements PinballAudioPlayer {}
class _MockPlungerCubit extends Mock implements PlungerCubit {}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final flameTester = FlameTester(_TestGame.new);
@ -50,25 +58,34 @@ void main() {
});
flameTester.test('can be loaded', (game) async {
final parent = Component();
final behavior = PlungerNoiseBehavior();
await game.pump(parent);
await parent.ensureAdd(behavior);
expect(parent.children, contains(behavior));
await game.pump(behavior);
expect(game.descendants(), contains(behavior));
});
flameTester.test('plays the correct sound on when released', (game) async {
final parent = Component();
flameTester.test(
'plays the correct sound when released',
(game) async {
final plungerBloc = _MockPlungerCubit();
final streamController = StreamController<PlungerState>();
whenListen<PlungerState>(
plungerBloc,
streamController.stream,
initialState: PlungerState.pulling,
);
final behavior = PlungerNoiseBehavior();
await game.pump(
parent,
behavior,
pinballAudioPlayer: audioPlayer,
plungerBloc: plungerBloc,
);
await parent.ensureAdd(behavior);
behavior.onNewState(PlungerState.releasing);
streamController.add(PlungerState.releasing);
await Future<void>.delayed(Duration.zero);
verify(() => audioPlayer.play(PinballAudio.launcher)).called(1);
});
},
);
});
}

@ -1,7 +1,39 @@
// ignore_for_file: 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_components/pinball_components.dart';
class _TestGame extends Forge2DGame {
Future<void> pump(
PlungerPullingBehavior behavior, {
PlungerCubit? plugerBloc,
}) async {
final plunger = Plunger.test();
await ensureAdd(plunger);
return plunger.ensureAdd(
FlameBlocProvider<PlungerCubit, PlungerState>.value(
value: plugerBloc ?? _MockPlungerCubit(),
children: [behavior],
),
);
}
}
class _MockPlungerCubit extends Mock implements PlungerCubit {}
class _MockPrismaticJoint extends Mock implements PrismaticJoint {}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final flameTester = FlameTester(_TestGame.new);
group('PlungerPullingBehavior', () {
test('can be instantiated', () {
expect(
@ -9,6 +41,38 @@ void main() {
isA<PlungerPullingBehavior>(),
);
});
flameTester.test('can be loaded', (game) async {
final behavior = PlungerPullingBehavior(strength: 0);
await game.pump(behavior);
expect(game.descendants(), contains(behavior));
});
flameTester.test(
'applies vertical linear velocity when pulled',
(game) async {
final plungerBloc = _MockPlungerCubit();
whenListen<PlungerState>(
plungerBloc,
Stream.value(PlungerState.pulling),
initialState: PlungerState.pulling,
);
const strength = 2.0;
final behavior = PlungerPullingBehavior(
strength: strength,
);
await game.pump(
behavior,
plugerBloc: plungerBloc,
);
game.update(0);
final plunger = behavior.ancestors().whereType<Plunger>().single;
expect(plunger.body.linearVelocity.x, equals(0));
expect(plunger.body.linearVelocity.y, equals(strength));
},
);
});
group('PlungerAutoPullingBehavior', () {
@ -18,5 +82,72 @@ void main() {
isA<PlungerAutoPullingBehavior>(),
);
});
flameTester.test('can be loaded', (game) async {
final behavior = PlungerAutoPullingBehavior(strength: 0);
await game.pump(behavior);
expect(game.descendants(), contains(behavior));
});
flameTester.test(
"pulls while joint hasn't reached limit",
(game) async {
final plungerBloc = _MockPlungerCubit();
whenListen<PlungerState>(
plungerBloc,
Stream.value(PlungerState.pulling),
initialState: PlungerState.pulling,
);
const strength = 2.0;
final behavior = PlungerAutoPullingBehavior(
strength: strength,
);
await game.pump(
behavior,
plugerBloc: plungerBloc,
);
final plunger = behavior.ancestors().whereType<Plunger>().single;
final joint = _MockPrismaticJoint();
when(joint.getJointTranslation).thenReturn(2);
when(joint.getLowerLimit).thenReturn(0);
plunger.body.joints.add(joint);
game.update(0);
expect(plunger.body.linearVelocity.x, equals(0));
expect(plunger.body.linearVelocity.y, equals(strength));
},
);
flameTester.test(
'releases when joint reaches limit',
(game) async {
final plungerBloc = _MockPlungerCubit();
whenListen<PlungerState>(
plungerBloc,
Stream.value(PlungerState.pulling),
initialState: PlungerState.pulling,
);
const strength = 2.0;
final behavior = PlungerAutoPullingBehavior(
strength: strength,
);
await game.pump(
behavior,
plugerBloc: plungerBloc,
);
final plunger = behavior.ancestors().whereType<Plunger>().single;
final joint = _MockPrismaticJoint();
when(joint.getJointTranslation).thenReturn(0);
when(joint.getLowerLimit).thenReturn(0);
plunger.body.joints.add(joint);
game.update(0);
verify(plungerBloc.released).called(1);
},
);
});
}

@ -1,5 +1,72 @@
// ignore_for_file: cascade_invocations
import 'dart:async';
import 'package:bloc_test/bloc_test.dart';
import 'package:flame_bloc/flame_bloc.dart';
import 'package:flame_forge2d/forge2d_game.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';
class _TestGame extends Forge2DGame {
Future<void> pump(
PlungerReleasingBehavior behavior, {
PlungerCubit? plugerBloc,
}) async {
final plunger = Plunger.test();
await ensureAdd(plunger);
return plunger.ensureAdd(
FlameBlocProvider<PlungerCubit, PlungerState>.value(
value: plugerBloc ?? PlungerCubit(),
children: [behavior],
),
);
}
}
class _MockPlungerCubit extends Mock implements PlungerCubit {}
void main() {
group('PlungerReleasingBehavior', () {});
group('PlungerReleasingBehavior', () {
TestWidgetsFlutterBinding.ensureInitialized();
final flameTester = FlameTester(_TestGame.new);
test('can be instantiated', () {
expect(
PlungerReleasingBehavior(strength: 0),
isA<PlungerReleasingBehavior>(),
);
});
flameTester.test('can be loaded', (game) async {
final behavior = PlungerReleasingBehavior(strength: 0);
await game.pump(behavior);
expect(game.descendants(), contains(behavior));
});
flameTester.test('applies vertical linear velocity', (game) async {
final plungerBloc = _MockPlungerCubit();
final streamController = StreamController<PlungerState>();
whenListen<PlungerState>(
plungerBloc,
streamController.stream,
initialState: PlungerState.pulling,
);
final behavior = PlungerReleasingBehavior(strength: 2);
await game.pump(
behavior,
plugerBloc: plungerBloc,
);
streamController.add(PlungerState.releasing);
await Future<void>.delayed(Duration.zero);
final plunger = behavior.ancestors().whereType<Plunger>().single;
expect(plunger.body.linearVelocity.x, equals(0));
expect(plunger.body.linearVelocity.y, isNot(greaterThan(0)));
});
});
}

@ -1,5 +1,6 @@
// ignore_for_file: cascade_invocations
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';
@ -14,7 +15,6 @@ void main() {
group('Plunger', () {
test('can be instantiated', () {
expect(Plunger(), isA<Plunger>());
expect(Plunger.test(), isA<Plunger>());
});
flameTester.test(
@ -26,8 +26,10 @@ void main() {
},
);
group('renders correctly', () {
const goldenPath = '../golden/plunger/';
flameTester.testGameWidget(
'renders correctly',
'pulling',
setUp: (game, tester) async {
await game.ensureAdd(Plunger());
game.camera.followVector2(Vector2.zero());
@ -35,139 +37,67 @@ void main() {
},
verify: (game, tester) async {
final plunger = game.descendants().whereType<Plunger>().first;
plunger.pull();
game.update(1);
final bloc = plunger
.descendants()
.whereType<FlameBlocProvider<PlungerCubit, PlungerState>>()
.single
.bloc;
bloc.pulled();
await tester.pump();
await expectLater(
find.byGame<TestGame>(),
matchesGoldenFile('golden/plunger/pull.png'),
);
plunger.release();
game.update(1);
await tester.pump();
await expectLater(
find.byGame<TestGame>(),
matchesGoldenFile('golden/plunger/release.png'),
matchesGoldenFile('${goldenPath}pull.png'),
);
},
);
group('body', () {
test('is dynamic', () {
final body = Plunger().createBody();
expect(body.bodyType, equals(BodyType.dynamic));
});
test('ignores gravity', () {
final body = Plunger().createBody();
expect(body.gravityScale, equals(Vector2.zero()));
});
});
group('fixture', () {
test('exists', () async {
final body = Plunger().createBody();
expect(body.fixtures[0], isA<Fixture>());
});
test('has density', () {
final body = Plunger().createBody();
final fixture = body.fixtures[0];
expect(fixture.density, greaterThan(0));
});
});
group('pullFor', () {
late Plunger plunger;
setUp(() {
plunger = Plunger();
});
flameTester.testGameWidget(
'moves downwards for given period when pullFor is called',
'releasing',
setUp: (game, tester) async {
await game.ensureAdd(plunger);
await game.ensureAdd(Plunger());
game.camera.followVector2(Vector2.zero());
game.camera.zoom = 4.1;
},
verify: (game, tester) async {
plunger.pullFor(2);
game.update(0);
expect(plunger.body.linearVelocity.y, isPositive);
// Call game update at 120 FPS, so that the plunger will act as if it
// was pulled for 2 seconds.
for (var i = 0.0; i < 2; i += 1 / 120) {
game.update(1 / 20);
}
expect(plunger.body.linearVelocity.y, isZero);
},
final plunger = game.descendants().whereType<Plunger>().first;
final bloc = plunger
.descendants()
.whereType<FlameBlocProvider<PlungerCubit, PlungerState>>()
.single
.bloc;
bloc.released();
await tester.pump();
await expectLater(
find.byGame<TestGame>(),
matchesGoldenFile('${goldenPath}release.png'),
);
});
group('pull', () {
late Plunger plunger;
setUp(() {
plunger = Plunger();
});
flameTester.test(
'moves downwards when pull is called',
(game) async {
await game.ensureAdd(plunger);
plunger.pull();
expect(plunger.body.linearVelocity.y, isPositive);
expect(plunger.body.linearVelocity.x, isZero);
},
);
flameTester.test(
'moves downwards when pull is called '
'and plunger is below its starting position', (game) async {
await game.ensureAdd(plunger);
plunger.pull();
plunger.release();
plunger.pull();
expect(plunger.body.linearVelocity.y, isPositive);
expect(plunger.body.linearVelocity.x, isZero);
});
});
group('release', () {
late Plunger plunger;
// group('body', () {
// test('is dynamic', () {
// final body = Plunger.test().createBody();
// expect(body.bodyType, equals(BodyType.dynamic));
// });
setUp(() {
plunger = Plunger();
});
// test('ignores gravity', () {
// final body = Plunger().createBody();
// expect(body.gravityScale, equals(Vector2.zero()));
// });
// });
flameTester.test(
'moves upwards when release is called '
'and plunger is below its starting position', (game) async {
await game.ensureAdd(plunger);
plunger.body.setTransform(Vector2(0, 1), 0);
plunger.release();
// group('fixture', () {
// test('exists', () async {
// final body = Plunger().createBody();
// expect(body.fixtures[0], isA<Fixture>());
// });
expect(plunger.body.linearVelocity.y, isNegative);
expect(plunger.body.linearVelocity.x, isZero);
// test('has density', () {
// final body = Plunger().createBody();
// final fixture = body.fixtures[0];
// expect(fixture.density, greaterThan(0));
// });
// });
});
flameTester.test(
'does not move when release is called '
'and plunger is in its starting position',
(game) async {
await game.ensureAdd(plunger);
plunger.release();
expect(plunger.body.linearVelocity.y, isZero);
expect(plunger.body.linearVelocity.x, isZero);
},
);
});
});
}

Loading…
Cancel
Save