diff --git a/assets/images/components/spaceship_railing_bg.png b/assets/images/components/spaceship_railing_bg.png new file mode 100644 index 00000000..2298f799 Binary files /dev/null and b/assets/images/components/spaceship_railing_bg.png differ diff --git a/assets/images/components/spaceship_railing_fg.png b/assets/images/components/spaceship_railing_fg.png new file mode 100644 index 00000000..e788fde0 Binary files /dev/null and b/assets/images/components/spaceship_railing_fg.png differ diff --git a/assets/images/components/spaceship_ramp.png b/assets/images/components/spaceship_ramp.png new file mode 100644 index 00000000..81498965 Binary files /dev/null and b/assets/images/components/spaceship_ramp.png differ diff --git a/lib/game/components/jetpack_ramp.dart b/lib/game/components/jetpack_ramp.dart index aa5a9dbd..34b00dd4 100644 --- a/lib/game/components/jetpack_ramp.dart +++ b/lib/game/components/jetpack_ramp.dart @@ -2,45 +2,52 @@ import 'dart:math' as math; -import 'package:flame/extensions.dart'; +import 'package:flame/components.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'; +import 'package:pinball/gen/assets.gen.dart'; +import 'package:pinball_components/pinball_components.dart' hide Assets; /// A [Blueprint] which creates the [JetpackRamp]. class Jetpack extends Forge2DBlueprint { + /// {@macro spaceship} + Jetpack(); + + static const int ballPriorityInsideRamp = 4; + @override void build(_) { - final position = Vector2( - BoardDimensions.bounds.left + 40.5, - BoardDimensions.bounds.top - 31.5, - ); - addAllContactCallback([ RampOpeningBallContactCallback<_JetpackRampOpening>(), ]); final rightOpening = _JetpackRampOpening( + // TODO(ruimiguel): set Board priority when defined. + outsidePriority: 1, rotation: math.pi, ) - ..initialPosition = position + Vector2(12.9, -20) + ..initialPosition = Vector2(1.7, 19) ..layer = Layer.opening; final leftOpening = _JetpackRampOpening( outsideLayer: Layer.spaceship, + outsidePriority: Spaceship.ballPriorityWhenOnSpaceship, rotation: math.pi, ) - ..initialPosition = position + Vector2(-2.5, -20) + ..initialPosition = Vector2(-13.7, 19) ..layer = Layer.jetpack; - final jetpackRamp = JetpackRamp() - ..initialPosition = position + Vector2(5, -20.2) - ..layer = Layer.jetpack; + final jetpackRamp = JetpackRamp(); + + final jetpackRampWallFg = _JetpackRampForegroundRailing(); + + final baseRight = _JetpackBase()..initialPosition = Vector2(1.7, 20); addAll([ rightOpening, leftOpening, + baseRight, jetpackRamp, + jetpackRampWallFg, ]); } } @@ -49,42 +56,129 @@ class Jetpack extends Forge2DBlueprint { /// Represents the upper left blue ramp of the [Board]. /// {@endtemplate} class JetpackRamp extends BodyComponent with InitialPosition, Layered { - JetpackRamp() : super(priority: 2) { + JetpackRamp() : super(priority: Jetpack.ballPriorityInsideRamp - 1) { 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 _createFixtureDefs() { final fixturesDef = []; - final externalCurveShape = ArcShape( - center: initialPosition, - arcRadius: _externalRadius, - angle: math.pi, - rotation: math.pi, + 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 onLoad() async { + await super.onLoad(); + await _loadSprites(); + } + + Future _loadSprites() async { + final spriteRamp = await gameRef.loadSprite( + Assets.images.components.spaceshipRamp.path, + ); + + 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.components.spaceshipRailingBg.path, + ); + final spriteRailingBgComponent = SpriteComponent( + sprite: spriteRailingBg, + size: Vector2(38.3, 35.1), + anchor: Anchor.center, + position: spriteRampComponent.position + Vector2(0, -1), ); - final externalFixtureDef = FixtureDef(externalCurveShape); - fixturesDef.add(externalFixtureDef); - final internalCurveShape = externalCurveShape.copyWith( - arcRadius: _externalRadius - width, + await addAll([ + spriteRailingBgComponent, + spriteRampComponent, + ]); + } +} + +class _JetpackRampForegroundRailing extends BodyComponent + with InitialPosition, Layered { + _JetpackRampForegroundRailing() + : super(priority: Jetpack.ballPriorityInsideRamp + 1) { + layer = Layer.jetpack; + } + + List _createFixtureDefs() { + final fixturesDef = []; + + final innerLeftCurveShape = BezierCurveShape( + controlPoints: [ + Vector2(-24.5, 38), + Vector2(-26.3, 64), + Vector2(-13.8, 64.5), + ], ); - final internalFixtureDef = FixtureDef(internalCurveShape); - fixturesDef.add(internalFixtureDef); + + 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; @@ -94,6 +188,56 @@ class JetpackRamp extends BodyComponent with InitialPosition, Layered { return body; } + + @override + Future onLoad() async { + await super.onLoad(); + await _loadSprites(); + } + + Future _loadSprites() async { + final spriteRailingFg = await gameRef.loadSprite( + Assets.images.components.spaceshipRailingFg.path, + ); + final spriteRailingFgComponent = SpriteComponent( + sprite: spriteRailingFg, + size: Vector2(26.1, 28.3), + anchor: Anchor.center, + position: Vector2(-12.2, -52.5), + ); + + await add(spriteRailingFgComponent); + } +} + +class _JetpackBase extends BodyComponent with InitialPosition, Layered { + _JetpackBase() { + 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 jetpack_ramp_opening} @@ -104,12 +248,15 @@ class _JetpackRampOpening extends RampOpening { /// {@macro jetpack_ramp_opening} _JetpackRampOpening({ Layer? outsideLayer, + int? outsidePriority, required double rotation, }) : _rotation = rotation, super( insideLayer: Layer.jetpack, outsideLayer: outsideLayer, orientation: RampOrientation.down, + insidePriority: Jetpack.ballPriorityInsideRamp, + outsidePriority: outsidePriority, ); final double _rotation; @@ -117,11 +264,14 @@ class _JetpackRampOpening extends RampOpening { static final Vector2 _size = Vector2(JetpackRamp.width / 4, .1); @override - Shape get shape => PolygonShape() - ..setAsBox( - _size.x, - _size.y, - initialPosition, - _rotation, - ); + Shape get shape { + renderBody = false; + return PolygonShape() + ..setAsBox( + _size.x, + _size.y, + initialPosition, + _rotation, + ); + } } diff --git a/lib/game/components/launcher_ramp.dart b/lib/game/components/launcher_ramp.dart index c05f8aa2..5c071f4f 100644 --- a/lib/game/components/launcher_ramp.dart +++ b/lib/game/components/launcher_ramp.dart @@ -124,6 +124,7 @@ class _LauncherRampOpening extends RampOpening { super( insideLayer: Layer.launcher, orientation: RampOrientation.down, + insidePriority: 3, ); final double _rotation; diff --git a/lib/game/components/spaceship_exit_rail.dart b/lib/game/components/spaceship_exit_rail.dart index fed97e0e..e4be9b31 100644 --- a/lib/game/components/spaceship_exit_rail.dart +++ b/lib/game/components/spaceship_exit_rail.dart @@ -191,6 +191,7 @@ class SpaceshipExitRailEnd extends RampOpening { : super( insideLayer: Layer.spaceshipExitRail, orientation: RampOrientation.down, + insidePriority: 3, ) { renderBody = false; layer = Layer.spaceshipExitRail; diff --git a/lib/game/game_assets.dart b/lib/game/game_assets.dart index e0d25592..dcb740a1 100644 --- a/lib/game/game_assets.dart +++ b/lib/game/game_assets.dart @@ -22,6 +22,9 @@ extension PinballGameAssetsX on PinballGame { images.load(components.Assets.images.dashBumper.main.active.keyName), images.load(components.Assets.images.dashBumper.main.inactive.keyName), images.load(Assets.images.components.background.path), + images.load(Assets.images.components.spaceshipRamp.path), + images.load(Assets.images.components.spaceshipRailingBg.path), + images.load(Assets.images.components.spaceshipRailingFg.path), images.load(Assets.images.components.spaceshipDropTube.path), ]); } diff --git a/lib/game/pinball_game.dart b/lib/game/pinball_game.dart index 0711e677..095a5f53 100644 --- a/lib/game/pinball_game.dart +++ b/lib/game/pinball_game.dart @@ -92,7 +92,9 @@ class PinballGame extends Forge2DGame } Future _addPaths() async { - unawaited(addFromBlueprint(Jetpack())); + unawaited( + addFromBlueprint(Jetpack()), + ); unawaited(addFromBlueprint(Launcher())); } diff --git a/lib/gen/assets.gen.dart b/lib/gen/assets.gen.dart index 2fe23925..7796df34 100644 --- a/lib/gen/assets.gen.dart +++ b/lib/gen/assets.gen.dart @@ -24,6 +24,18 @@ class $AssetsImagesComponentsGen { /// File path: assets/images/components/spaceship-drop-tube.png AssetGenImage get spaceshipDropTube => const AssetGenImage('assets/images/components/spaceship-drop-tube.png'); + + /// File path: assets/images/components/spaceship_railing_bg.png + AssetGenImage get spaceshipRailingBg => + const AssetGenImage('assets/images/components/spaceship_railing_bg.png'); + + /// File path: assets/images/components/spaceship_railing_fg.png + AssetGenImage get spaceshipRailingFg => + const AssetGenImage('assets/images/components/spaceship_railing_fg.png'); + + /// File path: assets/images/components/spaceship_ramp.png + AssetGenImage get spaceshipRamp => + const AssetGenImage('assets/images/components/spaceship_ramp.png'); } class Assets { diff --git a/packages/pinball_components/lib/src/components/spaceship.dart b/packages/pinball_components/lib/src/components/spaceship.dart index 59f1037a..588c0e33 100644 --- a/packages/pinball_components/lib/src/components/spaceship.dart +++ b/packages/pinball_components/lib/src/components/spaceship.dart @@ -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;