refactor: `Plunger` controls (#152)

* feat: added plunger asset and move

* feat: fixed plunger assets and position

* fix: set limits to plunger compression correctly

* chore: unused import

* fix: placed plunger correctly

* test: refactor test game

* refactor: changed spawnBall initialPosition

* chore: plunger golden test

* refactor: moved plunger to pinball_components

* feat: plunger story

* refactor: plunger assets preload

* chore: assets for plunger

* refactor: added key events to plunger game

* refactor: make pull and release public to call from outside plunger

* chore: update to retry tests

* refactor: added Traceable to Plunger sandbox story

* refactor: add Traceable

* fix: removed body from PlungerAnchor

* refactor: removed keyevents from plunger

* test: plunger tests refactored without keyevents

* refactor: removed unused keyevents

* refactor: plunger spritecomponent

* refactor: keyevents to gamecontroller

* feat: added plunger controller

* test: tests for plunger controller

* test: tested plunger controller

* fix: assets gen

* chore: removed export from barrel

* refactor: removed unnecessary keyhandler

* refactor: sprite size

* test: anchor at setup

* refactor: plunger const keys

* Update lib/game/components/controlled_plunger.dart

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

Co-authored-by: Alejandro Santiago <dev@alestiago.com>
pull/183/head
Rui Miguel Alonso 3 years ago committed by GitHub
parent 59c7c8b0ff
commit bf0596846b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -3,10 +3,10 @@ export 'bonus_word.dart';
export 'camera_controller.dart'; export 'camera_controller.dart';
export 'controlled_ball.dart'; export 'controlled_ball.dart';
export 'controlled_flipper.dart'; export 'controlled_flipper.dart';
export 'controlled_plunger.dart';
export 'controlled_sparky_computer.dart'; export 'controlled_sparky_computer.dart';
export 'flutter_forest.dart'; export 'flutter_forest.dart';
export 'game_flow_controller.dart'; export 'game_flow_controller.dart';
export 'plunger.dart';
export 'score_effect_controller.dart'; export 'score_effect_controller.dart';
export 'score_points.dart'; export 'score_points.dart';
export 'sparky_fire_zone.dart'; export 'sparky_fire_zone.dart';

@ -0,0 +1,49 @@
import 'package:flame/components.dart';
import 'package:flutter/services.dart';
import 'package:pinball/flame/flame.dart';
import 'package:pinball_components/pinball_components.dart';
/// {@template controlled_plunger}
/// A [Plunger] with a [PlungerController] attached.
/// {@endtemplate}
class ControlledPlunger extends Plunger with Controls<PlungerController> {
/// {@macro controlled_plunger}
ControlledPlunger({required double compressionDistance})
: super(compressionDistance: compressionDistance) {
controller = PlungerController(this);
}
}
/// {@template plunger_controller}
/// A [ComponentController] that controls a [Plunger]s movement.
/// {@endtemplate}
class PlungerController extends ComponentController<Plunger>
with KeyboardHandler {
/// {@macro plunger_controller}
PlungerController(Plunger plunger) : super(plunger);
/// The [LogicalKeyboardKey]s that will control the [Flipper].
///
/// [onKeyEvent] method listens to when one of these keys is pressed.
static const List<LogicalKeyboardKey> _keys = [
LogicalKeyboardKey.arrowDown,
LogicalKeyboardKey.space,
LogicalKeyboardKey.keyS,
];
@override
bool onKeyEvent(
RawKeyEvent event,
Set<LogicalKeyboardKey> keysPressed,
) {
if (!_keys.contains(event.logicalKey)) return true;
if (event is RawKeyDownEvent) {
component.pull();
} else if (event is RawKeyUpEvent) {
component.release();
}
return false;
}
}

@ -46,6 +46,7 @@ extension PinballGameAssetsX on PinballGame {
images.load(components.Assets.images.spaceship.rail.foreground.keyName), images.load(components.Assets.images.spaceship.rail.foreground.keyName),
images.load(components.Assets.images.chromeDino.mouth.keyName), images.load(components.Assets.images.chromeDino.mouth.keyName),
images.load(components.Assets.images.chromeDino.head.keyName), images.load(components.Assets.images.chromeDino.head.keyName),
images.load(components.Assets.images.plunger.plunger.keyName),
images.load(components.Assets.images.sparky.computer.base.keyName), images.load(components.Assets.images.sparky.computer.base.keyName),
images.load(components.Assets.images.sparky.computer.top.keyName), images.load(components.Assets.images.sparky.computer.top.keyName),
images.load(components.Assets.images.sparky.bumper.a.active.keyName), images.load(components.Assets.images.sparky.bumper.a.active.keyName),

@ -48,7 +48,7 @@ class PinballGame extends Forge2DGame
unawaited(addFromBlueprint(LaunchRamp())); unawaited(addFromBlueprint(LaunchRamp()));
unawaited(addFromBlueprint(ControlledSparkyComputer())); unawaited(addFromBlueprint(ControlledSparkyComputer()));
final plunger = Plunger(compressionDistance: 29) final plunger = ControlledPlunger(compressionDistance: 29)
..initialPosition = Vector2(38, -19); ..initialPosition = Vector2(38, -19);
await add(plunger); await add(plunger);

@ -3,6 +3,8 @@
/// FlutterGen /// FlutterGen
/// ***************************************************** /// *****************************************************
// ignore_for_file: directives_ordering,unnecessary_import
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
class $AssetsImagesGen { class $AssetsImagesGen {
@ -15,8 +17,11 @@ class $AssetsImagesGen {
class $AssetsImagesComponentsGen { class $AssetsImagesComponentsGen {
const $AssetsImagesComponentsGen(); const $AssetsImagesComponentsGen();
/// File path: assets/images/components/background.png
AssetGenImage get background => AssetGenImage get background =>
const AssetGenImage('assets/images/components/background.png'); const AssetGenImage('assets/images/components/background.png');
/// File path: assets/images/components/plunger.png
AssetGenImage get plunger => AssetGenImage get plunger =>
const AssetGenImage('assets/images/components/plunger.png'); const AssetGenImage('assets/images/components/plunger.png');
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

@ -33,6 +33,7 @@ class $AssetsImagesGen {
$AssetsImagesKickerGen get kicker => const $AssetsImagesKickerGen(); $AssetsImagesKickerGen get kicker => const $AssetsImagesKickerGen();
$AssetsImagesLaunchRampGen get launchRamp => $AssetsImagesLaunchRampGen get launchRamp =>
const $AssetsImagesLaunchRampGen(); const $AssetsImagesLaunchRampGen();
$AssetsImagesPlungerGen get plunger => const $AssetsImagesPlungerGen();
$AssetsImagesSlingshotGen get slingshot => const $AssetsImagesSlingshotGen(); $AssetsImagesSlingshotGen get slingshot => const $AssetsImagesSlingshotGen();
$AssetsImagesSpaceshipGen get spaceship => const $AssetsImagesSpaceshipGen(); $AssetsImagesSpaceshipGen get spaceship => const $AssetsImagesSpaceshipGen();
$AssetsImagesSparkyGen get sparky => const $AssetsImagesSparkyGen(); $AssetsImagesSparkyGen get sparky => const $AssetsImagesSparkyGen();
@ -171,6 +172,14 @@ class $AssetsImagesLaunchRampGen {
const AssetGenImage('assets/images/launch_ramp/ramp.png'); const AssetGenImage('assets/images/launch_ramp/ramp.png');
} }
class $AssetsImagesPlungerGen {
const $AssetsImagesPlungerGen();
/// File path: assets/images/plunger/plunger.png
AssetGenImage get plunger =>
const AssetGenImage('assets/images/plunger/plunger.png');
}
class $AssetsImagesSlingshotGen { class $AssetsImagesSlingshotGen {
const $AssetsImagesSlingshotGen(); const $AssetsImagesSlingshotGen();

@ -3,9 +3,14 @@
/// FlutterGen /// FlutterGen
/// ***************************************************** /// *****************************************************
// ignore_for_file: directives_ordering,unnecessary_import
class FontFamily { class FontFamily {
FontFamily._(); FontFamily._();
/// Font family: PixeloidMono
static const String pixeloidMono = 'PixeloidMono'; static const String pixeloidMono = 'PixeloidMono';
/// Font family: PixeloidSans
static const String pixeloidSans = 'PixeloidSans'; static const String pixeloidSans = 'PixeloidSans';
} }

@ -17,6 +17,7 @@ export 'joint_anchor.dart';
export 'kicker.dart'; export 'kicker.dart';
export 'launch_ramp.dart'; export 'launch_ramp.dart';
export 'layer.dart'; export 'layer.dart';
export 'plunger.dart';
export 'ramp_opening.dart'; export 'ramp_opening.dart';
export 'score_text.dart'; export 'score_text.dart';
export 'shapes/shapes.dart'; export 'shapes/shapes.dart';

@ -1,16 +1,14 @@
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:flutter/services.dart'; import 'package:pinball_components/pinball_components.dart';
import 'package:pinball/gen/assets.gen.dart';
import 'package:pinball_components/pinball_components.dart' hide Assets;
/// {@template plunger} /// {@template plunger}
/// [Plunger] serves as a spring, that shoots the ball on the right side of the /// [Plunger] serves as a spring, that shoots the ball on the right side of the
/// playfield. /// playfield.
/// ///
/// [Plunger] ignores gravity so the player controls its downward [_pull]. /// [Plunger] ignores gravity so the player controls its downward [pull].
/// {@endtemplate} /// {@endtemplate}
class Plunger extends BodyComponent with KeyboardHandler, InitialPosition { class Plunger extends BodyComponent with InitialPosition {
/// {@macro plunger} /// {@macro plunger}
Plunger({ Plunger({
required this.compressionDistance, required this.compressionDistance,
@ -43,7 +41,7 @@ class Plunger extends BodyComponent with KeyboardHandler, InitialPosition {
} }
/// Set a constant downward velocity on the [Plunger]. /// Set a constant downward velocity on the [Plunger].
void _pull() { void pull() {
body.linearVelocity = Vector2(0, -7); body.linearVelocity = Vector2(0, -7);
} }
@ -51,32 +49,11 @@ class Plunger extends BodyComponent with KeyboardHandler, InitialPosition {
/// ///
/// The velocity's magnitude depends on how far the [Plunger] has been pulled /// The velocity's magnitude depends on how far the [Plunger] has been pulled
/// from its original [initialPosition]. /// from its original [initialPosition].
void _release() { void release() {
final velocity = (initialPosition.y - body.position.y) * 5; final velocity = (initialPosition.y - body.position.y) * 5;
body.linearVelocity = Vector2(0, velocity); body.linearVelocity = Vector2(0, velocity);
} }
@override
bool onKeyEvent(
RawKeyEvent event,
Set<LogicalKeyboardKey> keysPressed,
) {
final keys = [
LogicalKeyboardKey.space,
LogicalKeyboardKey.arrowDown,
LogicalKeyboardKey.keyS,
];
if (!keys.contains(event.logicalKey)) return true;
if (event is RawKeyDownEvent) {
_pull();
} else if (event is RawKeyUpEvent) {
_release();
}
return false;
}
/// Anchors the [Plunger] to the [PrismaticJoint] that controls its vertical /// Anchors the [Plunger] to the [PrismaticJoint] that controls its vertical
/// motion. /// motion.
Future<void> _anchorToJoint() async { Future<void> _anchorToJoint() async {
@ -97,26 +74,24 @@ class Plunger extends BodyComponent with KeyboardHandler, InitialPosition {
Future<void> onLoad() async { Future<void> onLoad() async {
await super.onLoad(); await super.onLoad();
await _anchorToJoint(); await _anchorToJoint();
renderBody = false; renderBody = false;
await add(_PlungerSpriteComponent());
await _loadSprite();
} }
}
Future<void> _loadSprite() async { class _PlungerSpriteComponent extends SpriteComponent with HasGameRef {
@override
Future<void> onLoad() async {
await super.onLoad();
final sprite = await gameRef.loadSprite( final sprite = await gameRef.loadSprite(
Assets.images.components.plunger.path, Assets.images.plunger.plunger.keyName,
); );
await add( this.sprite = sprite;
SpriteComponent( size = sprite.originalSize / 10;
sprite: sprite, anchor = Anchor.center;
size: Vector2(5.5, 40), position = Vector2(2, 19);
anchor: Anchor.center, angle = -0.033;
position: Vector2(2, 19),
angle: -0.033,
),
);
} }
} }
@ -133,14 +108,6 @@ class PlungerAnchor extends JointAnchor {
-plunger.compressionDistance, -plunger.compressionDistance,
); );
} }
@override
Body createBody() {
final bodyDef = BodyDef()
..position = initialPosition
..type = BodyType.static;
return world.createBody(bodyDef);
}
} }
/// {@template plunger_anchor_prismatic_joint_def} /// {@template plunger_anchor_prismatic_joint_def}

@ -49,6 +49,7 @@ flutter:
- assets/images/spaceship/ramp/ - assets/images/spaceship/ramp/
- assets/images/chrome_dino/ - assets/images/chrome_dino/
- assets/images/kicker/ - assets/images/kicker/
- assets/images/plunger/
- assets/images/slingshot/ - assets/images/slingshot/
- assets/images/sparky/computer/ - assets/images/sparky/computer/
- assets/images/sparky/bumper/a/ - assets/images/sparky/bumper/a/

@ -21,6 +21,7 @@ void main() {
addChromeDinoStories(dashbook); addChromeDinoStories(dashbook);
addDashNestBumperStories(dashbook); addDashNestBumperStories(dashbook);
addKickerStories(dashbook); addKickerStories(dashbook);
addPlungerStories(dashbook);
addSlingshotStories(dashbook); addSlingshotStories(dashbook);
addSparkyBumperStories(dashbook); addSparkyBumperStories(dashbook);
addZoomStories(dashbook); addZoomStories(dashbook);

@ -0,0 +1,54 @@
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 BasicBallGame with KeyboardEvents, Traceable {
PlungerGame() : super(color: const Color(0xFFFF0000));
static const info = '''
Shows how Plunger is rendered.
- Activate the "trace" parameter to overlay the body.
- 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);
plunger = Plunger(compressionDistance: 29)
..initialPosition = Vector2(center.x - (Kicker.size.x * 2), center.y);
await add(plunger);
await traceAllBodies();
}
@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;
}
}

@ -0,0 +1,15 @@
import 'package:dashbook/dashbook.dart';
import 'package:flame/game.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/plunger/plunger_game.dart';
void addPlungerStories(Dashbook dashbook) {
dashbook.storiesOf('Plunger').add(
'Basic',
(context) => GameWidget(
game: PlungerGame()..trace = context.boolProperty('Trace', true),
),
codeLink: buildSourceLink('plunger_game/basic.dart'),
info: PlungerGame.info,
);
}

@ -8,6 +8,7 @@ export 'flutter_forest/stories.dart';
export 'google_word/stories.dart'; export 'google_word/stories.dart';
export 'launch_ramp/stories.dart'; export 'launch_ramp/stories.dart';
export 'layer/stories.dart'; export 'layer/stories.dart';
export 'plunger/stories.dart';
export 'score_text/stories.dart'; export 'score_text/stories.dart';
export 'slingshot/stories.dart'; export 'slingshot/stories.dart';
export 'spaceship/stories.dart'; export 'spaceship/stories.dart';

@ -1,12 +1,9 @@
// ignore_for_file: cascade_invocations // ignore_for_file: cascade_invocations
import 'dart:collection';
import 'package:flame_forge2d/flame_forge2d.dart'; import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flame_test/flame_test.dart'; import 'package:flame_test/flame_test.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:pinball/game/game.dart'; import 'package:pinball_components/pinball_components.dart';
import '../../helpers/helpers.dart'; import '../../helpers/helpers.dart';
@ -117,13 +114,23 @@ void main() {
); );
}); });
group('onKeyEvent', () { group('pull', () {
final keys = UnmodifiableListView([ flameTester.test(
LogicalKeyboardKey.space, 'moves downwards when pull is called',
LogicalKeyboardKey.arrowDown, (game) async {
LogicalKeyboardKey.keyS, final plunger = Plunger(
]); compressionDistance: compressionDistance,
);
await game.ensureAdd(plunger);
plunger.pull();
expect(plunger.body.linearVelocity.y, isNegative);
expect(plunger.body.linearVelocity.x, isZero);
},
);
});
group('release', () {
late Plunger plunger; late Plunger plunger;
setUp(() { setUp(() {
@ -132,56 +139,28 @@ void main() {
); );
}); });
testRawKeyUpEvents(keys, (event) { flameTester.test(
final keyLabel = (event.logicalKey != LogicalKeyboardKey.space) 'moves upwards when release is called '
? event.logicalKey.keyLabel 'and plunger is below its starting position', (game) async {
: 'Space'; await game.ensureAdd(plunger);
flameTester.test( plunger.body.setTransform(Vector2(0, -1), 0);
'moves upwards when $keyLabel is released ' plunger.release();
'and plunger is below its starting position',
(game) async {
await game.ensureAdd(plunger);
plunger.body.setTransform(Vector2(0, -1), 0);
plunger.onKeyEvent(event, {});
expect(plunger.body.linearVelocity.y, isPositive);
expect(plunger.body.linearVelocity.x, isZero);
},
);
});
testRawKeyUpEvents(keys, (event) { expect(plunger.body.linearVelocity.y, isPositive);
final keyLabel = (event.logicalKey != LogicalKeyboardKey.space) expect(plunger.body.linearVelocity.x, isZero);
? event.logicalKey.keyLabel
: 'Space';
flameTester.test(
'does not move when $keyLabel is released '
'and plunger is in its starting position',
(game) async {
await game.ensureAdd(plunger);
plunger.onKeyEvent(event, {});
expect(plunger.body.linearVelocity.y, isZero);
expect(plunger.body.linearVelocity.x, isZero);
},
);
}); });
testRawKeyDownEvents(keys, (event) { flameTester.test(
final keyLabel = (event.logicalKey != LogicalKeyboardKey.space) 'does not move when release is called '
? event.logicalKey.keyLabel 'and plunger is in its starting position',
: 'Space'; (game) async {
flameTester.test( await game.ensureAdd(plunger);
'moves downwards when $keyLabel is pressed', plunger.release();
(game) async {
await game.ensureAdd(plunger); expect(plunger.body.linearVelocity.y, isZero);
plunger.onKeyEvent(event, {}); expect(plunger.body.linearVelocity.x, isZero);
},
expect(plunger.body.linearVelocity.y, isNegative); );
expect(plunger.body.linearVelocity.x, isZero);
},
);
});
}); });
}); });
@ -210,11 +189,13 @@ void main() {
group('PlungerAnchorPrismaticJointDef', () { group('PlungerAnchorPrismaticJointDef', () {
const compressionDistance = 10.0; const compressionDistance = 10.0;
late Plunger plunger; late Plunger plunger;
late PlungerAnchor anchor;
setUp(() { setUp(() {
plunger = Plunger( plunger = Plunger(
compressionDistance: compressionDistance, compressionDistance: compressionDistance,
); );
anchor = PlungerAnchor(plunger: plunger);
}); });
group('initializes with', () { group('initializes with', () {
@ -222,7 +203,6 @@ void main() {
'plunger body as bodyA', 'plunger body as bodyA',
(game) async { (game) async {
await game.ensureAdd(plunger); await game.ensureAdd(plunger);
final anchor = PlungerAnchor(plunger: plunger);
await game.ensureAdd(anchor); await game.ensureAdd(anchor);
final jointDef = PlungerAnchorPrismaticJointDef( final jointDef = PlungerAnchorPrismaticJointDef(
@ -238,7 +218,6 @@ void main() {
'anchor body as bodyB', 'anchor body as bodyB',
(game) async { (game) async {
await game.ensureAdd(plunger); await game.ensureAdd(plunger);
final anchor = PlungerAnchor(plunger: plunger);
await game.ensureAdd(anchor); await game.ensureAdd(anchor);
final jointDef = PlungerAnchorPrismaticJointDef( final jointDef = PlungerAnchorPrismaticJointDef(
@ -255,7 +234,6 @@ void main() {
'limits enabled', 'limits enabled',
(game) async { (game) async {
await game.ensureAdd(plunger); await game.ensureAdd(plunger);
final anchor = PlungerAnchor(plunger: plunger);
await game.ensureAdd(anchor); await game.ensureAdd(anchor);
final jointDef = PlungerAnchorPrismaticJointDef( final jointDef = PlungerAnchorPrismaticJointDef(
@ -272,7 +250,6 @@ void main() {
'lower translation limit as negative infinity', 'lower translation limit as negative infinity',
(game) async { (game) async {
await game.ensureAdd(plunger); await game.ensureAdd(plunger);
final anchor = PlungerAnchor(plunger: plunger);
await game.ensureAdd(anchor); await game.ensureAdd(anchor);
final jointDef = PlungerAnchorPrismaticJointDef( final jointDef = PlungerAnchorPrismaticJointDef(
@ -289,7 +266,6 @@ void main() {
'connected body collison enabled', 'connected body collison enabled',
(game) async { (game) async {
await game.ensureAdd(plunger); await game.ensureAdd(plunger);
final anchor = PlungerAnchor(plunger: plunger);
await game.ensureAdd(anchor); await game.ensureAdd(anchor);
final jointDef = PlungerAnchorPrismaticJointDef( final jointDef = PlungerAnchorPrismaticJointDef(
@ -303,53 +279,47 @@ void main() {
); );
}); });
testRawKeyUpEvents([LogicalKeyboardKey.space], (event) { flameTester.testGameWidget(
late final anchor = PlungerAnchor(plunger: plunger); 'plunger cannot go below anchor',
flameTester.testGameWidget( setUp: (game, tester) async {
'plunger cannot go below anchor', await game.ensureAdd(plunger);
setUp: (game, tester) async { await game.ensureAdd(anchor);
await game.ensureAdd(plunger);
await game.ensureAdd(anchor);
// Giving anchor a shape for the plunger to collide with. // Giving anchor a shape for the plunger to collide with.
anchor.body.createFixtureFromShape(PolygonShape()..setAsBoxXY(2, 1)); anchor.body.createFixtureFromShape(PolygonShape()..setAsBoxXY(2, 1));
final jointDef = PlungerAnchorPrismaticJointDef( final jointDef = PlungerAnchorPrismaticJointDef(
plunger: plunger, plunger: plunger,
anchor: anchor, anchor: anchor,
); );
game.world.createJoint(PrismaticJoint(jointDef)); game.world.createJoint(PrismaticJoint(jointDef));
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
}, },
verify: (game, tester) async { verify: (game, tester) async {
expect(plunger.body.position.y > anchor.body.position.y, isTrue); expect(plunger.body.position.y > anchor.body.position.y, isTrue);
}, },
); );
});
testRawKeyUpEvents([LogicalKeyboardKey.space], (event) { flameTester.testGameWidget(
flameTester.testGameWidget( 'plunger cannot excessively exceed starting position',
'plunger cannot excessively exceed starting position', setUp: (game, tester) async {
setUp: (game, tester) async { await game.ensureAdd(plunger);
await game.ensureAdd(plunger); await game.ensureAdd(anchor);
final anchor = PlungerAnchor(plunger: plunger);
await game.ensureAdd(anchor);
final jointDef = PlungerAnchorPrismaticJointDef( final jointDef = PlungerAnchorPrismaticJointDef(
plunger: plunger, plunger: plunger,
anchor: anchor, anchor: anchor,
); );
game.world.createJoint(PrismaticJoint(jointDef)); game.world.createJoint(PrismaticJoint(jointDef));
plunger.body.setTransform(Vector2(0, -1), 0); plunger.body.setTransform(Vector2(0, -1), 0);
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
}, },
verify: (game, tester) async { verify: (game, tester) async {
expect(plunger.body.position.y < 1, isTrue); expect(plunger.body.position.y < 1, isTrue);
}, },
); );
});
}); });
} }

@ -0,0 +1,78 @@
import 'dart:collection';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flame_test/flame_test.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart';
import '../../helpers/helpers.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final flameTester = FlameTester(EmptyPinballGameTest.new);
group('PlungerController', () {
group('onKeyEvent', () {
final downKeys = UnmodifiableListView([
LogicalKeyboardKey.arrowDown,
LogicalKeyboardKey.space,
LogicalKeyboardKey.keyS,
]);
late Plunger plunger;
late PlungerController controller;
setUp(() {
plunger = Plunger(compressionDistance: 10);
controller = PlungerController(plunger);
plunger.add(controller);
});
testRawKeyDownEvents(downKeys, (event) {
flameTester.test(
'moves down '
'when ${event.logicalKey.keyLabel} is pressed',
(game) async {
await game.ensureAdd(plunger);
controller.onKeyEvent(event, {});
expect(plunger.body.linearVelocity.y, isNegative);
expect(plunger.body.linearVelocity.x, isZero);
},
);
});
testRawKeyUpEvents(downKeys, (event) {
flameTester.test(
'moves up '
'when ${event.logicalKey.keyLabel} is released '
'and plunger is below its starting position',
(game) async {
await game.ensureAdd(plunger);
plunger.body.setTransform(Vector2(0, -1), 0);
controller.onKeyEvent(event, {});
expect(plunger.body.linearVelocity.y, isPositive);
expect(plunger.body.linearVelocity.x, isZero);
},
);
});
testRawKeyUpEvents(downKeys, (event) {
flameTester.test(
'does not move when ${event.logicalKey.keyLabel} is released '
'and plunger is in its starting position',
(game) async {
await game.ensureAdd(plunger);
controller.onKeyEvent(event, {});
expect(plunger.body.linearVelocity.y, isZero);
expect(plunger.body.linearVelocity.x, isZero);
},
);
});
});
});
}
Loading…
Cancel
Save