From 424f35a9587176950a7717d7ecc8068d5302e6c5 Mon Sep 17 00:00:00 2001 From: alestiago Date: Thu, 5 May 2022 03:36:04 +0100 Subject: [PATCH] feat: implemented Flippers behaviors --- lib/game/components/bottom_group.dart | 3 +- lib/game/components/components.dart | 1 - .../lib/src/components/components.dart | 2 +- .../flipper/behaviors/behaviors.dart | 2 + .../behaviors/flipper_jointing_behavior.dart | 103 +++++++++++++++ .../flipper_key_listening_behavior.dart | 40 ++---- .../src/components/{ => flipper}/flipper.dart | 124 ++---------------- .../stories/bottom_group/flipper_game.dart | 40 ------ .../flipper_jointing_behavior_test.dart | 1 + ...flipper_key_controlling_behavior_test.dart | 0 .../{ => flipper}/flipper_test.dart | 2 +- 11 files changed, 135 insertions(+), 183 deletions(-) create mode 100644 packages/pinball_components/lib/src/components/flipper/behaviors/behaviors.dart create mode 100644 packages/pinball_components/lib/src/components/flipper/behaviors/flipper_jointing_behavior.dart rename lib/game/components/controlled_flipper.dart => packages/pinball_components/lib/src/components/flipper/behaviors/flipper_key_listening_behavior.dart (50%) rename packages/pinball_components/lib/src/components/{ => flipper}/flipper.dart (55%) create mode 100644 packages/pinball_components/test/src/components/flipper/behaviors/flipper_jointing_behavior_test.dart create mode 100644 packages/pinball_components/test/src/components/flipper/behaviors/flipper_key_controlling_behavior_test.dart rename packages/pinball_components/test/src/components/{ => flipper}/flipper_test.dart (99%) diff --git a/lib/game/components/bottom_group.dart b/lib/game/components/bottom_group.dart index d7856e48..86f81691 100644 --- a/lib/game/components/bottom_group.dart +++ b/lib/game/components/bottom_group.dart @@ -1,6 +1,5 @@ import 'package:flame/components.dart'; import 'package:pinball/game/behaviors/behaviors.dart'; -import 'package:pinball/game/game.dart'; import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_flame/pinball_flame.dart'; @@ -41,7 +40,7 @@ class _BottomGroupSide extends Component { final direction = _side.direction; final centerXAdjustment = _side.isLeft ? 0 : -6.66; - final flipper = ControlledFlipper( + final flipper = Flipper( side: _side, )..initialPosition = Vector2((11.8 * direction) + centerXAdjustment, 43.6); final baseboard = Baseboard(side: _side) diff --git a/lib/game/components/components.dart b/lib/game/components/components.dart index 2b132656..80b7ca8d 100644 --- a/lib/game/components/components.dart +++ b/lib/game/components/components.dart @@ -3,7 +3,6 @@ export 'backbox/backbox.dart'; export 'bottom_group.dart'; export 'camera_controller.dart'; export 'controlled_ball.dart'; -export 'controlled_flipper.dart'; export 'controlled_plunger.dart'; export 'dino_desert/dino_desert.dart'; export 'drain.dart'; diff --git a/packages/pinball_components/lib/src/components/components.dart b/packages/pinball_components/lib/src/components/components.dart index 5eef3538..a5621c85 100644 --- a/packages/pinball_components/lib/src/components/components.dart +++ b/packages/pinball_components/lib/src/components/components.dart @@ -14,7 +14,7 @@ export 'dash_nest_bumper/dash_nest_bumper.dart'; export 'dino_walls.dart'; export 'fire_effect.dart'; export 'flapper/flapper.dart'; -export 'flipper.dart'; +export 'flipper/flipper.dart'; export 'google_letter/google_letter.dart'; export 'initial_position.dart'; export 'joint_anchor.dart'; diff --git a/packages/pinball_components/lib/src/components/flipper/behaviors/behaviors.dart b/packages/pinball_components/lib/src/components/flipper/behaviors/behaviors.dart new file mode 100644 index 00000000..8f3d1d55 --- /dev/null +++ b/packages/pinball_components/lib/src/components/flipper/behaviors/behaviors.dart @@ -0,0 +1,2 @@ +export 'flipper_jointing_behavior.dart'; +export 'flipper_key_listening_behavior.dart'; diff --git a/packages/pinball_components/lib/src/components/flipper/behaviors/flipper_jointing_behavior.dart b/packages/pinball_components/lib/src/components/flipper/behaviors/flipper_jointing_behavior.dart new file mode 100644 index 00000000..c0574f6c --- /dev/null +++ b/packages/pinball_components/lib/src/components/flipper/behaviors/flipper_jointing_behavior.dart @@ -0,0 +1,103 @@ +import 'package:flame/components.dart'; +import 'package:flame_forge2d/flame_forge2d.dart'; +import 'package:pinball_components/pinball_components.dart'; +import 'package:pinball_flame/pinball_flame.dart'; + +/// Joints the [Flipper] to allow pivoting around one end. +class FlipperJointingBehavior extends Component + with ParentIsA, HasGameRef { + late final RevoluteJoint _joint; + + @override + Future onLoad() async { + await super.onLoad(); + + final anchor = _FlipperAnchor(flipper: parent); + await add(anchor); + + final jointDef = _FlipperAnchorRevoluteJointDef( + flipper: parent, + anchor: anchor, + ); + _joint = _FlipperJoint(jointDef); + parent.world.createJoint(_joint); + } + + @override + void onMount() { + gameRef.ready().whenComplete( + () => parent.body.joints.whereType<_FlipperJoint>().first.unlock(), + ); + } +} + +/// {@template flipper_anchor} +/// [JointAnchor] positioned at the end of a [Flipper]. +/// +/// The end of a [Flipper] depends on its [Flipper.side]. +/// {@endtemplate} +class _FlipperAnchor extends JointAnchor { + /// {@macro flipper_anchor} + _FlipperAnchor({ + required Flipper flipper, + }) { + initialPosition = Vector2( + (Flipper.size.x * flipper.side.direction) / 2 - + (1.65 * flipper.side.direction), + -0.15, + ); + } +} + +/// {@template flipper_anchor_revolute_joint_def} +/// Hinges one end of [Flipper] to a [_FlipperAnchor] to achieve a potivoting +/// motion. +/// {@endtemplate} +class _FlipperAnchorRevoluteJointDef extends RevoluteJointDef { + /// {@macro flipper_anchor_revolute_joint_def} + _FlipperAnchorRevoluteJointDef({ + required Flipper flipper, + required _FlipperAnchor anchor, + }) : side = flipper.side { + enableLimit = true; + initialize( + flipper.body, + anchor.body, + flipper.body.position + anchor.body.position, + ); + } + + final BoardSide side; +} + +/// {@template flipper_joint} +/// [RevoluteJoint] that controls the pivoting motion of a [Flipper]. +/// {@endtemplate} +class _FlipperJoint extends RevoluteJoint { + /// {@macro flipper_joint} + _FlipperJoint(_FlipperAnchorRevoluteJointDef def) + : side = def.side, + super(def) { + lock(); + } + + /// Half the angle of the arc motion. + static const _halfSweepingAngle = 0.611; + + final BoardSide side; + + /// Locks the [Flipper] to its resting position. + /// + /// The joint is locked when initialized in order to force the [Flipper] + /// at its resting position. + void lock() { + final angle = _halfSweepingAngle * side.direction; + setLimits(angle, angle); + } + + /// Unlocks the [Flipper] from its resting position. + void unlock() { + const angle = _halfSweepingAngle; + setLimits(-angle, angle); + } +} diff --git a/lib/game/components/controlled_flipper.dart b/packages/pinball_components/lib/src/components/flipper/behaviors/flipper_key_listening_behavior.dart similarity index 50% rename from lib/game/components/controlled_flipper.dart rename to packages/pinball_components/lib/src/components/flipper/behaviors/flipper_key_listening_behavior.dart index 3c82e719..e171b371 100644 --- a/lib/game/components/controlled_flipper.dart +++ b/packages/pinball_components/lib/src/components/flipper/behaviors/flipper_key_listening_behavior.dart @@ -1,49 +1,33 @@ import 'package:flame/components.dart'; -import 'package:flame_bloc/flame_bloc.dart'; import 'package:flutter/services.dart'; -import 'package:pinball/game/game.dart'; import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_flame/pinball_flame.dart'; -/// {@template controlled_flipper} -/// A [Flipper] with a [FlipperController] attached. -/// {@endtemplate} -class ControlledFlipper extends Flipper with Controls { - /// {@macro controlled_flipper} - ControlledFlipper({ - required BoardSide side, - }) : super(side: side) { - controller = FlipperController(this); - } -} - -/// {@template flipper_controller} -/// A [ComponentController] that controls a [Flipper]s movement. -/// {@endtemplate} -class FlipperController extends ComponentController - with KeyboardHandler, BlocComponent { - /// {@macro flipper_controller} - FlipperController(Flipper flipper) - : _keys = flipper.side.flipperKeys, - super(flipper); - +/// Allows controlling the [Flipper]'s movement with keyboard input. +class FlipperKeyListeningBehavior extends Component + with KeyboardHandler, ParentIsA { /// The [LogicalKeyboardKey]s that will control the [Flipper]. /// /// [onKeyEvent] method listens to when one of these keys is pressed. - final List _keys; + late final List _keys; + + @override + Future onLoad() async { + await super.onLoad(); + _keys = parent.side.flipperKeys; + } @override bool onKeyEvent( RawKeyEvent event, Set keysPressed, ) { - if (state?.isGameOver ?? false) return true; if (!_keys.contains(event.logicalKey)) return true; if (event is RawKeyDownEvent) { - component.moveUp(); + parent.moveUp(); } else if (event is RawKeyUpEvent) { - component.moveDown(); + parent.moveDown(); } return false; diff --git a/packages/pinball_components/lib/src/components/flipper.dart b/packages/pinball_components/lib/src/components/flipper/flipper.dart similarity index 55% rename from packages/pinball_components/lib/src/components/flipper.dart rename to packages/pinball_components/lib/src/components/flipper/flipper.dart index b62d2390..36455d15 100644 --- a/packages/pinball_components/lib/src/components/flipper.dart +++ b/packages/pinball_components/lib/src/components/flipper/flipper.dart @@ -4,6 +4,8 @@ import 'package:flame/components.dart'; import 'package:flame_forge2d/flame_forge2d.dart'; import 'package:pinball_components/pinball_components.dart'; +export 'behaviors/behaviors.dart'; + /// {@template flipper} /// A bat, typically found in pairs at the bottom of the board. /// @@ -15,7 +17,11 @@ class Flipper extends BodyComponent with KeyboardHandler, InitialPosition { required this.side, }) : super( renderBody: false, - children: [_FlipperSpriteComponent(side: side)], + children: [ + _FlipperSpriteComponent(side: side), + FlipperJointingBehavior(), + FlipperKeyListeningBehavior(), + ], ); /// The size of the [Flipper]. @@ -44,19 +50,6 @@ class Flipper extends BodyComponent with KeyboardHandler, InitialPosition { body.linearVelocity = Vector2(0, -_speed); } - /// Anchors the [Flipper] to the [RevoluteJoint] that controls its arc motion. - Future _anchorToJoint() async { - final anchor = _FlipperAnchor(flipper: this); - await add(anchor); - - final jointDef = _FlipperAnchorRevoluteJointDef( - flipper: this, - anchor: anchor, - ); - final joint = _FlipperJoint(jointDef); - world.createJoint(joint); - } - List _createFixtureDefs() { final direction = side.direction; @@ -73,7 +66,6 @@ class Flipper extends BodyComponent with KeyboardHandler, InitialPosition { assetShadow, 0, ); - final bigCircleFixtureDef = FixtureDef(bigCircleShape); final smallCircleShape = CircleShape()..radius = size.y * 0.23; smallCircleShape.position.setValues( @@ -82,7 +74,6 @@ class Flipper extends BodyComponent with KeyboardHandler, InitialPosition { assetShadow, 0, ); - final smallCircleFixtureDef = FixtureDef(smallCircleShape); final trapeziumVertices = side.isLeft ? [ @@ -98,26 +89,18 @@ class Flipper extends BodyComponent with KeyboardHandler, InitialPosition { Vector2(smallCircleShape.position.x, -smallCircleShape.radius), ]; final trapezium = PolygonShape()..set(trapeziumVertices); - final trapeziumFixtureDef = FixtureDef( - trapezium, - density: 50, // TODO(alestiago): Use a proper density. - friction: .1, // TODO(alestiago): Use a proper friction. - ); return [ - bigCircleFixtureDef, - smallCircleFixtureDef, - trapeziumFixtureDef, + FixtureDef(bigCircleShape), + FixtureDef(smallCircleShape), + FixtureDef( + trapezium, + density: 50, // TODO(alestiago): Use a proper density. + friction: .1, // TODO(alestiago): Use a proper friction. + ), ]; } - @override - Future onLoad() async { - await super.onLoad(); - - await _anchorToJoint(); - } - @override Body createBody() { final bodyDef = BodyDef( @@ -131,15 +114,6 @@ class Flipper extends BodyComponent with KeyboardHandler, InitialPosition { return body; } - - @override - void onMount() { - super.onMount(); - - gameRef.ready().whenComplete( - () => body.joints.whereType<_FlipperJoint>().first.unlock(), - ); - } } class _FlipperSpriteComponent extends SpriteComponent with HasGameRef { @@ -163,73 +137,3 @@ class _FlipperSpriteComponent extends SpriteComponent with HasGameRef { size = sprite.originalSize / 10; } } - -/// {@template flipper_anchor} -/// [JointAnchor] positioned at the end of a [Flipper]. -/// -/// The end of a [Flipper] depends on its [Flipper.side]. -/// {@endtemplate} -class _FlipperAnchor extends JointAnchor { - /// {@macro flipper_anchor} - _FlipperAnchor({ - required Flipper flipper, - }) { - initialPosition = Vector2( - (Flipper.size.x * flipper.side.direction) / 2 - - (1.65 * flipper.side.direction), - -0.15, - ); - } -} - -/// {@template flipper_anchor_revolute_joint_def} -/// Hinges one end of [Flipper] to a [_FlipperAnchor] to achieve an arc motion. -/// {@endtemplate} -class _FlipperAnchorRevoluteJointDef extends RevoluteJointDef { - /// {@macro flipper_anchor_revolute_joint_def} - _FlipperAnchorRevoluteJointDef({ - required Flipper flipper, - required _FlipperAnchor anchor, - }) : side = flipper.side { - enableLimit = true; - initialize( - flipper.body, - anchor.body, - flipper.body.position + anchor.body.position, - ); - } - - final BoardSide side; -} - -/// {@template flipper_joint} -/// [RevoluteJoint] that controls the arc motion of a [Flipper]. -/// {@endtemplate} -class _FlipperJoint extends RevoluteJoint { - /// {@macro flipper_joint} - _FlipperJoint(_FlipperAnchorRevoluteJointDef def) - : side = def.side, - super(def) { - lock(); - } - - /// Half the angle of the arc motion. - static const _halfSweepingAngle = 0.611; - - final BoardSide side; - - /// Locks the [Flipper] to its resting position. - /// - /// The joint is locked when initialized in order to force the [Flipper] - /// at its resting position. - void lock() { - final angle = _halfSweepingAngle * side.direction; - setLimits(angle, angle); - } - - /// Unlocks the [Flipper] from its resting position. - void unlock() { - const angle = _halfSweepingAngle; - setLimits(-angle, angle); - } -} diff --git a/packages/pinball_components/sandbox/lib/stories/bottom_group/flipper_game.dart b/packages/pinball_components/sandbox/lib/stories/bottom_group/flipper_game.dart index 789fa8b4..bdb23141 100644 --- a/packages/pinball_components/sandbox/lib/stories/bottom_group/flipper_game.dart +++ b/packages/pinball_components/sandbox/lib/stories/bottom_group/flipper_game.dart @@ -1,6 +1,4 @@ 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/stories/ball/basic_ball_game.dart'; @@ -23,16 +21,6 @@ class FlipperGame extends BallGame with KeyboardEvents { - Press right arrow key or "D" to move the right flipper. '''; - static const _leftFlipperKeys = [ - LogicalKeyboardKey.arrowLeft, - LogicalKeyboardKey.keyA, - ]; - - static const _rightFlipperKeys = [ - LogicalKeyboardKey.arrowRight, - LogicalKeyboardKey.keyD, - ]; - late Flipper leftFlipper; late Flipper rightFlipper; @@ -50,32 +38,4 @@ class FlipperGame extends BallGame with KeyboardEvents { await traceAllBodies(); } - - @override - KeyEventResult onKeyEvent( - RawKeyEvent event, - Set keysPressed, - ) { - final movedLeftFlipper = _leftFlipperKeys.contains(event.logicalKey); - if (movedLeftFlipper) { - if (event is RawKeyDownEvent) { - leftFlipper.moveUp(); - } else if (event is RawKeyUpEvent) { - leftFlipper.moveDown(); - } - } - - final movedRightFlipper = _rightFlipperKeys.contains(event.logicalKey); - if (movedRightFlipper) { - if (event is RawKeyDownEvent) { - rightFlipper.moveUp(); - } else if (event is RawKeyUpEvent) { - rightFlipper.moveDown(); - } - } - - return movedLeftFlipper || movedRightFlipper - ? KeyEventResult.handled - : KeyEventResult.ignored; - } } diff --git a/packages/pinball_components/test/src/components/flipper/behaviors/flipper_jointing_behavior_test.dart b/packages/pinball_components/test/src/components/flipper/behaviors/flipper_jointing_behavior_test.dart new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/packages/pinball_components/test/src/components/flipper/behaviors/flipper_jointing_behavior_test.dart @@ -0,0 +1 @@ + diff --git a/packages/pinball_components/test/src/components/flipper/behaviors/flipper_key_controlling_behavior_test.dart b/packages/pinball_components/test/src/components/flipper/behaviors/flipper_key_controlling_behavior_test.dart new file mode 100644 index 00000000..e69de29b diff --git a/packages/pinball_components/test/src/components/flipper_test.dart b/packages/pinball_components/test/src/components/flipper/flipper_test.dart similarity index 99% rename from packages/pinball_components/test/src/components/flipper_test.dart rename to packages/pinball_components/test/src/components/flipper/flipper_test.dart index 314b1f77..fae3dea4 100644 --- a/packages/pinball_components/test/src/components/flipper_test.dart +++ b/packages/pinball_components/test/src/components/flipper/flipper_test.dart @@ -6,7 +6,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_theme/pinball_theme.dart' as theme; -import '../../helpers/helpers.dart'; +import '../../../helpers/helpers.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized();