Merge branch 'main' into feat/dash-bumper-sandbox

pull/137/head
Allison Ryan 4 years ago committed by GitHub
commit bcef043173
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -3,7 +3,6 @@ export 'bonus_word.dart';
export 'controlled_ball.dart';
export 'controlled_flipper.dart';
export 'flutter_forest.dart';
export 'launcher_ramp.dart';
export 'plunger.dart';
export 'score_points.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,142 +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,
insidePriority: 3,
);
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;

@ -13,6 +13,12 @@ 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.spaceshipSaucer.keyName),
images.load(components.Assets.images.spaceshipBridge.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 +27,8 @@ 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.spaceshipRamp.spaceshipRamp.keyName),
images.load(
components.Assets.images.spaceshipRamp.spaceshipRailingBg.keyName,

@ -33,9 +33,10 @@ class PinballGame extends Forge2DGame
await _addGameBoundaries();
unawaited(add(Board()));
unawaited(addFromBlueprint(Boundaries()));
unawaited(_addPlunger());
unawaited(_addBonusWord());
unawaited(_addPaths());
unawaited(_addRamps());
unawaited(
addFromBlueprint(
Spaceship(
@ -91,9 +92,9 @@ class PinballGame extends Forge2DGame
);
}
Future<void> _addPaths() async {
Future<void> _addRamps() async {
unawaited(addFromBlueprint(SpaceshipRamp()));
unawaited(addFromBlueprint(Launcher()));
unawaited(addFromBlueprint(LaunchRamp()));
}
void spawnBall() {
@ -128,7 +129,7 @@ class DebugPinballGame extends PinballGame with TapDetector {
anchor: Anchor.center,
)
..position = Vector2(0, -7.8)
..priority = -1;
..priority = -2;
await add(spriteComponent);
}

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: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

@ -14,6 +14,7 @@ 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 =>
@ -25,6 +26,9 @@ class $AssetsImagesGen {
AssetGenImage get flutterSignPost =>
const AssetGenImage('assets/images/flutter_sign_post.png');
$AssetsImagesLaunchRampGen get launchRamp =>
const $AssetsImagesLaunchRampGen();
/// File path: assets/images/spaceship_bridge.png
AssetGenImage get spaceshipBridge =>
const AssetGenImage('assets/images/spaceship_bridge.png');
@ -49,6 +53,18 @@ 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();
@ -94,6 +110,18 @@ 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 $AssetsImagesSpaceshipRampGen {
const $AssetsImagesSpaceshipRampGen();

@ -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),
),
);
}
}

@ -2,6 +2,7 @@ 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';
@ -11,6 +12,7 @@ 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';

@ -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,
);
}

@ -27,8 +27,10 @@ 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/

@ -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'),
// );
// },
);
});
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

@ -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'),
// );
// },
);
});
}

@ -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);

Loading…
Cancel
Save