feat: including black and white Flipper assets (#102)

* feat: included left and right flipper assets

* feat: loaded left and right flipper assets

* feat: moved Flipper to components and defined controller

* refactor: moved lock to FlipperJoint

* refactor(sandbox): rephrased description

* feat(sanbox): including Flipper example

* feat: included Tracing story

* feat: defined trace method

* feat(sandbox): included right flipper

* feat: sized Flipper to match asset

* refactor: moved tests

* feat: tested flipper_controller

* feat: adjusted flipper size

* feat(sandbox): removed TapDetector

* refactor: removed unused import

* fix: increased test coverage

* docs: improved doc comments

* fix: changing merge imports

* refactor: simplified loading asset logic

Co-authored-by: Allison Ryan <77211884+allisonryan0002@users.noreply.github.com>

* chore: removed old Flipper asset

* fix: used correct variable

* feat: enchanced tracing example

* refactor: renamed circleAssetShadow to assetShadow

Co-authored-by: Allison Ryan <77211884+allisonryan0002@users.noreply.github.com>
pull/108/head
Alejandro Santiago 4 years ago committed by GitHub
parent c4012b1c65
commit 72b8213f74
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

@ -1,7 +1,6 @@
import 'dart:math' as math; import 'dart:math' as math;
import 'package:flame_forge2d/flame_forge2d.dart'; import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
/// {@template baseboard} /// {@template baseboard}

@ -1,5 +1,6 @@
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:pinball/game/game.dart'; import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart';
/// {@template board} /// {@template board}
/// The main flat surface of the [PinballGame]. /// The main flat surface of the [PinballGame].
@ -95,12 +96,15 @@ class _BottomGroupSide extends Component {
final flipper = Flipper( final flipper = Flipper(
side: _side, side: _side,
)..initialPosition = _position; )..initialPosition = _position;
await flipper.add(FlipperController(flipper));
final baseboard = Baseboard(side: _side) final baseboard = Baseboard(side: _side)
..initialPosition = _position + ..initialPosition = _position +
Vector2( Vector2(
(Baseboard.size.x / 1.6 * direction), (Baseboard.size.x / 1.6 * direction),
Baseboard.size.y - 2, Baseboard.size.y - 2,
); );
final kicker = Kicker( final kicker = Kicker(
side: _side, side: _side,
)..initialPosition = _position + )..initialPosition = _position +

@ -4,7 +4,6 @@ import 'dart:math' as math;
import 'package:flame/components.dart'; import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart' hide Timer; import 'package:flame_forge2d/flame_forge2d.dart' hide Timer;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
/// {@template chrome_dino} /// {@template chrome_dino}

@ -1,13 +1,11 @@
export 'ball.dart'; export 'ball.dart';
export 'baseboard.dart'; export 'baseboard.dart';
export 'board.dart'; export 'board.dart';
export 'board_side.dart';
export 'bonus_word.dart'; export 'bonus_word.dart';
export 'chrome_dino.dart'; export 'chrome_dino.dart';
export 'flipper.dart'; export 'flipper_controller.dart';
export 'flutter_forest.dart'; export 'flutter_forest.dart';
export 'jetpack_ramp.dart'; export 'jetpack_ramp.dart';
export 'joint_anchor.dart';
export 'kicker.dart'; export 'kicker.dart';
export 'launcher_ramp.dart'; export 'launcher_ramp.dart';
export 'plunger.dart'; export 'plunger.dart';

@ -0,0 +1,52 @@
import 'package:flame/components.dart';
import 'package:flutter/services.dart';
import 'package:pinball_components/pinball_components.dart';
/// {@template flipper_controller}
/// A [Component] that controls the [Flipper]s movement.
/// {@endtemplate}
class FlipperController extends Component with KeyboardHandler {
/// {@macro flipper_controller}
FlipperController(this.flipper) : _keys = flipper.side.flipperKeys;
/// The [Flipper] this controller is controlling.
final Flipper flipper;
/// The [LogicalKeyboardKey]s that will control the [Flipper].
///
/// [onKeyEvent] method listens to when one of these keys is pressed.
final List<LogicalKeyboardKey> _keys;
@override
bool onKeyEvent(
RawKeyEvent event,
Set<LogicalKeyboardKey> keysPressed,
) {
if (!_keys.contains(event.logicalKey)) return true;
if (event is RawKeyDownEvent) {
flipper.moveUp();
} else if (event is RawKeyUpEvent) {
flipper.moveDown();
}
return false;
}
}
extension on BoardSide {
List<LogicalKeyboardKey> get flipperKeys {
switch (this) {
case BoardSide.left:
return [
LogicalKeyboardKey.arrowLeft,
LogicalKeyboardKey.keyA,
];
case BoardSide.right:
return [
LogicalKeyboardKey.arrowRight,
LogicalKeyboardKey.keyD,
];
}
}
}

@ -4,7 +4,6 @@ import 'package:flame/extensions.dart';
import 'package:flame_forge2d/flame_forge2d.dart'; import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:geometry/geometry.dart' as geometry show centroid; import 'package:geometry/geometry.dart' as geometry show centroid;
import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
/// {@template kicker} /// {@template kicker}

@ -8,7 +8,8 @@ extension PinballGameAssetsX on PinballGame {
Future<void> preLoadAssets() async { Future<void> preLoadAssets() async {
await Future.wait([ await Future.wait([
images.load(components.Assets.images.ball.keyName), images.load(components.Assets.images.ball.keyName),
images.load(Assets.images.components.flipper.path), images.load(components.Assets.images.flipper.left.keyName),
images.load(components.Assets.images.flipper.right.keyName),
images.load(Assets.images.components.background.path), images.load(Assets.images.components.background.path),
images.load(Assets.images.components.spaceship.androidTop.path), images.load(Assets.images.components.spaceship.androidTop.path),
images.load(Assets.images.components.spaceship.androidBottom.path), images.load(Assets.images.components.spaceship.androidBottom.path),

@ -21,10 +21,6 @@ class $AssetsImagesComponentsGen {
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/flipper.png
AssetGenImage get flipper =>
const AssetGenImage('assets/images/components/flipper.png');
$AssetsImagesComponentsSpaceshipGen get spaceship => $AssetsImagesComponentsSpaceshipGen get spaceship =>
const $AssetsImagesComponentsSpaceshipGen(); const $AssetsImagesComponentsSpaceshipGen();
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

@ -3,12 +3,29 @@
/// FlutterGen /// FlutterGen
/// ***************************************************** /// *****************************************************
// ignore_for_file: directives_ordering,unnecessary_import
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
class $AssetsImagesGen { class $AssetsImagesGen {
const $AssetsImagesGen(); const $AssetsImagesGen();
/// File path: assets/images/ball.png
AssetGenImage get ball => const AssetGenImage('assets/images/ball.png'); AssetGenImage get ball => const AssetGenImage('assets/images/ball.png');
$AssetsImagesFlipperGen get flipper => const $AssetsImagesFlipperGen();
}
class $AssetsImagesFlipperGen {
const $AssetsImagesFlipperGen();
/// File path: assets/images/flipper/left.png
AssetGenImage get left =>
const AssetGenImage('assets/images/flipper/left.png');
/// File path: assets/images/flipper/right.png
AssetGenImage get right =>
const AssetGenImage('assets/images/flipper/right.png');
} }
class Assets { class Assets {

@ -6,7 +6,7 @@ import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:pinball_components/pinball_components.dart'; import 'package:pinball_components/pinball_components.dart';
/// {@template ball} /// {@template ball}
/// A solid, [BodyType.dynamic] sphere that rolls and bounces around /// A solid, [BodyType.dynamic] sphere that rolls and bounces around.
/// {@endtemplate} /// {@endtemplate}
class Ball<T extends Forge2DGame> extends BodyComponent<T> class Ball<T extends Forge2DGame> extends BodyComponent<T>
with Layered, InitialPosition { with Layered, InitialPosition {
@ -90,7 +90,7 @@ class Ball<T extends Forge2DGame> extends BodyComponent<T>
} }
} }
/// Applies a boost on this [Ball] /// Applies a boost on this [Ball].
void boost(Vector2 impulse) { void boost(Vector2 impulse) {
body.applyLinearImpulse(impulse); body.applyLinearImpulse(impulse);
_boostTimer = _boostDuration; _boostTimer = _boostDuration;

@ -1,4 +1,8 @@
import 'package:pinball/game/game.dart'; // ignore_for_file: comment_references
// TODO(alestiago): Revisit ignore lint rule once Kicker is moved to this
// package.
import 'package:pinball_components/pinball_components.dart';
/// Indicates a side of the board. /// Indicates a side of the board.
/// ///

@ -1,5 +1,8 @@
export 'ball.dart'; export 'ball.dart';
export 'board_side.dart';
export 'fire_effect.dart'; export 'fire_effect.dart';
export 'flipper.dart';
export 'initial_position.dart'; export 'initial_position.dart';
export 'joint_anchor.dart';
export 'layer.dart'; export 'layer.dart';
export 'shapes/shapes.dart'; export 'shapes/shapes.dart';

@ -3,20 +3,7 @@ import 'dart:math' as math;
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/game/game.dart';
import 'package:pinball/gen/assets.gen.dart';
import 'package:pinball_components/pinball_components.dart' hide Assets;
const _leftFlipperKeys = [
LogicalKeyboardKey.arrowLeft,
LogicalKeyboardKey.keyA,
];
const _rightFlipperKeys = [
LogicalKeyboardKey.arrowRight,
LogicalKeyboardKey.keyD,
];
/// {@template flipper} /// {@template flipper}
/// A bat, typically found in pairs at the bottom of the board. /// A bat, typically found in pairs at the bottom of the board.
@ -27,10 +14,10 @@ class Flipper extends BodyComponent with KeyboardHandler, InitialPosition {
/// {@macro flipper} /// {@macro flipper}
Flipper({ Flipper({
required this.side, required this.side,
}) : _keys = side.isLeft ? _leftFlipperKeys : _rightFlipperKeys; });
/// The size of the [Flipper]. /// The size of the [Flipper].
static final size = Vector2(12, 2.8); static final size = Vector2(13.5, 4.3);
/// The speed required to move the [Flipper] to its highest position. /// The speed required to move the [Flipper] to its highest position.
/// ///
@ -43,27 +30,24 @@ class Flipper extends BodyComponent with KeyboardHandler, InitialPosition {
/// whereas a [Flipper] with [BoardSide.right] has a clockwise arc motion. /// whereas a [Flipper] with [BoardSide.right] has a clockwise arc motion.
final BoardSide side; final BoardSide side;
/// The [LogicalKeyboardKey]s that will control the [Flipper].
///
/// [onKeyEvent] method listens to when one of these keys is pressed.
final List<LogicalKeyboardKey> _keys;
/// Applies downward linear velocity to the [Flipper], moving it to its /// Applies downward linear velocity to the [Flipper], moving it to its
/// resting position. /// resting position.
void _moveDown() { void moveDown() {
body.linearVelocity = Vector2(0, -_speed); body.linearVelocity = Vector2(0, -_speed);
} }
/// Applies upward linear velocity to the [Flipper], moving it to its highest /// Applies upward linear velocity to the [Flipper], moving it to its highest
/// position. /// position.
void _moveUp() { void moveUp() {
body.linearVelocity = Vector2(0, _speed); body.linearVelocity = Vector2(0, _speed);
} }
/// Loads the sprite that renders with the [Flipper]. /// Loads the sprite that renders with the [Flipper].
Future<void> _loadSprite() async { Future<void> _loadSprite() async {
final sprite = await gameRef.loadSprite( final sprite = await gameRef.loadSprite(
Assets.images.components.flipper.path, (side.isLeft)
? Assets.images.flipper.left.keyName
: Assets.images.flipper.right.keyName,
); );
final spriteComponent = SpriteComponent( final spriteComponent = SpriteComponent(
sprite: sprite, sprite: sprite,
@ -71,10 +55,6 @@ class Flipper extends BodyComponent with KeyboardHandler, InitialPosition {
anchor: Anchor.center, anchor: Anchor.center,
); );
if (side.isRight) {
spriteComponent.flipHorizontally();
}
await add(spriteComponent); await add(spriteComponent);
} }
@ -87,30 +67,36 @@ class Flipper extends BodyComponent with KeyboardHandler, InitialPosition {
flipper: this, flipper: this,
anchor: anchor, anchor: anchor,
); );
final joint = _FlipperJoint(jointDef)..create(world); final joint = _FlipperJoint(jointDef);
world.createJoint2(joint);
// FIXME(erickzanardo): when mounted the initial position is not fully unawaited(mounted.whenComplete(joint.unlock));
// reached.
unawaited(
mounted.whenComplete(joint.unlock),
);
} }
List<FixtureDef> _createFixtureDefs() { List<FixtureDef> _createFixtureDefs() {
final fixturesDef = <FixtureDef>[]; final fixturesDef = <FixtureDef>[];
final direction = side.direction; final direction = side.direction;
final bigCircleShape = CircleShape()..radius = 1.75; final assetShadow = Flipper.size.x * 0.012 * -direction;
final size = Vector2(
Flipper.size.x - (assetShadow * 2),
Flipper.size.y,
);
final bigCircleShape = CircleShape()..radius = size.y / 2 - 0.2;
bigCircleShape.position.setValues( bigCircleShape.position.setValues(
((size.x / 2) * direction) + (bigCircleShape.radius * -direction), ((size.x / 2) * direction) +
(bigCircleShape.radius * -direction) +
assetShadow,
0, 0,
); );
final bigCircleFixtureDef = FixtureDef(bigCircleShape); final bigCircleFixtureDef = FixtureDef(bigCircleShape);
fixturesDef.add(bigCircleFixtureDef); fixturesDef.add(bigCircleFixtureDef);
final smallCircleShape = CircleShape()..radius = 0.9; final smallCircleShape = CircleShape()..radius = size.y * 0.23;
smallCircleShape.position.setValues( smallCircleShape.position.setValues(
((size.x / 2) * -direction) + (smallCircleShape.radius * direction), ((size.x / 2) * -direction) +
(smallCircleShape.radius * direction) -
assetShadow,
0, 0,
); );
final smallCircleFixtureDef = FixtureDef(smallCircleShape); final smallCircleFixtureDef = FixtureDef(smallCircleShape);
@ -143,7 +129,7 @@ class Flipper extends BodyComponent with KeyboardHandler, InitialPosition {
await super.onLoad(); await super.onLoad();
renderBody = false; renderBody = false;
await Future.wait([ await Future.wait<void>([
_loadSprite(), _loadSprite(),
_anchorToJoint(), _anchorToJoint(),
]); ]);
@ -160,22 +146,6 @@ class Flipper extends BodyComponent with KeyboardHandler, InitialPosition {
return body; return body;
} }
@override
bool onKeyEvent(
RawKeyEvent event,
Set<LogicalKeyboardKey> keysPressed,
) {
if (!_keys.contains(event.logicalKey)) return true;
if (event is RawKeyDownEvent) {
_moveUp();
} else if (event is RawKeyUpEvent) {
_moveDown();
}
return false;
}
} }
/// {@template flipper_anchor} /// {@template flipper_anchor}
@ -204,45 +174,60 @@ class _FlipperAnchorRevoluteJointDef extends RevoluteJointDef {
required Flipper flipper, required Flipper flipper,
required _FlipperAnchor anchor, required _FlipperAnchor anchor,
}) : side = flipper.side { }) : side = flipper.side {
enableLimit = true;
initialize( initialize(
flipper.body, flipper.body,
anchor.body, anchor.body,
anchor.body.position, anchor.body.position,
); );
enableLimit = true;
final angle = (_sweepingAngle * -side.direction) / 2;
lowerAngle = upperAngle = angle;
} }
/// The total angle of the arc motion.
static const _sweepingAngle = math.pi / 3.5;
final BoardSide side; final BoardSide side;
} }
/// {@template flipper_joint}
/// [RevoluteJoint] that controls the arc motion of a [Flipper].
/// {@endtemplate}
class _FlipperJoint extends RevoluteJoint { class _FlipperJoint extends RevoluteJoint {
/// {@macro flipper_joint}
_FlipperJoint(_FlipperAnchorRevoluteJointDef def) _FlipperJoint(_FlipperAnchorRevoluteJointDef def)
: side = def.side, : side = def.side,
super(def); super(def) {
lock();
}
/// The total angle of the arc motion.
static const _sweepingAngle = math.pi / 3.5;
final BoardSide side; final BoardSide side;
// TODO(alestiago): Remove once Forge2D supports custom joints. /// Locks the [Flipper] to its resting position.
void create(World world) { ///
world.joints.add(this); /// The joint is locked when initialized in order to force the [Flipper]
bodyA.joints.add(this); /// at its resting position.
bodyB.joints.add(this); void lock() {
const angle = _sweepingAngle / 2;
setLimits(
-angle * side.direction,
-angle * side.direction,
);
} }
/// Unlocks the [Flipper] from its resting position. /// Unlocks the [Flipper] from its resting position.
///
/// The [Flipper] is locked when initialized in order to force it to be at
/// its resting position.
void unlock() { void unlock() {
setLimits( const angle = _sweepingAngle / 2;
lowerLimit * side.direction, setLimits(-angle, angle);
-upperLimit * side.direction, }
); }
// TODO(alestiago): Remove once Forge2D supports custom joints.
extension on World {
void createJoint2(Joint joint) {
assert(!isLocked, '');
joints.add(joint);
joint.bodyA.joints.add(joint);
joint.bodyB.joints.add(joint);
} }
} }

@ -26,6 +26,7 @@ flutter:
generate: true generate: true
assets: assets:
- assets/images/ - assets/images/
- assets/images/flipper/
flutter_gen: flutter_gen:
line_length: 80 line_length: 80

@ -15,5 +15,6 @@ void main() {
addBallStories(dashbook); addBallStories(dashbook);
addLayerStories(dashbook); addLayerStories(dashbook);
addEffectsStories(dashbook); addEffectsStories(dashbook);
addFlipperStories(dashbook);
runApp(dashbook); runApp(dashbook);
} }

@ -7,8 +7,9 @@ class BasicBallGame extends BasicGame with TapDetector {
BasicBallGame({required this.color}); BasicBallGame({required this.color});
static const info = ''' static const info = '''
Basic example of how a Ball works, tap anywhere on the Basic example of how a Ball works.
screen to spawn a ball into the game.
Tap anywhere on the screen to spawn a ball into the game.
'''; ''';
final Color color; final Color color;

@ -0,0 +1,26 @@
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/common/common.dart';
class BasicFlipperGame extends BasicGame {
static const info = '''
Basic example of how a Flipper works.
''';
@override
Future<void> onLoad() async {
await super.onLoad();
final center = screenToWorld(camera.viewport.canvasSize! / 2);
final leftFlipper = Flipper(side: BoardSide.left)
..initialPosition = center - Vector2(Flipper.size.x, 0);
final rightFlipper = Flipper(side: BoardSide.right)
..initialPosition = center + Vector2(Flipper.size.x, 0);
await addAll([
leftFlipper,
rightFlipper,
]);
}
}

@ -0,0 +1,25 @@
import 'package:dashbook/dashbook.dart';
import 'package:flame/game.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/flipper/basic.dart';
import 'package:sandbox/stories/flipper/tracing.dart';
void addFlipperStories(Dashbook dashbook) {
dashbook.storiesOf('Flipper')
..add(
'Basic',
(context) => GameWidget(
game: BasicFlipperGame(),
),
codeLink: buildSourceLink('flipper/basic.dart'),
info: BasicFlipperGame.info,
)
..add(
'Tracing',
(context) => GameWidget(
game: FlipperTracingGame(),
),
codeLink: buildSourceLink('flipper/tracing.dart'),
info: FlipperTracingGame.info,
);
}

@ -0,0 +1,49 @@
import 'dart:async';
import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flutter/material.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/common/common.dart';
class FlipperTracingGame extends BasicGame {
static const info = '''
Basic example of how the Flipper body overlays the sprite.
''';
@override
Future<void> onLoad() async {
await super.onLoad();
final center = screenToWorld(camera.viewport.canvasSize! / 2);
final leftFlipper = Flipper(side: BoardSide.left)
..initialPosition = center - Vector2(Flipper.size.x, 0);
final rightFlipper = Flipper(side: BoardSide.right)
..initialPosition = center + Vector2(Flipper.size.x, 0);
await addAll([
leftFlipper,
rightFlipper,
]);
leftFlipper.trace();
rightFlipper.trace();
}
}
extension on BodyComponent {
void trace({Color color = Colors.red}) {
paint = Paint()..color = color;
renderBody = true;
body.joints.whereType<RevoluteJoint>().forEach(
(joint) => joint.setLimits(0, 0),
);
body.setType(BodyType.static);
unawaited(
mounted.whenComplete(() {
final sprite = children.whereType<SpriteComponent>().first;
sprite.paint.color = sprite.paint.color.withOpacity(0.5);
}),
);
}
}

@ -8,8 +8,9 @@ class BasicLayerGame extends BasicGame with TapDetector {
BasicLayerGame({required this.color}); BasicLayerGame({required this.color});
static const info = ''' static const info = '''
Basic example of how layers work with a Ball hitting other components, Basic example of how layers work when a Ball hits other components.
tap anywhere on the screen to spawn a ball into the game.
Tap anywhere on the screen to spawn a ball into the game.
'''; ''';
final Color color; final Color color;

@ -1,2 +1,3 @@
export 'ball/ball.dart'; export 'ball/ball.dart';
export 'flipper/flipper.dart';
export 'layer/layer.dart'; export 'layer/layer.dart';

@ -1,5 +1,5 @@
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';
void main() { void main() {
group( group(

@ -0,0 +1,133 @@
// ignore_for_file: cascade_invocations
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flame_test/flame_test.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:pinball_components/pinball_components.dart';
import '../../helpers/helpers.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final flameTester = FlameTester(TestGame.new);
group('Flipper', () {
// TODO(alestiago): Add golden tests.
// TODO(alestiago): Consider testing always both left and right Flipper.
flameTester.test(
'loads correctly',
(game) async {
final leftFlipper = Flipper(side: BoardSide.left);
final rightFlipper = Flipper(side: BoardSide.right);
await game.ready();
await game.ensureAddAll([leftFlipper, rightFlipper]);
expect(game.contains(leftFlipper), isTrue);
expect(game.contains(rightFlipper), isTrue);
},
);
group('constructor', () {
test('sets BoardSide', () {
final leftFlipper = Flipper(side: BoardSide.left);
expect(leftFlipper.side, equals(leftFlipper.side));
final rightFlipper = Flipper(side: BoardSide.right);
expect(rightFlipper.side, equals(rightFlipper.side));
});
});
group('body', () {
flameTester.test(
'is dynamic',
(game) async {
final flipper = Flipper(side: BoardSide.left);
await game.ensureAdd(flipper);
expect(flipper.body.bodyType, equals(BodyType.dynamic));
},
);
flameTester.test(
'ignores gravity',
(game) async {
final flipper = Flipper(side: BoardSide.left);
await game.ensureAdd(flipper);
expect(flipper.body.gravityScale, isZero);
},
);
flameTester.test(
'has greater mass than Ball',
(game) async {
final flipper = Flipper(side: BoardSide.left);
final ball = Ball(baseColor: Colors.white);
await game.ready();
await game.ensureAddAll([flipper, ball]);
expect(
flipper.body.getMassData().mass,
greaterThan(ball.body.getMassData().mass),
);
},
);
});
group('fixtures', () {
flameTester.test(
'has three',
(game) async {
final flipper = Flipper(side: BoardSide.left);
await game.ensureAdd(flipper);
expect(flipper.body.fixtures.length, equals(3));
},
);
flameTester.test(
'has density',
(game) async {
final flipper = Flipper(side: BoardSide.left);
await game.ensureAdd(flipper);
final fixtures = flipper.body.fixtures;
final density = fixtures.fold<double>(
0,
(sum, fixture) => sum + fixture.density,
);
expect(density, greaterThan(0));
},
);
});
flameTester.test(
'moveDown applies downward velocity',
(game) async {
final flipper = Flipper(side: BoardSide.left);
await game.ensureAdd(flipper);
expect(flipper.body.linearVelocity, equals(Vector2.zero()));
flipper.moveDown();
expect(flipper.body.linearVelocity.y, lessThan(0));
},
);
flameTester.test(
'moveUp applies upward velocity',
(game) async {
final flipper = Flipper(side: BoardSide.left);
await game.ensureAdd(flipper);
expect(flipper.body.linearVelocity, equals(Vector2.zero()));
flipper.moveUp();
expect(flipper.body.linearVelocity.y, greaterThan(0));
},
);
});
}

@ -3,7 +3,7 @@
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_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:pinball/game/game.dart'; import 'package:pinball_components/pinball_components.dart';
void main() { void main() {
TestWidgetsFlutterBinding.ensureInitialized(); TestWidgetsFlutterBinding.ensureInitialized();

@ -4,6 +4,7 @@ import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flame_test/flame_test.dart'; import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:pinball/game/game.dart'; import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart';
void main() { void main() {
group('Baseboard', () { group('Baseboard', () {

@ -3,6 +3,7 @@
import 'package:flame_test/flame_test.dart'; import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:pinball/game/game.dart'; import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart';
import '../../helpers/helpers.dart'; import '../../helpers/helpers.dart';

@ -29,6 +29,7 @@ void main() {
group('listenWhen', () { group('listenWhen', () {
final previousState = MockGameState(); final previousState = MockGameState();
final currentState = MockGameState(); final currentState = MockGameState();
test( test(
'returns true when there is a new word bonus awarded', 'returns true when there is a new word bonus awarded',
() { () {

@ -0,0 +1,169 @@
import 'dart:collection';
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(PinballGameTest.create);
group('FlipperController', () {
group('onKeyEvent', () {
final leftKeys = UnmodifiableListView([
LogicalKeyboardKey.arrowLeft,
LogicalKeyboardKey.keyA,
]);
final rightKeys = UnmodifiableListView([
LogicalKeyboardKey.arrowRight,
LogicalKeyboardKey.keyD,
]);
group('and Flipper is left', () {
late Flipper flipper;
late FlipperController controller;
setUp(() {
flipper = Flipper(side: BoardSide.left);
controller = FlipperController(flipper);
flipper.add(controller);
});
testRawKeyDownEvents(leftKeys, (event) {
flameTester.test(
'moves upwards '
'when ${event.logicalKey.keyLabel} is pressed',
(game) async {
await game.ready();
await game.add(flipper);
controller.onKeyEvent(event, {});
expect(flipper.body.linearVelocity.y, isPositive);
expect(flipper.body.linearVelocity.x, isZero);
},
);
});
testRawKeyUpEvents(leftKeys, (event) {
flameTester.test(
'moves downwards '
'when ${event.logicalKey.keyLabel} is released',
(game) async {
await game.ready();
await game.add(flipper);
controller.onKeyEvent(event, {});
expect(flipper.body.linearVelocity.y, isNegative);
expect(flipper.body.linearVelocity.x, isZero);
},
);
});
testRawKeyUpEvents(rightKeys, (event) {
flameTester.test(
'does nothing '
'when ${event.logicalKey.keyLabel} is released',
(game) async {
await game.ready();
await game.add(flipper);
controller.onKeyEvent(event, {});
expect(flipper.body.linearVelocity.y, isZero);
expect(flipper.body.linearVelocity.x, isZero);
},
);
});
testRawKeyDownEvents(rightKeys, (event) {
flameTester.test(
'does nothing '
'when ${event.logicalKey.keyLabel} is pressed',
(game) async {
await game.ready();
await game.add(flipper);
controller.onKeyEvent(event, {});
expect(flipper.body.linearVelocity.y, isZero);
expect(flipper.body.linearVelocity.x, isZero);
},
);
});
});
group('and Flipper is right', () {
late Flipper flipper;
late FlipperController controller;
setUp(() {
flipper = Flipper(side: BoardSide.right);
controller = FlipperController(flipper);
flipper.add(controller);
});
testRawKeyDownEvents(rightKeys, (event) {
flameTester.test(
'moves upwards '
'when ${event.logicalKey.keyLabel} is pressed',
(game) async {
await game.ready();
await game.add(flipper);
controller.onKeyEvent(event, {});
expect(flipper.body.linearVelocity.y, isPositive);
expect(flipper.body.linearVelocity.x, isZero);
},
);
});
testRawKeyUpEvents(rightKeys, (event) {
flameTester.test(
'moves downwards '
'when ${event.logicalKey.keyLabel} is released',
(game) async {
await game.ready();
await game.add(flipper);
controller.onKeyEvent(event, {});
expect(flipper.body.linearVelocity.y, isNegative);
expect(flipper.body.linearVelocity.x, isZero);
},
);
});
testRawKeyUpEvents(leftKeys, (event) {
flameTester.test(
'does nothing '
'when ${event.logicalKey.keyLabel} is released',
(game) async {
await game.ready();
await game.add(flipper);
controller.onKeyEvent(event, {});
expect(flipper.body.linearVelocity.y, isZero);
expect(flipper.body.linearVelocity.x, isZero);
},
);
});
testRawKeyDownEvents(leftKeys, (event) {
flameTester.test(
'does nothing '
'when ${event.logicalKey.keyLabel} is pressed',
(game) async {
await game.ready();
await game.add(flipper);
controller.onKeyEvent(event, {});
expect(flipper.body.linearVelocity.y, isZero);
expect(flipper.body.linearVelocity.x, isZero);
},
);
});
});
});
});
}

@ -1,275 +0,0 @@
// ignore_for_file: cascade_invocations
import 'dart:collection';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flame_test/flame_test.dart';
import 'package:flutter/material.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(PinballGameTest.create);
group(
'Flipper',
() {
// TODO(alestiago): Add golden tests.
flameTester.test(
'loads correctly',
(game) async {
final leftFlipper = Flipper(
side: BoardSide.left,
);
final rightFlipper = Flipper(
side: BoardSide.right,
);
await game.ready();
await game.ensureAddAll([leftFlipper, rightFlipper]);
expect(game.contains(leftFlipper), isTrue);
expect(game.contains(rightFlipper), isTrue);
},
);
group('constructor', () {
test('sets BoardSide', () {
final leftFlipper = Flipper(
side: BoardSide.left,
);
expect(leftFlipper.side, equals(leftFlipper.side));
final rightFlipper = Flipper(
side: BoardSide.right,
);
expect(rightFlipper.side, equals(rightFlipper.side));
});
});
group('body', () {
flameTester.test(
'is dynamic',
(game) async {
final flipper = Flipper(
side: BoardSide.left,
);
await game.ensureAdd(flipper);
expect(flipper.body.bodyType, equals(BodyType.dynamic));
},
);
flameTester.test(
'ignores gravity',
(game) async {
final flipper = Flipper(
side: BoardSide.left,
);
await game.ensureAdd(flipper);
expect(flipper.body.gravityScale, isZero);
},
);
flameTester.test(
'has greater mass than Ball',
(game) async {
final flipper = Flipper(
side: BoardSide.left,
);
final ball = Ball(baseColor: Colors.white);
await game.ready();
await game.ensureAddAll([flipper, ball]);
expect(
flipper.body.getMassData().mass,
greaterThan(ball.body.getMassData().mass),
);
},
);
});
group('fixtures', () {
flameTester.test(
'has three',
(game) async {
final flipper = Flipper(
side: BoardSide.left,
);
await game.ensureAdd(flipper);
expect(flipper.body.fixtures.length, equals(3));
},
);
flameTester.test(
'has density',
(game) async {
final flipper = Flipper(
side: BoardSide.left,
);
await game.ensureAdd(flipper);
final fixtures = flipper.body.fixtures;
final density = fixtures.fold<double>(
0,
(sum, fixture) => sum + fixture.density,
);
expect(density, greaterThan(0));
},
);
});
group('onKeyEvent', () {
final leftKeys = UnmodifiableListView([
LogicalKeyboardKey.arrowLeft,
LogicalKeyboardKey.keyA,
]);
final rightKeys = UnmodifiableListView([
LogicalKeyboardKey.arrowRight,
LogicalKeyboardKey.keyD,
]);
group('and Flipper is left', () {
late Flipper flipper;
setUp(() {
flipper = Flipper(
side: BoardSide.left,
);
});
testRawKeyDownEvents(leftKeys, (event) {
flameTester.test(
'moves upwards '
'when ${event.logicalKey.keyLabel} is pressed',
(game) async {
await game.ensureAdd(flipper);
flipper.onKeyEvent(event, {});
expect(flipper.body.linearVelocity.y, isPositive);
expect(flipper.body.linearVelocity.x, isZero);
},
);
});
testRawKeyUpEvents(leftKeys, (event) {
flameTester.test(
'moves downwards '
'when ${event.logicalKey.keyLabel} is released',
(game) async {
await game.ensureAdd(flipper);
flipper.onKeyEvent(event, {});
expect(flipper.body.linearVelocity.y, isNegative);
expect(flipper.body.linearVelocity.x, isZero);
},
);
});
testRawKeyUpEvents(rightKeys, (event) {
flameTester.test(
'does nothing '
'when ${event.logicalKey.keyLabel} is released',
(game) async {
await game.ensureAdd(flipper);
flipper.onKeyEvent(event, {});
expect(flipper.body.linearVelocity.y, isZero);
expect(flipper.body.linearVelocity.x, isZero);
},
);
});
testRawKeyDownEvents(rightKeys, (event) {
flameTester.test(
'does nothing '
'when ${event.logicalKey.keyLabel} is pressed',
(game) async {
await game.ensureAdd(flipper);
flipper.onKeyEvent(event, {});
expect(flipper.body.linearVelocity.y, isZero);
expect(flipper.body.linearVelocity.x, isZero);
},
);
});
});
group('and Flipper is right', () {
late Flipper flipper;
setUp(() {
flipper = Flipper(
side: BoardSide.right,
);
});
testRawKeyDownEvents(rightKeys, (event) {
flameTester.test(
'moves upwards '
'when ${event.logicalKey.keyLabel} is pressed',
(game) async {
await game.ensureAdd(flipper);
flipper.onKeyEvent(event, {});
expect(flipper.body.linearVelocity.y, isPositive);
expect(flipper.body.linearVelocity.x, isZero);
},
);
});
testRawKeyUpEvents(rightKeys, (event) {
flameTester.test(
'moves downwards '
'when ${event.logicalKey.keyLabel} is released',
(game) async {
await game.ensureAdd(flipper);
flipper.onKeyEvent(event, {});
expect(flipper.body.linearVelocity.y, isNegative);
expect(flipper.body.linearVelocity.x, isZero);
},
);
});
testRawKeyUpEvents(leftKeys, (event) {
flameTester.test(
'does nothing '
'when ${event.logicalKey.keyLabel} is released',
(game) async {
await game.ensureAdd(flipper);
flipper.onKeyEvent(event, {});
expect(flipper.body.linearVelocity.y, isZero);
expect(flipper.body.linearVelocity.x, isZero);
},
);
});
testRawKeyDownEvents(leftKeys, (event) {
flameTester.test(
'does nothing '
'when ${event.logicalKey.keyLabel} is pressed',
(game) async {
await game.ensureAdd(flipper);
flipper.onKeyEvent(event, {});
expect(flipper.body.linearVelocity.y, isZero);
expect(flipper.body.linearVelocity.x, isZero);
},
);
});
});
});
},
);
}

@ -4,6 +4,7 @@ import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flame_test/flame_test.dart'; import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:pinball/game/game.dart'; import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart';
void main() { void main() {
group('Kicker', () { group('Kicker', () {

Loading…
Cancel
Save