Merge branch 'main' into feat/adding-sound-effects

pull/143/head
Erick 4 years ago committed by GitHub
commit 4343a58b72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,13 +1,8 @@
export 'board.dart';
export 'bonus_word.dart';
export 'chrome_dino.dart';
export 'controlled_ball.dart';
export 'flipper_controller.dart';
export 'controlled_flipper.dart';
export 'flutter_forest.dart';
export 'jetpack_ramp.dart';
export 'kicker.dart';
export 'launcher_ramp.dart';
export 'plunger.dart';
export 'score_points.dart';
export 'spaceship_exit_rail.dart';
export 'wall.dart';

@ -88,7 +88,7 @@ class LaunchedBallController extends BallController
void onNewState(GameState state) {
super.onNewState(state);
component.shouldRemove = true;
if (state.balls > 1) gameRef.spawnBall();
if (state.balls > 0) gameRef.spawnBall();
}
/// Removes the [Ball] from a [PinballGame]; spawning a new [Ball] if

@ -68,7 +68,7 @@ class _FlutterForestController extends ComponentController<FlutterForest>
void onNewState(GameState state) {
super.onNewState(state);
component.add(
gameRef.add(
ControlledBall.bonus(theme: gameRef.theme)
..initialPosition = Vector2(17.2, 52.7),
);

@ -1,127 +0,0 @@
// ignore_for_file: public_member_api_docs, avoid_renaming_method_parameters
import 'dart:math' as math;
import 'package:flame/extensions.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flutter/material.dart';
import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart';
/// A [Blueprint] which creates the [JetpackRamp].
class Jetpack extends Forge2DBlueprint {
@override
void build(_) {
final position = Vector2(
BoardDimensions.bounds.left + 40.5,
BoardDimensions.bounds.top - 31.5,
);
addAllContactCallback([
RampOpeningBallContactCallback<_JetpackRampOpening>(),
]);
final rightOpening = _JetpackRampOpening(
rotation: math.pi,
)
..initialPosition = position + Vector2(12.9, -20)
..layer = Layer.opening;
final leftOpening = _JetpackRampOpening(
outsideLayer: Layer.spaceship,
rotation: math.pi,
)
..initialPosition = position + Vector2(-2.5, -20)
..layer = Layer.jetpack;
final jetpackRamp = JetpackRamp()
..initialPosition = position + Vector2(5, -20.2)
..layer = Layer.jetpack;
addAll([
rightOpening,
leftOpening,
jetpackRamp,
]);
}
}
/// {@template jetpack_ramp}
/// Represents the upper left blue ramp of the [Board].
/// {@endtemplate}
class JetpackRamp extends BodyComponent with InitialPosition, Layered {
JetpackRamp() : super(priority: 2) {
layer = Layer.jetpack;
paint = Paint()
..color = const Color.fromARGB(255, 8, 218, 241)
..style = PaintingStyle.stroke;
}
/// Radius of the external arc.
static const _externalRadius = 18.0;
/// Width between walls of the ramp.
static const width = 5.0;
List<FixtureDef> _createFixtureDefs() {
final fixturesDef = <FixtureDef>[];
final externalCurveShape = ArcShape(
center: initialPosition,
arcRadius: _externalRadius,
angle: math.pi,
rotation: math.pi,
);
final externalFixtureDef = FixtureDef(externalCurveShape);
fixturesDef.add(externalFixtureDef);
final internalCurveShape = externalCurveShape.copyWith(
arcRadius: _externalRadius - width,
);
final internalFixtureDef = FixtureDef(internalCurveShape);
fixturesDef.add(internalFixtureDef);
return fixturesDef;
}
@override
Body createBody() {
final bodyDef = BodyDef()
..userData = this
..position = initialPosition;
final body = world.createBody(bodyDef);
_createFixtureDefs().forEach(body.createFixture);
return body;
}
}
/// {@template jetpack_ramp_opening}
/// [RampOpening] with [Layer.jetpack] to filter [Ball] collisions
/// inside [JetpackRamp].
/// {@endtemplate}
class _JetpackRampOpening extends RampOpening {
/// {@macro jetpack_ramp_opening}
_JetpackRampOpening({
Layer? outsideLayer,
required double rotation,
}) : _rotation = rotation,
super(
insideLayer: Layer.jetpack,
outsideLayer: outsideLayer,
orientation: RampOrientation.down,
);
final double _rotation;
static final Vector2 _size = Vector2(JetpackRamp.width / 4, .1);
@override
Shape get shape => PolygonShape()
..setAsBox(
_size.x,
_size.y,
initialPosition,
_rotation,
);
}

@ -1,141 +0,0 @@
// ignore_for_file: public_member_api_docs, avoid_renaming_method_parameters
import 'dart:math' as math;
import 'package:flame/extensions.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flutter/material.dart';
import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart';
/// A [Blueprint] which creates the [LauncherRamp].
class Launcher extends Forge2DBlueprint {
@override
void build(_) {
final position = Vector2(
BoardDimensions.bounds.right - 31.3,
BoardDimensions.bounds.bottom + 33,
);
addAllContactCallback([
RampOpeningBallContactCallback<_LauncherRampOpening>(),
]);
final leftOpening = _LauncherRampOpening(rotation: math.pi / 2)
..initialPosition = position + Vector2(-11.8, 72.7)
..layer = Layer.opening;
final rightOpening = _LauncherRampOpening(rotation: 0)
..initialPosition = position + Vector2(-5.4, 65.4)
..layer = Layer.opening;
final launcherRamp = LauncherRamp()
..initialPosition = position + Vector2(1.7, 0)
..layer = Layer.launcher;
addAll([
leftOpening,
rightOpening,
launcherRamp,
]);
}
}
/// {@template launcher_ramp}
/// The yellow right ramp, where the [Ball] goes through when launched from the
/// [Plunger].
/// {@endtemplate}
class LauncherRamp extends BodyComponent with InitialPosition, Layered {
/// {@macro launcher_ramp}
LauncherRamp() : super(priority: 2) {
layer = Layer.launcher;
paint = Paint()
..color = const Color.fromARGB(255, 251, 255, 0)
..style = PaintingStyle.stroke;
}
/// Width between walls of the ramp.
static const width = 5.0;
/// Radius of the external arc at the top of the ramp.
static const _externalRadius = 16.3;
List<FixtureDef> _createFixtureDefs() {
final fixturesDef = <FixtureDef>[];
final startPosition = initialPosition + Vector2(0, 3);
final endPosition = initialPosition + Vector2(0, 130);
final rightStraightShape = EdgeShape()
..set(
startPosition..rotate(BoardDimensions.perspectiveAngle),
endPosition..rotate(BoardDimensions.perspectiveAngle),
);
final rightStraightFixtureDef = FixtureDef(rightStraightShape);
fixturesDef.add(rightStraightFixtureDef);
final leftStraightShape = EdgeShape()
..set(
startPosition - Vector2(width, 0),
endPosition - Vector2(width, 0),
);
final leftStraightFixtureDef = FixtureDef(leftStraightShape);
fixturesDef.add(leftStraightFixtureDef);
final externalCurveShape = ArcShape(
center: initialPosition + Vector2(-28.2, 132),
arcRadius: _externalRadius,
angle: math.pi / 2,
rotation: 3 * math.pi / 2,
);
final externalCurveFixtureDef = FixtureDef(externalCurveShape);
fixturesDef.add(externalCurveFixtureDef);
final internalCurveShape = externalCurveShape.copyWith(
arcRadius: _externalRadius - width,
);
final internalCurveFixtureDef = FixtureDef(internalCurveShape);
fixturesDef.add(internalCurveFixtureDef);
return fixturesDef;
}
@override
Body createBody() {
final bodyDef = BodyDef()
..userData = this
..position = initialPosition;
final body = world.createBody(bodyDef);
_createFixtureDefs().forEach(body.createFixture);
return body;
}
}
/// {@template launcher_ramp_opening}
/// [RampOpening] with [Layer.launcher] to filter [Ball]s collisions
/// inside [LauncherRamp].
/// {@endtemplate}
class _LauncherRampOpening extends RampOpening {
/// {@macro launcher_ramp_opening}
_LauncherRampOpening({
required double rotation,
}) : _rotation = rotation,
super(
insideLayer: Layer.launcher,
orientation: RampOrientation.down,
);
final double _rotation;
static final Vector2 _size = Vector2(LauncherRamp.width / 3, .1);
@override
Shape get shape => PolygonShape()
..setAsBox(
_size.x,
_size.y,
initialPosition,
_rotation,
);
}

@ -1,5 +1,6 @@
import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:pinball_components/pinball_components.dart';
@ -13,7 +14,11 @@ class Plunger extends BodyComponent with KeyboardHandler, InitialPosition {
/// {@macro plunger}
Plunger({
required this.compressionDistance,
});
}) : super(
priority: 5,
// TODO(allisonryan0002): remove paint after asset is added.
paint: Paint()..color = const Color.fromARGB(255, 241, 8, 8),
);
/// Distance the plunger can lower.
final double compressionDistance;

@ -1,198 +0,0 @@
// ignore_for_file: avoid_renaming_method_parameters
import 'dart:math' as math;
import 'dart:ui';
import 'package:flame/extensions.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:pinball_components/pinball_components.dart' hide Assets;
/// {@template spaceship_exit_rail}
/// A [Blueprint] for the spaceship drop tube.
/// {@endtemplate}
class SpaceshipExitRail extends Forge2DBlueprint {
/// {@macro spaceship_exit_rail}
SpaceshipExitRail({required this.position});
/// The [position] where the elements will be created
final Vector2 position;
@override
void build(_) {
addAllContactCallback([
SpaceshipExitRailEndBallContactCallback(),
]);
final spaceshipExitRailRamp = _SpaceshipExitRailRamp()
..initialPosition = position;
final exitRail = SpaceshipExitRailEnd()
..initialPosition = position + _SpaceshipExitRailRamp.exitPoint;
addAll([
spaceshipExitRailRamp,
exitRail,
]);
}
}
class _SpaceshipExitRailRamp extends BodyComponent
with InitialPosition, Layered {
_SpaceshipExitRailRamp() : super(priority: 2) {
layer = Layer.spaceshipExitRail;
// TODO(ruimiguel): remove color once asset is placed.
paint = Paint()
..color = const Color.fromARGB(255, 249, 65, 3)
..style = PaintingStyle.stroke;
}
static final exitPoint = Vector2(9.2, -48.5);
List<FixtureDef> _createFixtureDefs() {
const entranceRotationAngle = 175 * math.pi / 180;
const curveRotationAngle = 275 * math.pi / 180;
const exitRotationAngle = 340 * math.pi / 180;
const width = 5.5;
final fixturesDefs = <FixtureDef>[];
final entranceWall = ArcShape(
center: Vector2(width / 2, 0),
arcRadius: width / 2,
angle: math.pi,
rotation: entranceRotationAngle,
);
final entranceFixtureDef = FixtureDef(entranceWall);
fixturesDefs.add(entranceFixtureDef);
final topLeftControlPoints = [
Vector2(0, 0),
Vector2(10, .5),
Vector2(7, 4),
Vector2(15.5, 8.3),
];
final topLeftCurveShape = BezierCurveShape(
controlPoints: topLeftControlPoints,
)..rotate(curveRotationAngle);
final topLeftFixtureDef = FixtureDef(topLeftCurveShape);
fixturesDefs.add(topLeftFixtureDef);
final topRightControlPoints = [
Vector2(0, width),
Vector2(10, 6.5),
Vector2(7, 10),
Vector2(15.5, 13.2),
];
final topRightCurveShape = BezierCurveShape(
controlPoints: topRightControlPoints,
)..rotate(curveRotationAngle);
final topRightFixtureDef = FixtureDef(topRightCurveShape);
fixturesDefs.add(topRightFixtureDef);
final mediumLeftControlPoints = [
topLeftControlPoints.last,
Vector2(21, 12.9),
Vector2(30, 7.1),
Vector2(32, 4.8),
];
final mediumLeftCurveShape = BezierCurveShape(
controlPoints: mediumLeftControlPoints,
)..rotate(curveRotationAngle);
final mediumLeftFixtureDef = FixtureDef(mediumLeftCurveShape);
fixturesDefs.add(mediumLeftFixtureDef);
final mediumRightControlPoints = [
topRightControlPoints.last,
Vector2(21, 17.2),
Vector2(30, 12.1),
Vector2(32, 10.2),
];
final mediumRightCurveShape = BezierCurveShape(
controlPoints: mediumRightControlPoints,
)..rotate(curveRotationAngle);
final mediumRightFixtureDef = FixtureDef(mediumRightCurveShape);
fixturesDefs.add(mediumRightFixtureDef);
final bottomLeftControlPoints = [
mediumLeftControlPoints.last,
Vector2(40, -1),
Vector2(48, 1.9),
Vector2(50.5, 2.5),
];
final bottomLeftCurveShape = BezierCurveShape(
controlPoints: bottomLeftControlPoints,
)..rotate(curveRotationAngle);
final bottomLeftFixtureDef = FixtureDef(bottomLeftCurveShape);
fixturesDefs.add(bottomLeftFixtureDef);
final bottomRightControlPoints = [
mediumRightControlPoints.last,
Vector2(40, 4),
Vector2(46, 6.5),
Vector2(48.8, 7.6),
];
final bottomRightCurveShape = BezierCurveShape(
controlPoints: bottomRightControlPoints,
)..rotate(curveRotationAngle);
final bottomRightFixtureDef = FixtureDef(bottomRightCurveShape);
fixturesDefs.add(bottomRightFixtureDef);
final exitWall = ArcShape(
center: exitPoint,
arcRadius: width / 2,
angle: math.pi,
rotation: exitRotationAngle,
);
final exitFixtureDef = FixtureDef(exitWall);
fixturesDefs.add(exitFixtureDef);
return fixturesDefs;
}
@override
Body createBody() {
final bodyDef = BodyDef()
..userData = this
..position = initialPosition;
final body = world.createBody(bodyDef);
_createFixtureDefs().forEach(body.createFixture);
return body;
}
}
/// {@template spaceship_exit_rail_end}
/// A sensor [BodyComponent] responsible for sending the [Ball]
/// back to the board.
/// {@endtemplate}
class SpaceshipExitRailEnd extends RampOpening {
/// {@macro spaceship_exit_rail_end}
SpaceshipExitRailEnd()
: super(
insideLayer: Layer.spaceshipExitRail,
orientation: RampOrientation.down,
) {
layer = Layer.spaceshipExitRail;
}
@override
Shape get shape {
return CircleShape()..radius = 1;
}
}
/// [ContactCallback] that handles the contact between the [Ball]
/// and a [SpaceshipExitRailEnd].
///
/// It resets the [Ball] priority and filter data so it will "be back" on the
/// board.
class SpaceshipExitRailEndBallContactCallback
extends ContactCallback<SpaceshipExitRailEnd, Ball> {
@override
void begin(SpaceshipExitRailEnd exitRail, Ball ball, _) {
ball
..priority = 1
..gameRef.reorderChildren()
..layer = exitRail.outsideLayer;
}
}

@ -13,6 +13,10 @@ extension PinballGameAssetsX on PinballGame {
images.load(components.Assets.images.flipper.right.keyName),
images.load(components.Assets.images.baseboard.left.keyName),
images.load(components.Assets.images.baseboard.right.keyName),
images.load(components.Assets.images.launchRamp.ramp.keyName),
images.load(
components.Assets.images.launchRamp.foregroundRailing.keyName,
),
images.load(components.Assets.images.dino.dinoLandTop.keyName),
images.load(components.Assets.images.dino.dinoLandBottom.keyName),
images.load(components.Assets.images.dashBumper.a.active.keyName),
@ -21,6 +25,21 @@ extension PinballGameAssetsX on PinballGame {
images.load(components.Assets.images.dashBumper.b.inactive.keyName),
images.load(components.Assets.images.dashBumper.main.active.keyName),
images.load(components.Assets.images.dashBumper.main.inactive.keyName),
images.load(components.Assets.images.boundary.bottom.keyName),
images.load(components.Assets.images.boundary.outer.keyName),
images.load(components.Assets.images.spaceship.saucer.keyName),
images.load(components.Assets.images.spaceship.bridge.keyName),
images.load(components.Assets.images.spaceship.ramp.main.keyName),
images.load(
components.Assets.images.spaceship.ramp.railingBackground.keyName,
),
images.load(
components.Assets.images.spaceship.ramp.railingForeground.keyName,
),
images.load(components.Assets.images.spaceship.rail.main.keyName),
images.load(components.Assets.images.spaceship.rail.foreground.keyName),
images.load(components.Assets.images.chromeDino.mouth.keyName),
images.load(components.Assets.images.chromeDino.head.keyName),
images.load(Assets.images.components.background.path),
]);
}

@ -36,9 +36,10 @@ class PinballGame extends Forge2DGame
await _addGameBoundaries();
unawaited(add(Board()));
unawaited(addFromBlueprint(Boundaries()));
unawaited(_addPlunger());
unawaited(_addBonusWord());
unawaited(_addPaths());
unawaited(_addRamps());
unawaited(
addFromBlueprint(
Spaceship(
@ -48,9 +49,7 @@ class PinballGame extends Forge2DGame
);
unawaited(
addFromBlueprint(
SpaceshipExitRail(
position: Vector2(-34.3, 23.8),
),
SpaceshipRail(),
),
);
@ -96,9 +95,9 @@ class PinballGame extends Forge2DGame
);
}
Future<void> _addPaths() async {
unawaited(addFromBlueprint(Jetpack()));
unawaited(addFromBlueprint(Launcher()));
Future<void> _addRamps() async {
unawaited(addFromBlueprint(SpaceshipRamp()));
unawaited(addFromBlueprint(LaunchRamp()));
}
void spawnBall() {
@ -139,7 +138,7 @@ class DebugPinballGame extends PinballGame with TapDetector {
anchor: Anchor.center,
)
..position = Vector2(0, -7.8)
..priority = -1;
..priority = -2;
await add(spriteComponent);
}

@ -114,9 +114,9 @@ void main() {
Vector2(0, 0),
Vector2(10, 10),
],
step: 0.001,
step: 0.02,
);
expect(points.length, 1000);
expect(points.length, 50);
});
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 768 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

@ -14,6 +14,9 @@ class $AssetsImagesGen {
AssetGenImage get ball => const AssetGenImage('assets/images/ball.png');
$AssetsImagesBaseboardGen get baseboard => const $AssetsImagesBaseboardGen();
$AssetsImagesBoundaryGen get boundary => const $AssetsImagesBoundaryGen();
$AssetsImagesChromeDinoGen get chromeDino =>
const $AssetsImagesChromeDinoGen();
$AssetsImagesDashBumperGen get dashBumper =>
const $AssetsImagesDashBumperGen();
$AssetsImagesDinoGen get dino => const $AssetsImagesDinoGen();
@ -23,13 +26,9 @@ class $AssetsImagesGen {
AssetGenImage get flutterSignPost =>
const AssetGenImage('assets/images/flutter_sign_post.png');
/// File path: assets/images/spaceship_bridge.png
AssetGenImage get spaceshipBridge =>
const AssetGenImage('assets/images/spaceship_bridge.png');
/// File path: assets/images/spaceship_saucer.png
AssetGenImage get spaceshipSaucer =>
const AssetGenImage('assets/images/spaceship_saucer.png');
$AssetsImagesLaunchRampGen get launchRamp =>
const $AssetsImagesLaunchRampGen();
$AssetsImagesSpaceshipGen get spaceship => const $AssetsImagesSpaceshipGen();
}
class $AssetsImagesBaseboardGen {
@ -44,6 +43,30 @@ class $AssetsImagesBaseboardGen {
const AssetGenImage('assets/images/baseboard/right.png');
}
class $AssetsImagesBoundaryGen {
const $AssetsImagesBoundaryGen();
/// File path: assets/images/boundary/bottom.png
AssetGenImage get bottom =>
const AssetGenImage('assets/images/boundary/bottom.png');
/// File path: assets/images/boundary/outer.png
AssetGenImage get outer =>
const AssetGenImage('assets/images/boundary/outer.png');
}
class $AssetsImagesChromeDinoGen {
const $AssetsImagesChromeDinoGen();
/// File path: assets/images/chrome_dino/head.png
AssetGenImage get head =>
const AssetGenImage('assets/images/chrome_dino/head.png');
/// File path: assets/images/chrome_dino/mouth.png
AssetGenImage get mouth =>
const AssetGenImage('assets/images/chrome_dino/mouth.png');
}
class $AssetsImagesDashBumperGen {
const $AssetsImagesDashBumperGen();
@ -77,6 +100,35 @@ class $AssetsImagesFlipperGen {
const AssetGenImage('assets/images/flipper/right.png');
}
class $AssetsImagesLaunchRampGen {
const $AssetsImagesLaunchRampGen();
/// File path: assets/images/launch_ramp/foreground-railing.png
AssetGenImage get foregroundRailing =>
const AssetGenImage('assets/images/launch_ramp/foreground-railing.png');
/// File path: assets/images/launch_ramp/ramp.png
AssetGenImage get ramp =>
const AssetGenImage('assets/images/launch_ramp/ramp.png');
}
class $AssetsImagesSpaceshipGen {
const $AssetsImagesSpaceshipGen();
/// File path: assets/images/spaceship/bridge.png
AssetGenImage get bridge =>
const AssetGenImage('assets/images/spaceship/bridge.png');
$AssetsImagesSpaceshipRailGen get rail =>
const $AssetsImagesSpaceshipRailGen();
$AssetsImagesSpaceshipRampGen get ramp =>
const $AssetsImagesSpaceshipRampGen();
/// File path: assets/images/spaceship/saucer.png
AssetGenImage get saucer =>
const AssetGenImage('assets/images/spaceship/saucer.png');
}
class $AssetsImagesDashBumperAGen {
const $AssetsImagesDashBumperAGen();
@ -113,6 +165,34 @@ class $AssetsImagesDashBumperMainGen {
const AssetGenImage('assets/images/dash_bumper/main/inactive.png');
}
class $AssetsImagesSpaceshipRailGen {
const $AssetsImagesSpaceshipRailGen();
/// File path: assets/images/spaceship/rail/foreground.png
AssetGenImage get foreground =>
const AssetGenImage('assets/images/spaceship/rail/foreground.png');
/// File path: assets/images/spaceship/rail/main.png
AssetGenImage get main =>
const AssetGenImage('assets/images/spaceship/rail/main.png');
}
class $AssetsImagesSpaceshipRampGen {
const $AssetsImagesSpaceshipRampGen();
/// File path: assets/images/spaceship/ramp/main.png
AssetGenImage get main =>
const AssetGenImage('assets/images/spaceship/ramp/main.png');
/// File path: assets/images/spaceship/ramp/railing-background.png
AssetGenImage get railingBackground => const AssetGenImage(
'assets/images/spaceship/ramp/railing-background.png');
/// File path: assets/images/spaceship/ramp/railing-foreground.png
AssetGenImage get railingForeground => const AssetGenImage(
'assets/images/spaceship/ramp/railing-foreground.png');
}
class Assets {
Assets._();

@ -0,0 +1,156 @@
// ignore_for_file: avoid_renaming_method_parameters
import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:pinball_components/pinball_components.dart';
/// {@template boundaries}
/// A [Blueprint] which creates the [_BottomBoundary] and [_OuterBoundary].
///{@endtemplate boundaries}
class Boundaries extends Forge2DBlueprint {
@override
void build(_) {
final bottomBoundary = _BottomBoundary();
final outerBoundary = _OuterBoundary();
addAll([bottomBoundary, outerBoundary]);
}
}
/// {@template bottom_boundary}
/// Curved boundary at the bottom of the board where the [Ball] exits the field
/// of play.
/// {@endtemplate bottom_boundary}
class _BottomBoundary extends BodyComponent with InitialPosition {
/// {@macro bottom_boundary}
_BottomBoundary() : super(priority: 2);
List<FixtureDef> _createFixtureDefs() {
final fixturesDefs = <FixtureDef>[];
final bottomLeftCurve = BezierCurveShape(
controlPoints: [
Vector2(-43.6, -44.4),
Vector2(-31, -43.4),
Vector2(-18.7, -52.1),
],
);
final bottomLeftCurveFixtureDef = FixtureDef(bottomLeftCurve);
fixturesDefs.add(bottomLeftCurveFixtureDef);
final bottomRightCurve = BezierCurveShape(
controlPoints: [
Vector2(31.8, -44.1),
Vector2(21.95, -47),
Vector2(12.3, -51.4),
],
);
final bottomRightCurveFixtureDef = FixtureDef(bottomRightCurve);
fixturesDefs.add(bottomRightCurveFixtureDef);
return fixturesDefs;
}
@override
Body createBody() {
final bodyDef = BodyDef()..position = initialPosition;
final body = world.createBody(bodyDef);
_createFixtureDefs().forEach(body.createFixture);
return body;
}
@override
Future<void> onLoad() async {
await super.onLoad();
await _loadSprite();
renderBody = false;
}
Future<void> _loadSprite() async {
final sprite = await gameRef.loadSprite(
Assets.images.boundary.bottom.keyName,
);
await add(
SpriteComponent(
sprite: sprite,
size: sprite.originalSize / 10,
anchor: Anchor.center,
position: Vector2(-5.4, 57.4),
),
);
}
}
/// {@template outer_boundary}
/// Boundary enclosing the top and left side of the board. The right side of the
/// board is closed by the barrier the [LaunchRamp] creates.
/// {@endtemplate outer_boundary}
class _OuterBoundary extends BodyComponent with InitialPosition {
/// {@macro outer_boundary}
_OuterBoundary() : super(priority: -1);
List<FixtureDef> _createFixtureDefs() {
final fixturesDefs = <FixtureDef>[];
final topWall = EdgeShape()
..set(
Vector2(3.6, 70.2),
Vector2(-14.1, 70.2),
);
final topWallFixtureDef = FixtureDef(topWall);
fixturesDefs.add(topWallFixtureDef);
final topLeftCurve = BezierCurveShape(
controlPoints: [
Vector2(-32.3, 57.2),
Vector2(-31.5, 69.9),
Vector2(-14.1, 70.2),
],
);
final topLeftCurveFixtureDef = FixtureDef(topLeftCurve);
fixturesDefs.add(topLeftCurveFixtureDef);
final leftWall = EdgeShape()
..set(
Vector2(-32.3, 57.2),
Vector2(-44.1, -44.4),
);
final leftWallFixtureDef = FixtureDef(leftWall);
fixturesDefs.add(leftWallFixtureDef);
return fixturesDefs;
}
@override
Body createBody() {
final bodyDef = BodyDef()..position = initialPosition;
final body = world.createBody(bodyDef);
_createFixtureDefs().forEach(body.createFixture);
return body;
}
@override
Future<void> onLoad() async {
await super.onLoad();
await _loadSprite();
renderBody = false;
}
Future<void> _loadSprite() async {
final sprite = await gameRef.loadSprite(
Assets.images.boundary.outer.keyName,
);
await add(
SpriteComponent(
sprite: sprite,
size: sprite.originalSize / 10,
anchor: Anchor.center,
position: Vector2(-0.2, -1.4),
),
);
}
}

@ -43,7 +43,7 @@ class ChromeDino extends BodyComponent with InitialPosition {
await add(
TimerComponent(
period: 1,
onTick: joint.swivel,
onTick: joint._swivel,
repeat: true,
),
);
@ -150,7 +150,7 @@ class _ChromeDinoJoint extends RevoluteJoint {
_ChromeDinoJoint(_ChromeDinoAnchorRevoluteJointDef def) : super(def);
/// Sweeps the [ChromeDino] up and down repeatedly.
void swivel() {
void _swivel() {
setMotorSpeed(-motorSpeed);
}
}

@ -2,6 +2,8 @@ export 'ball.dart';
export 'baseboard.dart';
export 'board_dimensions.dart';
export 'board_side.dart';
export 'boundaries.dart';
export 'chrome_dino.dart';
export 'dash_nest_bumper.dart';
export 'dino_walls.dart';
export 'fire_effect.dart';
@ -9,7 +11,11 @@ export 'flipper.dart';
export 'flutter_sign_post.dart';
export 'initial_position.dart';
export 'joint_anchor.dart';
export 'kicker.dart';
export 'launch_ramp.dart';
export 'layer.dart';
export 'ramp_opening.dart';
export 'shapes/shapes.dart';
export 'spaceship.dart';
export 'spaceship_rail.dart';
export 'spaceship_ramp.dart';

@ -67,6 +67,7 @@ class BigDashNestBumper extends DashNestBumper {
inactiveAssetPath: Assets.images.dashBumper.main.inactive.keyName,
spriteComponent: SpriteComponent(
anchor: Anchor.center,
position: Vector2(0, -0.3),
),
);
@ -74,9 +75,9 @@ class BigDashNestBumper extends DashNestBumper {
Body createBody() {
final shape = EllipseShape(
center: Vector2.zero(),
majorRadius: 4.85,
minorRadius: 3.95,
)..rotate(math.pi / 2);
majorRadius: 5.1,
minorRadius: 3.75,
)..rotate(math.pi / 2.1);
final fixtureDef = FixtureDef(shape);
final bodyDef = BodyDef()

@ -0,0 +1,243 @@
// ignore_for_file: avoid_renaming_method_parameters
import 'dart:math' as math;
import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:pinball_components/pinball_components.dart';
/// {@template launch_ramp}
/// A [Blueprint] which creates the [_LaunchRampBase] and
/// [_LaunchRampForegroundRailing].
/// {@endtemplate}
class LaunchRamp extends Forge2DBlueprint {
@override
void build(_) {
addAllContactCallback([
RampOpeningBallContactCallback<_LaunchRampExit>(),
]);
final launchRampBase = _LaunchRampBase()..layer = Layer.launcher;
final launchRampForegroundRailing = _LaunchRampForegroundRailing()
..layer = Layer.launcher;
final launchRampExit = _LaunchRampExit(rotation: math.pi / 2)
..initialPosition = Vector2(1.8, 34.2)
..layer = Layer.opening
..renderBody = false;
addAll([
launchRampBase,
launchRampForegroundRailing,
launchRampExit,
]);
}
}
/// {@template launch_ramp_base}
/// Ramp the [Ball] is launched from at the beginning of each ball life.
/// {@endtemplate}
class _LaunchRampBase extends BodyComponent with InitialPosition, Layered {
/// {@macro launch_ramp_base}
_LaunchRampBase() : super(priority: -1) {
layer = Layer.launcher;
}
List<FixtureDef> _createFixtureDefs() {
final fixturesDef = <FixtureDef>[];
final rightStraightShape = EdgeShape()
..set(
Vector2(31.4, 61.4),
Vector2(46.5, -68.4),
);
final rightStraightFixtureDef = FixtureDef(rightStraightShape);
fixturesDef.add(rightStraightFixtureDef);
final leftStraightShape = EdgeShape()
..set(
Vector2(27.8, 61.4),
Vector2(41.5, -68.4),
);
final leftStraightFixtureDef = FixtureDef(leftStraightShape);
fixturesDef.add(leftStraightFixtureDef);
final topCurveShape = ArcShape(
center: Vector2(20.5, 61.1),
arcRadius: 11,
angle: 1.6,
rotation: -1.65,
);
final topCurveFixtureDef = FixtureDef(topCurveShape);
fixturesDef.add(topCurveFixtureDef);
final bottomCurveShape = ArcShape(
center: Vector2(19.3, 60.3),
arcRadius: 8.5,
angle: 1.48,
rotation: -1.58,
);
final bottomCurveFixtureDef = FixtureDef(bottomCurveShape);
fixturesDef.add(bottomCurveFixtureDef);
final topStraightShape = EdgeShape()
..set(
Vector2(3.7, 70.1),
Vector2(19.1, 72.1),
);
final topStraightFixtureDef = FixtureDef(topStraightShape);
fixturesDef.add(topStraightFixtureDef);
final bottomStraightShape = EdgeShape()
..set(
Vector2(3.7, 66.9),
Vector2(19.1, 68.8),
);
final bottomStraightFixtureDef = FixtureDef(bottomStraightShape);
fixturesDef.add(bottomStraightFixtureDef);
return fixturesDef;
}
@override
Body createBody() {
final bodyDef = BodyDef()
..userData = this
..position = initialPosition;
final body = world.createBody(bodyDef);
_createFixtureDefs().forEach(body.createFixture);
return body;
}
@override
Future<void> onLoad() async {
await super.onLoad();
await _loadSprite();
renderBody = false;
}
Future<void> _loadSprite() async {
final sprite = await gameRef.loadSprite(
Assets.images.launchRamp.ramp.keyName,
);
await add(
SpriteComponent(
sprite: sprite,
size: sprite.originalSize / 10,
anchor: Anchor.center,
position: Vector2(25.65, 0),
),
);
}
}
/// {@template launch_ramp_foreground_railing}
/// Foreground railing for the [_LaunchRampBase] to render in front of the
/// [Ball].
/// {@endtemplate}
class _LaunchRampForegroundRailing extends BodyComponent
with InitialPosition, Layered {
/// {@macro launch_ramp_foreground_railing}
_LaunchRampForegroundRailing() : super(priority: 4) {
layer = Layer.launcher;
}
List<FixtureDef> _createFixtureDefs() {
final fixturesDef = <FixtureDef>[];
final rightStraightShape = EdgeShape()
..set(
Vector2(27.6, 57.9),
Vector2(30, 35.1),
);
final rightStraightFixtureDef = FixtureDef(rightStraightShape);
fixturesDef.add(rightStraightFixtureDef);
final curveShape = ArcShape(
center: Vector2(20.1, 59.3),
arcRadius: 7.5,
angle: 1.8,
rotation: -1.63,
);
final curveFixtureDef = FixtureDef(curveShape);
fixturesDef.add(curveFixtureDef);
final topStraightShape = EdgeShape()
..set(
Vector2(3.7, 66.8),
Vector2(19.7, 66.8),
);
final topStraightFixtureDef = FixtureDef(topStraightShape);
fixturesDef.add(topStraightFixtureDef);
return fixturesDef;
}
@override
Body createBody() {
final bodyDef = BodyDef()
..userData = this
..position = initialPosition;
final body = world.createBody(bodyDef);
_createFixtureDefs().forEach(body.createFixture);
return body;
}
@override
Future<void> onLoad() async {
await super.onLoad();
await _loadSprite();
renderBody = false;
}
Future<void> _loadSprite() async {
final sprite = await gameRef.loadSprite(
Assets.images.launchRamp.foregroundRailing.keyName,
);
await add(
SpriteComponent(
sprite: sprite,
size: sprite.originalSize / 10,
anchor: Anchor.center,
position: Vector2(22.8, 0),
priority: 4,
),
);
}
}
/// {@template launch_ramp_exit}
/// [RampOpening] with [Layer.launcher] to filter [Ball]s exiting the
/// [LaunchRamp].
/// {@endtemplate}
class _LaunchRampExit extends RampOpening {
/// {@macro launch_ramp_exit}
_LaunchRampExit({
required double rotation,
}) : _rotation = rotation,
super(
insideLayer: Layer.launcher,
orientation: RampOrientation.down,
insidePriority: 3,
);
final double _rotation;
static final Vector2 _size = Vector2(1.6, 0.1);
@override
Shape get shape => PolygonShape()
..setAsBox(
_size.x,
_size.y,
initialPosition,
_rotation,
);
}

@ -53,8 +53,8 @@ enum Layer {
/// Collide only with ramps opening elements.
opening,
/// Collide only with Jetpack group elements.
jetpack,
/// Collide only with Spaceship entrance ramp group elements.
spaceshipEntranceRamp,
/// Collide only with Launcher group elements.
launcher,
@ -86,7 +86,7 @@ extension LayerMaskBits on Layer {
return 0x0001;
case Layer.opening:
return 0x0007;
case Layer.jetpack:
case Layer.spaceshipEntranceRamp:
return 0x0002;
case Layer.launcher:
return 0x0005;

@ -37,7 +37,7 @@ class Spaceship extends Forge2DBlueprint {
AndroidHead()..initialPosition = position,
SpaceshipHole(
outsideLayer: Layer.spaceshipExitRail,
outsidePriority: 2,
outsidePriority: SpaceshipRail.ballPriorityWhenOnSpaceshipRail,
)..initialPosition = position - Vector2(5.2, 4.8),
SpaceshipHole()..initialPosition = position - Vector2(-7.2, 0.8),
SpaceshipWall()..initialPosition = position,
@ -59,7 +59,7 @@ class SpaceshipSaucer extends BodyComponent with InitialPosition, Layered {
Future<void> onLoad() async {
await super.onLoad();
final sprite = await gameRef.loadSprite(
Assets.images.spaceshipSaucer.keyName,
Assets.images.spaceship.saucer.keyName,
);
await add(
@ -106,7 +106,7 @@ class AndroidHead extends BodyComponent with InitialPosition, Layered {
renderBody = false;
final sprite = await gameRef.images.load(
Assets.images.spaceshipBridge.keyName,
Assets.images.spaceship.bridge.keyName,
);
await add(
@ -185,8 +185,9 @@ class SpaceshipHole extends RampOpening {
: super(
insideLayer: Layer.spaceship,
outsideLayer: outsideLayer,
outsidePriority: outsidePriority,
orientation: RampOrientation.up,
insidePriority: 4,
outsidePriority: outsidePriority,
) {
renderBody = false;
layer = Layer.spaceship;
@ -195,8 +196,8 @@ class SpaceshipHole extends RampOpening {
@override
Shape get shape {
return ArcShape(
center: Vector2(0, 4.2),
arcRadius: 6,
center: Vector2(0, 3.2),
arcRadius: 5,
angle: 1,
rotation: 60 * pi / 180,
);

@ -0,0 +1,246 @@
// ignore_for_file: avoid_renaming_method_parameters
import 'dart:math' as math;
import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:pinball_components/gen/assets.gen.dart';
import 'package:pinball_components/pinball_components.dart' hide Assets;
/// {@template spaceship_rail}
/// A [Blueprint] for the spaceship drop tube.
/// {@endtemplate}
class SpaceshipRail extends Forge2DBlueprint {
/// {@macro spaceship_rail}
SpaceshipRail();
/// Base priority for ball while be in [_SpaceshipRailRamp].
static const ballPriorityWhenOnSpaceshipRail = 2;
@override
void build(_) {
addAllContactCallback([
SpaceshipRailExitBallContactCallback(),
]);
final railRamp = _SpaceshipRailRamp();
final railEnd = SpaceshipRailExit();
final topBase = _SpaceshipRailBase(radius: 0.55)
..initialPosition = Vector2(-26.15, 18.65);
final bottomBase = _SpaceshipRailBase(radius: 0.8)
..initialPosition = Vector2(-25.5, -12.9);
final railForeground = _SpaceshipRailForeground();
addAll([
railRamp,
railEnd,
topBase,
bottomBase,
railForeground,
]);
}
}
/// Represents the spaceship drop rail from the [Spaceship].
class _SpaceshipRailRamp extends BodyComponent with InitialPosition, Layered {
_SpaceshipRailRamp()
: super(
priority: SpaceshipRail.ballPriorityWhenOnSpaceshipRail - 1,
) {
renderBody = false;
layer = Layer.spaceshipExitRail;
}
List<FixtureDef> _createFixtureDefs() {
final fixturesDefs = <FixtureDef>[];
final topArcShape = ArcShape(
center: Vector2(-35.5, 30.9),
arcRadius: 2.5,
angle: math.pi,
rotation: 2.9,
);
final topArcFixtureDef = FixtureDef(topArcShape);
fixturesDefs.add(topArcFixtureDef);
final topLeftCurveShape = BezierCurveShape(
controlPoints: [
Vector2(-37.9, 30.4),
Vector2(-38, 23.9),
Vector2(-30.93, 18.2),
],
);
final topLeftCurveFixtureDef = FixtureDef(topLeftCurveShape);
fixturesDefs.add(topLeftCurveFixtureDef);
final middleLeftCurveShape = BezierCurveShape(
controlPoints: [
topLeftCurveShape.vertices.last,
Vector2(-22.6, 10.3),
Vector2(-30, 0.2),
],
);
final middleLeftCurveFixtureDef = FixtureDef(middleLeftCurveShape);
fixturesDefs.add(middleLeftCurveFixtureDef);
final bottomLeftCurveShape = BezierCurveShape(
controlPoints: [
middleLeftCurveShape.vertices.last,
Vector2(-36, -8.6),
Vector2(-32.04, -18.3),
],
);
final bottomLeftCurveFixtureDef = FixtureDef(bottomLeftCurveShape);
fixturesDefs.add(bottomLeftCurveFixtureDef);
final topRightStraightShape = EdgeShape()
..set(
Vector2(-33, 31.3),
Vector2(-27.2, 21.3),
);
final topRightStraightFixtureDef = FixtureDef(topRightStraightShape);
fixturesDefs.add(topRightStraightFixtureDef);
final middleRightCurveShape = BezierCurveShape(
controlPoints: [
topRightStraightShape.vertex1,
Vector2(-16.5, 11.4),
Vector2(-25.29, -1.7),
],
);
final middleRightCurveFixtureDef = FixtureDef(middleRightCurveShape);
fixturesDefs.add(middleRightCurveFixtureDef);
final bottomRightCurveShape = BezierCurveShape(
controlPoints: [
middleRightCurveShape.vertices.last,
Vector2(-29.91, -8.5),
Vector2(-26.8, -15.7),
],
);
final bottomRightCurveFixtureDef = FixtureDef(bottomRightCurveShape);
fixturesDefs.add(bottomRightCurveFixtureDef);
return fixturesDefs;
}
@override
Body createBody() {
final bodyDef = BodyDef()
..userData = this
..position = initialPosition;
final body = world.createBody(bodyDef);
_createFixtureDefs().forEach(body.createFixture);
return body;
}
@override
Future<void> onLoad() async {
await super.onLoad();
await _loadSprite();
}
Future<void> _loadSprite() async {
final sprite = await gameRef.loadSprite(
Assets.images.spaceship.rail.main.keyName,
);
final spriteComponent = SpriteComponent(
sprite: sprite,
size: Vector2(17.5, 55.7),
anchor: Anchor.center,
position: Vector2(-29.4, -5.7),
);
await add(spriteComponent);
}
}
class _SpaceshipRailForeground extends SpriteComponent with HasGameRef {
_SpaceshipRailForeground()
: super(
anchor: Anchor.center,
position: Vector2(-28.5, 19.7),
priority: SpaceshipRail.ballPriorityWhenOnSpaceshipRail + 1,
);
@override
Future<void> onLoad() async {
await super.onLoad();
final sprite = await gameRef.loadSprite(
Assets.images.spaceship.rail.foreground.keyName,
);
this.sprite = sprite;
size = sprite.originalSize / 10;
}
}
/// Represents the ground bases of the [_SpaceshipRailRamp].
class _SpaceshipRailBase extends BodyComponent with InitialPosition, Layered {
_SpaceshipRailBase({required this.radius})
: super(
priority: SpaceshipRail.ballPriorityWhenOnSpaceshipRail + 1,
) {
renderBody = false;
layer = Layer.board;
}
final double radius;
@override
Body createBody() {
final shape = CircleShape()..radius = radius;
final fixtureDef = FixtureDef(shape);
final bodyDef = BodyDef()
..position = initialPosition
..userData = this;
return world.createBody(bodyDef)..createFixture(fixtureDef);
}
}
/// {@template spaceship_rail_exit}
/// A sensor [BodyComponent] responsible for sending the [Ball]
/// back to the board.
/// {@endtemplate}
class SpaceshipRailExit extends RampOpening {
/// {@macro spaceship_rail_exit}
SpaceshipRailExit()
: super(
insideLayer: Layer.spaceshipExitRail,
orientation: RampOrientation.down,
insidePriority: 3,
) {
renderBody = false;
layer = Layer.spaceshipExitRail;
}
@override
Shape get shape {
return ArcShape(
center: Vector2(-28, -19),
arcRadius: 2.5,
angle: math.pi * 0.4,
rotation: -0.16,
);
}
}
/// [ContactCallback] that handles the contact between the [Ball]
/// and a [SpaceshipRailExit].
///
/// It resets the [Ball] priority and filter data so it will "be back" on the
/// board.
class SpaceshipRailExitBallContactCallback
extends ContactCallback<SpaceshipRailExit, Ball> {
@override
void begin(SpaceshipRailExit exitRail, Ball ball, _) {
ball
..sendTo(exitRail.outsidePriority)
..layer = exitRail.outsideLayer;
}
}

@ -0,0 +1,282 @@
// ignore_for_file: avoid_renaming_method_parameters, comment_references
import 'dart:math' as math;
import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:pinball_components/gen/assets.gen.dart';
import 'package:pinball_components/pinball_components.dart' hide Assets;
/// {@template spaceship_ramp}
/// A [Blueprint] which creates the [_SpaceshipRampBackground].
/// {@endtemplate}
class SpaceshipRamp extends Forge2DBlueprint {
/// {@macro spaceship_ramp}
SpaceshipRamp();
/// Base priority for wall while be in the ramp.
static const int ballPriorityInsideRamp = 4;
@override
void build(_) {
addAllContactCallback([
RampOpeningBallContactCallback<_SpaceshipRampOpening>(),
]);
final rightOpening = _SpaceshipRampOpening(
// TODO(ruimiguel): set Board priority when defined.
outsidePriority: 1,
rotation: math.pi,
)
..initialPosition = Vector2(1.7, 19)
..layer = Layer.opening;
final leftOpening = _SpaceshipRampOpening(
outsideLayer: Layer.spaceship,
outsidePriority: Spaceship.ballPriorityWhenOnSpaceship,
rotation: math.pi,
)
..initialPosition = Vector2(-13.7, 19)
..layer = Layer.spaceshipEntranceRamp;
final spaceshipRamp = _SpaceshipRampBackground();
final spaceshipRampForegroundRailing = _SpaceshipRampForegroundRailing();
final baseRight = _SpaceshipRampBase()..initialPosition = Vector2(1.7, 20);
addAll([
rightOpening,
leftOpening,
baseRight,
spaceshipRamp,
spaceshipRampForegroundRailing,
]);
}
}
/// Represents the upper left blue ramp of the [Board] with its background
/// railing.
class _SpaceshipRampBackground extends BodyComponent
with InitialPosition, Layered {
_SpaceshipRampBackground()
: super(priority: SpaceshipRamp.ballPriorityInsideRamp - 1) {
layer = Layer.spaceshipEntranceRamp;
}
/// Width between walls of the ramp.
static const width = 5.0;
List<FixtureDef> _createFixtureDefs() {
final fixturesDef = <FixtureDef>[];
final outerLeftCurveShape = BezierCurveShape(
controlPoints: [
Vector2(-30.95, 38),
Vector2(-32.5, 71.25),
Vector2(-14.2, 71.25),
],
);
final outerLeftCurveFixtureDef = FixtureDef(outerLeftCurveShape);
fixturesDef.add(outerLeftCurveFixtureDef);
final outerRightCurveShape = BezierCurveShape(
controlPoints: [
outerLeftCurveShape.vertices.last,
Vector2(4.7, 71.25),
Vector2(6.3, 40),
],
);
final outerRightCurveFixtureDef = FixtureDef(outerRightCurveShape);
fixturesDef.add(outerRightCurveFixtureDef);
return fixturesDef;
}
@override
Body createBody() {
renderBody = false;
final bodyDef = BodyDef()
..userData = this
..position = initialPosition;
final body = world.createBody(bodyDef);
_createFixtureDefs().forEach(body.createFixture);
return body;
}
@override
Future<void> onLoad() async {
await super.onLoad();
await _loadSprites();
}
Future<void> _loadSprites() async {
final spriteRamp = await gameRef.loadSprite(
Assets.images.spaceship.ramp.main.keyName,
);
final spriteRampComponent = SpriteComponent(
sprite: spriteRamp,
size: Vector2(38.1, 33.8),
anchor: Anchor.center,
position: Vector2(-12.2, -53.5),
);
final spriteRailingBg = await gameRef.loadSprite(
Assets.images.spaceship.ramp.railingBackground.keyName,
);
final spriteRailingBgComponent = SpriteComponent(
sprite: spriteRailingBg,
size: Vector2(38.3, 35.1),
anchor: Anchor.center,
position: spriteRampComponent.position + Vector2(0, -1),
);
await addAll([
spriteRailingBgComponent,
spriteRampComponent,
]);
}
}
/// Represents the foreground of the railing upper left blue ramp.
class _SpaceshipRampForegroundRailing extends BodyComponent
with InitialPosition, Layered {
_SpaceshipRampForegroundRailing()
: super(priority: SpaceshipRamp.ballPriorityInsideRamp + 1) {
layer = Layer.spaceshipEntranceRamp;
}
List<FixtureDef> _createFixtureDefs() {
final fixturesDef = <FixtureDef>[];
final innerLeftCurveShape = BezierCurveShape(
controlPoints: [
Vector2(-24.5, 38),
Vector2(-26.3, 64),
Vector2(-13.8, 64.5),
],
);
final innerLeftCurveFixtureDef = FixtureDef(innerLeftCurveShape);
fixturesDef.add(innerLeftCurveFixtureDef);
final innerRightCurveShape = BezierCurveShape(
controlPoints: [
innerLeftCurveShape.vertices.last,
Vector2(-1, 64.5),
Vector2(0.1, 39.5),
],
);
final innerRightCurveFixtureDef = FixtureDef(innerRightCurveShape);
fixturesDef.add(innerRightCurveFixtureDef);
return fixturesDef;
}
@override
Body createBody() {
renderBody = false;
final bodyDef = BodyDef()
..userData = this
..position = initialPosition;
final body = world.createBody(bodyDef);
_createFixtureDefs().forEach(body.createFixture);
return body;
}
@override
Future<void> onLoad() async {
await super.onLoad();
await _loadSprites();
}
Future<void> _loadSprites() async {
final spriteRailingFg = await gameRef.loadSprite(
Assets.images.spaceship.ramp.railingForeground.keyName,
);
final spriteRailingFgComponent = SpriteComponent(
sprite: spriteRailingFg,
size: Vector2(26.1, 28.3),
anchor: Anchor.center,
position: Vector2(-12.2, -52.5),
);
await add(spriteRailingFgComponent);
}
}
/// Represents the ground right base of the [SpaceshipRamp].
class _SpaceshipRampBase extends BodyComponent with InitialPosition, Layered {
_SpaceshipRampBase() {
layer = Layer.board;
}
@override
Body createBody() {
renderBody = false;
const baseWidth = 6;
final baseShape = BezierCurveShape(
controlPoints: [
Vector2(initialPosition.x - baseWidth / 2, initialPosition.y),
Vector2(initialPosition.x - baseWidth / 2, initialPosition.y) +
Vector2(2, 2),
Vector2(initialPosition.x + baseWidth / 2, initialPosition.y) +
Vector2(-2, 2),
Vector2(initialPosition.x + baseWidth / 2, initialPosition.y)
],
);
final fixtureDef = FixtureDef(baseShape);
final bodyDef = BodyDef()
..userData = this
..position = initialPosition;
return world.createBody(bodyDef)..createFixture(fixtureDef);
}
}
/// {@template spaceship_ramp_opening}
/// [RampOpening] with [Layer.spaceshipEntranceRamp] to filter [Ball] collisions
/// inside [_SpaceshipRampBackground].
/// {@endtemplate}
class _SpaceshipRampOpening extends RampOpening {
/// {@macro spaceship_ramp_opening}
_SpaceshipRampOpening({
Layer? outsideLayer,
int? outsidePriority,
required double rotation,
}) : _rotation = rotation,
super(
insideLayer: Layer.spaceshipEntranceRamp,
outsideLayer: outsideLayer,
orientation: RampOrientation.down,
insidePriority: SpaceshipRamp.ballPriorityInsideRamp,
outsidePriority: outsidePriority,
);
final double _rotation;
static final Vector2 _size = Vector2(_SpaceshipRampBackground.width / 4, .1);
@override
Shape get shape {
renderBody = false;
return PolygonShape()
..setAsBox(
_size.x,
_size.y,
initialPosition,
_rotation,
);
}
}

@ -27,11 +27,17 @@ flutter:
assets:
- assets/images/
- assets/images/baseboard/
- assets/images/boundary/
- assets/images/dino/
- assets/images/flipper/
- assets/images/launch_ramp/
- assets/images/dash_bumper/a/
- assets/images/dash_bumper/b/
- assets/images/dash_bumper/main/
- assets/images/spaceship/
- assets/images/spaceship/rail/
- assets/images/spaceship/ramp/
- assets/images/chrome_dino/
flutter_gen:
line_length: 80

@ -1,2 +1,3 @@
export 'games.dart';
export 'methods.dart';
export 'trace.dart';

@ -0,0 +1,19 @@
import 'dart:async';
import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flutter/material.dart';
extension BodyTrace on BodyComponent {
void trace({Color color = const Color(0xFFFF0000)}) {
paint = Paint()..color = color;
renderBody = true;
unawaited(
mounted.whenComplete(() {
final sprite = children.whereType<SpriteComponent>().first;
sprite.paint.color = sprite.paint.color.withOpacity(0.5);
}),
);
}
}

@ -6,7 +6,6 @@
// https://opensource.org/licenses/MIT.
import 'package:dashbook/dashbook.dart';
import 'package:flutter/material.dart';
import 'package:sandbox/stories/spaceship/spaceship.dart';
import 'package:sandbox/stories/stories.dart';
void main() {
@ -18,5 +17,7 @@ void main() {
addFlipperStories(dashbook);
addSpaceshipStories(dashbook);
addBaseboardStories(dashbook);
addChromeDinoStories(dashbook);
addDashNestBumperStories(dashbook);
runApp(dashbook);
}

@ -3,8 +3,12 @@ import 'package:flutter/material.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/common/common.dart';
class BallBoosterExample extends LineGame {
static const info = '';
class BallBoosterGame extends LineGame {
static const info = '''
Shows how a Ball with a boost works.
Drag to launch a boosted Ball.
''';
@override
void onLine(Vector2 line) {

@ -7,9 +7,9 @@ class BasicBallGame extends BasicGame with TapDetector {
BasicBallGame({required this.color});
static const info = '''
Basic example of how a Ball works.
Shows how a Ball works.
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;

@ -2,8 +2,8 @@ import 'package:dashbook/dashbook.dart';
import 'package:flame/game.dart';
import 'package:flutter/material.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/ball/ball_booster.dart';
import 'package:sandbox/stories/ball/basic.dart';
import 'package:sandbox/stories/ball/ball_booster_game.dart';
import 'package:sandbox/stories/ball/basic_ball_game.dart';
void addBallStories(Dashbook dashbook) {
dashbook.storiesOf('Ball')
@ -20,9 +20,9 @@ void addBallStories(Dashbook dashbook) {
..add(
'Booster',
(context) => GameWidget(
game: BallBoosterExample(),
game: BallBoosterGame(),
),
codeLink: buildSourceLink('ball/ball_booster.dart'),
info: BallBoosterExample.info,
info: BallBoosterGame.info,
);
}

@ -3,9 +3,7 @@ import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/common/common.dart';
class BasicBaseboardGame extends BasicGame {
static const info = '''
Basic example of how a Baseboard works.
''';
static const info = 'Shows how a Baseboard works.';
@override
Future<void> onLoad() async {

@ -1,7 +1,7 @@
import 'package:dashbook/dashbook.dart';
import 'package:flame/game.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/baseboard/basic.dart';
import 'package:sandbox/stories/baseboard/basic_baseboard_game.dart';
void addBaseboardStories(Dashbook dashbook) {
dashbook.storiesOf('Baseboard').add(

@ -0,0 +1,14 @@
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:pinball_components/pinball_components.dart';
class ChromeDinoGame extends Forge2DGame {
static const info = 'Shows how a ChromeDino is rendered.';
@override
Future<void> onLoad() async {
await super.onLoad();
camera.followVector2(Vector2.zero());
await add(ChromeDino());
}
}

@ -0,0 +1,15 @@
import 'package:dashbook/dashbook.dart';
import 'package:flame/game.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/chrome_dino/chrome_dino_game.dart';
void addChromeDinoStories(Dashbook dashbook) {
dashbook.storiesOf('Chrome Dino').add(
'Basic',
(context) => GameWidget(
game: ChromeDinoGame(),
),
codeLink: buildSourceLink('chrome_dino/basic.dart'),
info: ChromeDinoGame.info,
);
}

@ -0,0 +1,33 @@
import 'dart:async';
import 'dart:ui';
import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/ball/basic_ball_game.dart';
class BigDashNestBumperGame extends BasicBallGame {
BigDashNestBumperGame({
required this.trace,
}) : super(color: const Color(0xFF0000FF));
static const info = '''
Shows how a BigDashNestBumper is rendered.
Activate the "trace" parameter to overlay the body.
''';
final bool trace;
@override
Future<void> onLoad() async {
await super.onLoad();
final center = screenToWorld(camera.viewport.canvasSize! / 2);
final bigDashNestBumper = BigDashNestBumper()
..initialPosition = center
..priority = 1;
await add(bigDashNestBumper);
if (trace) bigDashNestBumper.trace();
}
}

@ -0,0 +1,18 @@
import 'package:dashbook/dashbook.dart';
import 'package:flame/game.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/ball/basic_ball_game.dart';
import 'package:sandbox/stories/dash_nest_bumper/big_dash_nest_bumper_game.dart';
void addDashNestBumperStories(Dashbook dashbook) {
dashbook.storiesOf('Dash Nest Bumpers').add(
'Big',
(context) => GameWidget(
game: BigDashNestBumperGame(
trace: context.boolProperty('Trace', true),
),
),
codeLink: buildSourceLink('dash_nest_bumper/big.dart'),
info: BasicBallGame.info,
);
}

@ -2,9 +2,12 @@ import 'package:flame/components.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/common/common.dart';
class FireEffectExample extends LineGame {
static const info = 'Demonstrate the fire trail effect '
'drag a line to define the trail direction';
class FireEffectGame extends LineGame {
static const info = '''
Shows how the FireEffect renders.
Drag a line to define the trail direction.
''';
@override
void onLine(Vector2 line) {

@ -1,13 +1,13 @@
import 'package:dashbook/dashbook.dart';
import 'package:flame/game.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/effects/fire_effect.dart';
import 'package:sandbox/stories/effects/fire_effect_game.dart';
void addEffectsStories(Dashbook dashbook) {
dashbook.storiesOf('Effects').add(
'Fire Effect',
(context) => GameWidget(game: FireEffectExample()),
(context) => GameWidget(game: FireEffectGame()),
codeLink: buildSourceLink('effects/fire_effect.dart'),
info: FireEffectExample.info,
info: FireEffectGame.info,
);
}

@ -1,26 +0,0 @@
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,70 @@
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';
class BasicFlipperGame extends BasicBallGame with KeyboardEvents {
BasicFlipperGame() : super(color: Colors.blue);
static const info = 'Shows how a Flipper works.';
static const _leftFlipperKeys = [
LogicalKeyboardKey.arrowLeft,
LogicalKeyboardKey.keyA,
];
static const _rightFlipperKeys = [
LogicalKeyboardKey.arrowRight,
LogicalKeyboardKey.keyD,
];
late Flipper leftFlipper;
late Flipper rightFlipper;
@override
Future<void> onLoad() async {
await super.onLoad();
final center = screenToWorld(camera.viewport.canvasSize! / 2);
leftFlipper = Flipper(side: BoardSide.left)
..initialPosition = center - Vector2(Flipper.size.x, 0);
rightFlipper = Flipper(side: BoardSide.right)
..initialPosition = center + Vector2(Flipper.size.x, 0);
await addAll([
leftFlipper,
rightFlipper,
]);
}
@override
KeyEventResult onKeyEvent(
RawKeyEvent event,
Set<LogicalKeyboardKey> 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;
}
}

@ -0,0 +1,26 @@
import 'dart:async';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/flipper/basic_flipper_game.dart';
class FlipperTracingGame extends BasicFlipperGame {
static const info = '''
Basic example of how the Flipper body overlays the sprite.
''';
@override
Future<void> onLoad() async {
await super.onLoad();
leftFlipper.trace();
leftFlipper.body.joints.whereType<RevoluteJoint>().forEach(
(joint) => joint.setLimits(0, 0),
);
rightFlipper.trace();
rightFlipper.body.joints.whereType<RevoluteJoint>().forEach(
(joint) => joint.setLimits(0, 0),
);
}
}

@ -1,8 +1,8 @@
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';
import 'package:sandbox/stories/flipper/basic_flipper_game.dart';
import 'package:sandbox/stories/flipper/flipper_tracing_game.dart';
void addFlipperStories(Dashbook dashbook) {
dashbook.storiesOf('Flipper')

@ -1,49 +0,0 @@
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,9 +8,9 @@ class BasicLayerGame extends BasicGame with TapDetector {
BasicLayerGame({required this.color});
static const info = '''
Basic example of how layers work when a Ball hits other components.
Shows 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;
@ -35,7 +35,7 @@ class BigSquare extends BodyComponent with InitialPosition, Layered {
paint = Paint()
..color = const Color.fromARGB(255, 8, 218, 241)
..style = PaintingStyle.stroke;
layer = Layer.jetpack;
layer = Layer.spaceshipEntranceRamp;
}
@override

@ -2,7 +2,7 @@ import 'package:dashbook/dashbook.dart';
import 'package:flame/game.dart';
import 'package:flutter/material.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/layer/basic.dart';
import 'package:sandbox/stories/layer/basic_layer_game.dart';
void addLayerStories(Dashbook dashbook) {
dashbook.storiesOf('Layer').add(

@ -5,9 +5,12 @@ import 'package:flutter/material.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:sandbox/common/common.dart';
class BasicSpaceship extends BasicGame with TapDetector {
static String info = 'Renders a spaceship and allows balls to be '
'spawned upon click to test their interactions';
class BasicSpaceshipGame extends BasicGame with TapDetector {
static const info = '''
Shows how a Spaceship works.
Tap anywhere on the screen to spawn a Ball into the game.
''';
@override
Future<void> onLoad() async {
@ -25,7 +28,7 @@ class BasicSpaceship extends BasicGame with TapDetector {
add(
Ball(baseColor: Colors.blue)
..initialPosition = info.eventPosition.game
..layer = Layer.jetpack,
..layer = Layer.spaceshipEntranceRamp,
);
}
}

@ -1,13 +1,15 @@
import 'package:dashbook/dashbook.dart';
import 'package:flame/game.dart';
import 'package:sandbox/common/common.dart';
import 'package:sandbox/stories/spaceship/basic.dart';
import 'package:sandbox/stories/spaceship/basic_spaceship_game.dart';
void addSpaceshipStories(Dashbook dashbook) {
dashbook.storiesOf('Spaceship').add(
'Basic',
(context) => GameWidget(game: BasicSpaceship()),
(context) => GameWidget(
game: BasicSpaceshipGame(),
),
codeLink: buildSourceLink('spaceship/basic.dart'),
info: BasicSpaceship.info,
info: BasicSpaceshipGame.info,
);
}

@ -1,5 +1,8 @@
export 'ball/ball.dart';
export 'baseboard/baseboard.dart';
export 'effects/effects.dart';
export 'flipper/flipper.dart';
export 'layer/layer.dart';
export 'ball/stories.dart';
export 'baseboard/stories.dart';
export 'chrome_dino/stories.dart';
export 'dash_nest_bumper/stories.dart';
export 'effects/stories.dart';
export 'flipper/stories.dart';
export 'layer/stories.dart';
export 'spaceship/stories.dart';

@ -17,6 +17,8 @@ class MockSpaceshipEntrance extends Mock implements SpaceshipEntrance {}
class MockSpaceshipHole extends Mock implements SpaceshipHole {}
class MockSpaceshipRailExit extends Mock implements SpaceshipRailExit {}
class MockContact extends Mock implements Contact {}
class MockContactCallback extends Mock

@ -0,0 +1,31 @@
// ignore_for_file: cascade_invocations
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:pinball_components/pinball_components.dart';
import '../../helpers/helpers.dart';
void main() {
group('Boundaries', () {
final tester = FlameTester(TestGame.new);
tester.testGameWidget(
'render correctly',
setUp: (game, tester) async {
await game.addFromBlueprint(Boundaries());
await game.ready();
game.camera.followVector2(Vector2.zero());
game.camera.zoom = 3.9;
},
// TODO(allisonryan0002): enable test when workflows are fixed.
// verify: (game, tester) async {
// await expectLater(
// find.byGame<Forge2DGame>(),
// matchesGoldenFile('golden/boundaries.png'),
// );
// },
);
});
}

@ -0,0 +1,38 @@
// ignore_for_file: cascade_invocations
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:pinball_components/pinball_components.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final flameTester = FlameTester(Forge2DGame.new);
group('ChromeDino', () {
flameTester.test(
'loads correctly',
(game) async {
final chromeDino = ChromeDino();
await game.ensureAdd(chromeDino);
expect(game.contains(chromeDino), isTrue);
},
);
flameTester.test(
'swivels',
(game) async {
// TODO(alestiago): Write golden tests to check the
// swivel animation.
final chromeDino = ChromeDino();
await game.ensureAdd(chromeDino);
final previousPosition = chromeDino.body.position.clone();
game.update(64);
expect(chromeDino.body.position, isNot(equals(previousPosition)));
},
);
});
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

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

@ -0,0 +1,31 @@
// ignore_for_file: cascade_invocations
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:pinball_components/pinball_components.dart';
import '../../helpers/helpers.dart';
void main() {
group('LaunchRamp', () {
final tester = FlameTester(TestGame.new);
tester.testGameWidget(
'renders correctly',
setUp: (game, tester) async {
await game.addFromBlueprint(LaunchRamp());
await game.ready();
game.camera.followVector2(Vector2.zero());
game.camera.zoom = 4.1;
},
// TODO(allisonryan0002): enable test when workflows are fixed.
// verify: (game, tester) async {
// await expectLater(
// find.byGame<Forge2DGame>(),
// matchesGoldenFile('golden/launch-ramp.png'),
// );
// },
);
});
}

@ -46,14 +46,15 @@ void main() {
});
test('correctly sets and gets', () {
final component = TestLayeredBodyComponent()..layer = Layer.jetpack;
expect(component.layer, Layer.jetpack);
final component = TestLayeredBodyComponent()
..layer = Layer.spaceshipEntranceRamp;
expect(component.layer, Layer.spaceshipEntranceRamp);
});
flameTester.test(
'layers correctly before being loaded',
(game) async {
const expectedLayer = Layer.jetpack;
const expectedLayer = Layer.spaceshipEntranceRamp;
final component = TestLayeredBodyComponent()..layer = expectedLayer;
await game.ensureAdd(component);
// TODO(alestiago): modify once component.loaded is available.
@ -71,7 +72,8 @@ void main() {
'when multiple different sets',
(game) async {
const expectedLayer = Layer.launcher;
final component = TestLayeredBodyComponent()..layer = Layer.jetpack;
final component = TestLayeredBodyComponent()
..layer = Layer.spaceshipEntranceRamp;
expect(component.layer, isNot(equals(expectedLayer)));
component.layer = expectedLayer;
@ -90,7 +92,7 @@ void main() {
flameTester.test(
'layers correctly after being loaded',
(game) async {
const expectedLayer = Layer.jetpack;
const expectedLayer = Layer.spaceshipEntranceRamp;
final component = TestLayeredBodyComponent();
await game.ensureAdd(component);
component.layer = expectedLayer;
@ -109,7 +111,7 @@ void main() {
final component = TestLayeredBodyComponent();
await game.ensureAdd(component);
component.layer = Layer.jetpack;
component.layer = Layer.spaceshipEntranceRamp;
expect(component.layer, isNot(equals(expectedLayer)));
component.layer = expectedLayer;
@ -133,7 +135,7 @@ void main() {
flameTester.test(
'nested Layered children will keep their layer',
(game) async {
const parentLayer = Layer.jetpack;
const parentLayer = Layer.spaceshipEntranceRamp;
const childLayer = Layer.board;
final component = TestLayeredBodyComponent()..layer = parentLayer;
@ -152,7 +154,7 @@ void main() {
flameTester.test(
'nested children will keep their layer',
(game) async {
const parentLayer = Layer.jetpack;
const parentLayer = Layer.spaceshipEntranceRamp;
final component = TestLayeredBodyComponent()..layer = parentLayer;
final childComponent = TestBodyComponent();

@ -44,7 +44,7 @@ void main() {
(game) async {
final ramp = TestRampOpening(
orientation: RampOrientation.down,
pathwayLayer: Layer.jetpack,
pathwayLayer: Layer.spaceshipEntranceRamp,
);
await game.ready();
await game.ensureAdd(ramp);
@ -59,7 +59,7 @@ void main() {
(game) async {
final ramp = TestRampOpening(
orientation: RampOrientation.down,
pathwayLayer: Layer.jetpack,
pathwayLayer: Layer.spaceshipEntranceRamp,
);
await game.ensureAdd(ramp);
@ -68,7 +68,7 @@ void main() {
);
group('first fixture', () {
const pathwayLayer = Layer.jetpack;
const pathwayLayer = Layer.spaceshipEntranceRamp;
const openingLayer = Layer.opening;
flameTester.test(
@ -124,7 +124,7 @@ void main() {
final body = MockBody();
final area = TestRampOpening(
orientation: RampOrientation.down,
pathwayLayer: Layer.jetpack,
pathwayLayer: Layer.spaceshipEntranceRamp,
);
final callback = TestRampOpeningBallContactCallback();
@ -145,7 +145,7 @@ void main() {
final body = MockBody();
final area = TestRampOpening(
orientation: RampOrientation.up,
pathwayLayer: Layer.jetpack,
pathwayLayer: Layer.spaceshipEntranceRamp,
);
final callback = TestRampOpeningBallContactCallback();
@ -165,7 +165,7 @@ void main() {
final body = MockBody();
final area = TestRampOpening(
orientation: RampOrientation.down,
pathwayLayer: Layer.jetpack,
pathwayLayer: Layer.spaceshipEntranceRamp,
)..initialPosition = Vector2(0, 10);
final callback = TestRampOpeningBallContactCallback();
@ -189,7 +189,7 @@ void main() {
final body = MockBody();
final area = TestRampOpening(
orientation: RampOrientation.up,
pathwayLayer: Layer.jetpack,
pathwayLayer: Layer.spaceshipEntranceRamp,
)..initialPosition = Vector2(0, 10);
final callback = TestRampOpeningBallContactCallback();
@ -213,7 +213,7 @@ void main() {
final body = MockBody();
final area = TestRampOpening(
orientation: RampOrientation.down,
pathwayLayer: Layer.jetpack,
pathwayLayer: Layer.spaceshipEntranceRamp,
)..initialPosition = Vector2(0, 10);
final callback = TestRampOpeningBallContactCallback();

@ -0,0 +1,82 @@
// ignore_for_file: cascade_invocations
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';
import '../../helpers/helpers.dart';
void main() {
group('SpaceshipRail', () {
TestWidgetsFlutterBinding.ensureInitialized();
final flameTester = FlameTester(TestGame.new);
flameTester.test(
'loads correctly',
(game) async {
final spaceshipRail = SpaceshipRail();
await game.addFromBlueprint(spaceshipRail);
await game.ready();
for (final element in spaceshipRail.components) {
expect(game.contains(element), isTrue);
}
},
);
});
// TODO(alestiago): Make ContactCallback private and use `beginContact`
// instead.
group('SpaceshipRailExitBallContactCallback', () {
late Forge2DGame game;
late SpaceshipRailExit railExit;
late Ball ball;
late Body body;
late Fixture fixture;
late Filter filterData;
setUp(() {
game = MockGame();
railExit = MockSpaceshipRailExit();
ball = MockBall();
body = MockBody();
when(() => ball.gameRef).thenReturn(game);
when(() => ball.body).thenReturn(body);
fixture = MockFixture();
filterData = MockFilter();
when(() => body.fixtures).thenReturn([fixture]);
when(() => fixture.filterData).thenReturn(filterData);
});
setUp(() {
when(() => ball.priority).thenReturn(1);
when(() => railExit.outsideLayer).thenReturn(Layer.board);
when(() => railExit.outsidePriority).thenReturn(0);
});
test('changes the ball priority on contact', () {
SpaceshipRailExitBallContactCallback().begin(
railExit,
ball,
MockContact(),
);
verify(() => ball.sendTo(railExit.outsidePriority)).called(1);
});
test('changes the ball layer on contact', () {
SpaceshipRailExitBallContactCallback().begin(
railExit,
ball,
MockContact(),
);
verify(() => ball.layer = railExit.outsideLayer).called(1);
});
});
}

@ -0,0 +1,27 @@
// ignore_for_file: cascade_invocations
import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:pinball_components/pinball_components.dart';
import '../../helpers/helpers.dart';
void main() {
group('SpaceshipRamp', () {
TestWidgetsFlutterBinding.ensureInitialized();
final flameTester = FlameTester(TestGame.new);
flameTester.test(
'loads correctly',
(game) async {
final spaceshipEntranceRamp = SpaceshipRamp();
await game.addFromBlueprint(spaceshipEntranceRamp);
await game.ready();
for (final element in spaceshipEntranceRamp.components) {
expect(game.contains(element), isTrue);
}
},
);
});
}

@ -1,23 +0,0 @@
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:pinball/game/game.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final flameTester = FlameTester(Forge2DGame.new);
group('ChromeDino', () {
flameTester.test(
'loads correctly',
(game) async {
final chromeDino = ChromeDino();
await game.ready();
await game.ensureAdd(chromeDino);
expect(game.contains(chromeDino), isTrue);
},
);
});
}

@ -176,7 +176,7 @@ void main() {
await game.ensureAdd(ball);
final state = MockGameState();
when(() => state.balls).thenReturn(1);
when(() => state.balls).thenReturn(0);
final previousBalls = game.descendants().whereType<Ball>().toList();
controller.onNewState(state);

@ -1,60 +0,0 @@
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:pinball/game/game.dart';
import 'package:pinball_components/pinball_components.dart';
import '../../helpers/helpers.dart';
void main() {
group('SpaceshipExitRail', () {
late PinballGame game;
late SpaceshipExitRailEnd exitRailEnd;
late Ball ball;
late Body body;
late Fixture fixture;
late Filter filterData;
setUp(() {
game = MockPinballGame();
exitRailEnd = MockSpaceshipExitRailEnd();
ball = MockBall();
body = MockBody();
when(() => ball.gameRef).thenReturn(game);
when(() => ball.body).thenReturn(body);
fixture = MockFixture();
filterData = MockFilter();
when(() => body.fixtures).thenReturn([fixture]);
when(() => fixture.filterData).thenReturn(filterData);
});
group('SpaceshipExitHoleBallContactCallback', () {
test('changes the ball priority on contact', () {
when(() => exitRailEnd.outsideLayer).thenReturn(Layer.board);
SpaceshipExitRailEndBallContactCallback().begin(
exitRailEnd,
ball,
MockContact(),
);
verify(() => ball.priority = 1).called(1);
});
test('reorders the game children', () {
when(() => exitRailEnd.outsideLayer).thenReturn(Layer.board);
SpaceshipExitRailEndBallContactCallback().begin(
exitRailEnd,
ball,
MockContact(),
);
verify(game.reorderChildren).called(1);
});
});
});
}

@ -67,8 +67,6 @@ class MockFilter extends Mock implements Filter {}
class MockFixture extends Mock implements Fixture {}
class MockSpaceshipExitRailEnd extends Mock implements SpaceshipExitRailEnd {}
class MockComponentSet extends Mock implements ComponentSet {}
class MockDashNestBumper extends Mock implements DashNestBumper {}

Loading…
Cancel
Save