feat: spaceship ramp final assets (#207)

* refactor: updated spaceship ramp assets

* "feat: added spritecomponent for arrow"

* test: tests for spaceship ramp

* refactor: spaceship ramp tests

* chore: trailing commas

* refactor: updated assets for ramp main and opening

* Update packages/pinball_components/lib/src/components/spaceship_ramp.dart

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

* Update packages/pinball_components/lib/src/components/spaceship_ramp.dart

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

* chore: changed visibility, some comments

* test: golden tests for ramp

* test: refactored tests for spaceshipramp

* refactor: make arrow accesible

* refactor: changed arrow assets filenames

* refactor: changed arrow assets filenames

* chore: doc for arrow sprites state

* test: removed pump

* refactor: load images from cache

* test: refactor test with cached images

* refactor: fir spaceship ramp entrance"

* refactor: new priority for ramp arrow and fix comments

* test: ramp assets

* refactor: spaceship sandbox refactored to see arrow behaviour

* test: assets for tests

Co-authored-by: Allison Ryan <77211884+allisonryan0002@users.noreply.github.com>
pull/214/head
Rui Miguel Alonso 2 years ago committed by GitHub
parent 9615d6105f
commit 5889ca8379
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -41,13 +41,30 @@ extension PinballGameAssetsX on PinballGame {
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.boardOpening.keyName),
images.load(
components.Assets.images.spaceship.ramp.railingForeground.keyName,
),
images.load(
components.Assets.images.spaceship.ramp.railingBackground.keyName,
),
images.load(components.Assets.images.spaceship.ramp.main.keyName),
images
.load(components.Assets.images.spaceship.ramp.arrow.inactive.keyName),
images.load(
components.Assets.images.spaceship.ramp.railingForeground.keyName,
components.Assets.images.spaceship.ramp.arrow.active1.keyName,
),
images.load(
components.Assets.images.spaceship.ramp.arrow.active2.keyName,
),
images.load(
components.Assets.images.spaceship.ramp.arrow.active3.keyName,
),
images.load(
components.Assets.images.spaceship.ramp.arrow.active4.keyName,
),
images.load(
components.Assets.images.spaceship.ramp.arrow.active5.keyName,
),
images.load(components.Assets.images.spaceship.rail.main.keyName),
images.load(components.Assets.images.spaceship.rail.foreground.keyName),

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 19 KiB

@ -311,6 +311,9 @@ class $AssetsImagesSpaceshipRailGen {
class $AssetsImagesSpaceshipRampGen {
const $AssetsImagesSpaceshipRampGen();
$AssetsImagesSpaceshipRampArrowGen get arrow =>
const $AssetsImagesSpaceshipRampArrowGen();
/// File path: assets/images/spaceship/ramp/board-opening.png
AssetGenImage get boardOpening =>
const AssetGenImage('assets/images/spaceship/ramp/board-opening.png');
@ -384,6 +387,34 @@ class $AssetsImagesDashBumperMainGen {
const AssetGenImage('assets/images/dash/bumper/main/inactive.png');
}
class $AssetsImagesSpaceshipRampArrowGen {
const $AssetsImagesSpaceshipRampArrowGen();
/// File path: assets/images/spaceship/ramp/arrow/active1.png
AssetGenImage get active1 =>
const AssetGenImage('assets/images/spaceship/ramp/arrow/active1.png');
/// File path: assets/images/spaceship/ramp/arrow/active2.png
AssetGenImage get active2 =>
const AssetGenImage('assets/images/spaceship/ramp/arrow/active2.png');
/// File path: assets/images/spaceship/ramp/arrow/active3.png
AssetGenImage get active3 =>
const AssetGenImage('assets/images/spaceship/ramp/arrow/active3.png');
/// File path: assets/images/spaceship/ramp/arrow/active4.png
AssetGenImage get active4 =>
const AssetGenImage('assets/images/spaceship/ramp/arrow/active4.png');
/// File path: assets/images/spaceship/ramp/arrow/active5.png
AssetGenImage get active5 =>
const AssetGenImage('assets/images/spaceship/ramp/arrow/active5.png');
/// File path: assets/images/spaceship/ramp/arrow/inactive.png
AssetGenImage get inactive =>
const AssetGenImage('assets/images/spaceship/ramp/arrow/inactive.png');
}
class $AssetsImagesSparkyBumperAGen {
const $AssetsImagesSparkyBumperAGen();

@ -101,6 +101,8 @@ abstract class RenderPriority {
static const int spaceshipRampBackgroundRailing = _above + spaceshipRamp;
static const int spaceshipRampArrow = _above + spaceshipRamp;
static const int spaceshipRampForegroundRailing =
_above + ballOnSpaceshipRamp;

@ -4,6 +4,7 @@ import 'dart:math' as math;
import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flutter/material.dart';
import 'package:pinball_components/gen/assets.gen.dart';
import 'package:pinball_components/pinball_components.dart' hide Assets;
import 'package:pinball_flame/pinball_flame.dart';
@ -15,6 +16,15 @@ class SpaceshipRamp extends Forge2DBlueprint {
/// {@macro spaceship_ramp}
SpaceshipRamp();
/// [SpriteGroupComponent] representing the arrow that lights up.
@visibleForTesting
late final SpaceshipRampArrowSpriteComponent spaceshipRampArrow;
/// Forwards the sprite to the next [SpaceshipRampArrowSpriteState].
///
/// If the current state is the last one it cycles back to the initial state.
void progress() => spaceshipRampArrow.progress();
@override
void build(_) {
addAllContactCallback([
@ -23,20 +33,22 @@ class SpaceshipRamp extends Forge2DBlueprint {
final rightOpening = _SpaceshipRampOpening(
outsidePriority: RenderPriority.ballOnBoard,
rotation: math.pi,
rotation: -5 * math.pi / 180,
)
..initialPosition = Vector2(1.7, -19.8)
..initialPosition = Vector2(1.7, -19.12)
..layer = Layer.opening;
final leftOpening = _SpaceshipRampOpening(
outsideLayer: Layer.spaceship,
outsidePriority: RenderPriority.ballOnSpaceship,
rotation: math.pi,
rotation: -5 * math.pi / 180,
)
..initialPosition = Vector2(-13.7, -18.6)
..initialPosition = Vector2(-13.7, -19)
..layer = Layer.spaceshipEntranceRamp;
final spaceshipRamp = _SpaceshipRampBackground();
spaceshipRampArrow = SpaceshipRampArrowSpriteComponent();
final spaceshipRampBoardOpeningSprite =
_SpaceshipRampBoardOpeningSpriteComponent()
..position = Vector2(3.4, -39.5);
@ -52,15 +64,69 @@ class SpaceshipRamp extends Forge2DBlueprint {
baseRight,
_SpaceshipRampBackgroundRailingSpriteComponent(),
spaceshipRamp,
spaceshipRampArrow,
spaceshipRampForegroundRailing,
]);
}
}
/// Indicates the state of the arrow on the [SpaceshipRamp].
@visibleForTesting
enum SpaceshipRampArrowSpriteState {
/// Arrow with no dashes lit up.
inactive,
/// Arrow with 1 light lit up.
active1,
/// Arrow with 2 lights lit up.
active2,
/// Arrow with 3 lights lit up.
active3,
/// Arrow with 4 lights lit up.
active4,
/// Arrow with all 5 lights lit up.
active5,
}
extension on SpaceshipRampArrowSpriteState {
String get path {
switch (this) {
case SpaceshipRampArrowSpriteState.inactive:
return Assets.images.spaceship.ramp.arrow.inactive.keyName;
case SpaceshipRampArrowSpriteState.active1:
return Assets.images.spaceship.ramp.arrow.active1.keyName;
case SpaceshipRampArrowSpriteState.active2:
return Assets.images.spaceship.ramp.arrow.active2.keyName;
case SpaceshipRampArrowSpriteState.active3:
return Assets.images.spaceship.ramp.arrow.active3.keyName;
case SpaceshipRampArrowSpriteState.active4:
return Assets.images.spaceship.ramp.arrow.active4.keyName;
case SpaceshipRampArrowSpriteState.active5:
return Assets.images.spaceship.ramp.arrow.active5.keyName;
}
}
SpaceshipRampArrowSpriteState get next {
return SpaceshipRampArrowSpriteState
.values[(index + 1) % SpaceshipRampArrowSpriteState.values.length];
}
}
class _SpaceshipRampBackground extends BodyComponent
with InitialPosition, Layered {
_SpaceshipRampBackground() : super(priority: RenderPriority.spaceshipRamp) {
_SpaceshipRampBackground()
: super(
priority: RenderPriority.spaceshipRamp,
children: [
_SpaceshipRampBackgroundRampSpriteComponent(),
],
) {
layer = Layer.spaceshipEntranceRamp;
renderBody = false;
}
/// Width between walls of the ramp.
@ -112,30 +178,26 @@ class _SpaceshipRampBackground extends BodyComponent
return body;
}
@override
Future<void> onLoad() async {
await super.onLoad();
renderBody = false;
await add(_SpaceshipRampBackgroundRampSpriteComponent());
}
}
class _SpaceshipRampBackgroundRailingSpriteComponent extends SpriteComponent
with HasGameRef {
_SpaceshipRampBackgroundRailingSpriteComponent()
: super(priority: RenderPriority.spaceshipRampBackgroundRailing);
: super(
anchor: Anchor.center,
position: Vector2(-11.7, -54.3),
priority: RenderPriority.spaceshipRampBackgroundRailing,
);
@override
Future<void> onLoad() async {
await super.onLoad();
final sprite = await gameRef.loadSprite(
Assets.images.spaceship.ramp.railingBackground.keyName,
final sprite = Sprite(
gameRef.images.fromCache(
Assets.images.spaceship.ramp.railingBackground.keyName,
),
);
this.sprite = sprite;
size = sprite.originalSize / 10;
anchor = Anchor.center;
position = Vector2(-11.7, -54.3);
}
}
@ -144,13 +206,50 @@ class _SpaceshipRampBackgroundRampSpriteComponent extends SpriteComponent
@override
Future<void> onLoad() async {
await super.onLoad();
final sprite = await gameRef.loadSprite(
Assets.images.spaceship.ramp.main.keyName,
final sprite = Sprite(
gameRef.images.fromCache(
Assets.images.spaceship.ramp.main.keyName,
),
);
this.sprite = sprite;
size = sprite.originalSize / 10;
anchor = Anchor.center;
position = Vector2(-11.7, -53.6);
position = Vector2(-10.7, -53.6);
}
}
/// {@template spaceship_ramp_arrow_sprite_component}
/// An arrow inside [SpaceshipRamp].
///
/// Lights up a each dash whenever a [Ball] gets into [SpaceshipRamp].
/// {@endtemplate}
class SpaceshipRampArrowSpriteComponent
extends SpriteGroupComponent<SpaceshipRampArrowSpriteState>
with HasGameRef {
/// {@macro spaceship_ramp_arrow_sprite_component}
SpaceshipRampArrowSpriteComponent()
: super(
anchor: Anchor.center,
position: Vector2(-3.9, -56.5),
priority: RenderPriority.spaceshipRampArrow,
);
/// Changes arrow image to the next [Sprite].
void progress() => current = current?.next;
@override
Future<void> onLoad() async {
await super.onLoad();
final sprites = <SpaceshipRampArrowSpriteState, Sprite>{};
this.sprites = sprites;
for (final spriteState in SpaceshipRampArrowSpriteState.values) {
sprites[spriteState] = Sprite(
gameRef.images.fromCache(spriteState.path),
);
}
current = SpaceshipRampArrowSpriteState.inactive;
size = sprites[current]!.originalSize / 10;
}
}
@ -159,8 +258,10 @@ class _SpaceshipRampBoardOpeningSpriteComponent extends SpriteComponent
@override
Future<void> onLoad() async {
await super.onLoad();
final sprite = await gameRef.loadSprite(
Assets.images.spaceship.ramp.boardOpening.keyName,
final sprite = Sprite(
gameRef.images.fromCache(
Assets.images.spaceship.ramp.boardOpening.keyName,
),
);
this.sprite = sprite;
size = sprite.originalSize / 10;
@ -231,16 +332,22 @@ class _SpaceshipRampForegroundRailing extends BodyComponent
class _SpaceshipRampForegroundRailingSpriteComponent extends SpriteComponent
with HasGameRef {
_SpaceshipRampForegroundRailingSpriteComponent()
: super(
anchor: Anchor.center,
position: Vector2(-12.3, -52.5),
);
@override
Future<void> onLoad() async {
await super.onLoad();
final sprite = await gameRef.loadSprite(
Assets.images.spaceship.ramp.railingForeground.keyName,
final sprite = Sprite(
gameRef.images.fromCache(
Assets.images.spaceship.ramp.railingForeground.keyName,
),
);
this.sprite = sprite;
size = sprite.originalSize / 10;
anchor = Anchor.center;
position = Vector2(-12.3, -52.5);
}
}

@ -52,6 +52,7 @@ flutter:
- assets/images/spaceship/
- assets/images/spaceship/rail/
- assets/images/spaceship/ramp/
- assets/images/spaceship/ramp/arrow/
- assets/images/chrome_dino/
- assets/images/kicker/
- assets/images/plunger/

@ -2,11 +2,12 @@ import 'dart:async';
import 'package:flame/input.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:pinball_components/pinball_components.dart';
import 'package:pinball_flame/pinball_flame.dart';
import 'package:sandbox/stories/ball/basic_ball_game.dart';
class SpaceshipRampGame extends BasicBallGame {
class SpaceshipRampGame extends BasicBallGame with KeyboardEvents {
SpaceshipRampGame()
: super(
color: Colors.blue,
@ -19,13 +20,45 @@ class SpaceshipRampGame extends BasicBallGame {
- Activate the "trace" parameter to overlay the body.
- Tap anywhere on the screen to spawn a ball into the game.
- Press space to progress arrow sprites.
''';
late final SpaceshipRamp _spaceshipRamp;
@override
Future<void> onLoad() async {
await super.onLoad();
await addFromBlueprint(SpaceshipRamp());
await images.loadAll([
Assets.images.spaceship.ramp.railingBackground.keyName,
Assets.images.spaceship.ramp.main.keyName,
Assets.images.spaceship.ramp.boardOpening.keyName,
Assets.images.spaceship.ramp.railingForeground.keyName,
Assets.images.spaceship.ramp.arrow.inactive.keyName,
Assets.images.spaceship.ramp.arrow.active1.keyName,
Assets.images.spaceship.ramp.arrow.active2.keyName,
Assets.images.spaceship.ramp.arrow.active3.keyName,
Assets.images.spaceship.ramp.arrow.active4.keyName,
Assets.images.spaceship.ramp.arrow.active5.keyName,
]);
_spaceshipRamp = SpaceshipRamp();
await addFromBlueprint(_spaceshipRamp);
camera.followVector2(Vector2(-12, -50));
await traceAllBodies();
}
@override
KeyEventResult onKeyEvent(
RawKeyEvent event,
Set<LogicalKeyboardKey> keysPressed,
) {
if (event is RawKeyDownEvent &&
event.logicalKey == LogicalKeyboardKey.space) {
_spaceshipRamp.progress();
return KeyEventResult.handled;
}
return KeyEventResult.ignored;
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

@ -1,5 +1,6 @@
// ignore_for_file: cascade_invocations
import 'package:flame/components.dart';
import 'package:flame_forge2d/flame_forge2d.dart';
import 'package:flame_test/flame_test.dart';
import 'package:flutter_test/flutter_test.dart';
@ -9,22 +10,197 @@ import 'package:pinball_flame/pinball_flame.dart';
import '../../helpers/helpers.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
final assets = [
Assets.images.spaceship.ramp.boardOpening.keyName,
Assets.images.spaceship.ramp.railingForeground.keyName,
Assets.images.spaceship.ramp.railingBackground.keyName,
Assets.images.spaceship.ramp.main.keyName,
Assets.images.spaceship.ramp.arrow.inactive.keyName,
Assets.images.spaceship.ramp.arrow.active1.keyName,
Assets.images.spaceship.ramp.arrow.active2.keyName,
Assets.images.spaceship.ramp.arrow.active3.keyName,
Assets.images.spaceship.ramp.arrow.active4.keyName,
Assets.images.spaceship.ramp.arrow.active5.keyName,
];
final flameTester = FlameTester(() => TestGame(assets));
group('SpaceshipRamp', () {
final tester = FlameTester(TestGame.new);
tester.testGameWidget(
'renders correctly',
setUp: (game, tester) async {
await game.addFromBlueprint(SpaceshipRamp());
game.camera.followVector2(Vector2(-13, -50));
await game.ready();
},
verify: (game, tester) async {
await expectLater(
find.byGame<TestGame>(),
matchesGoldenFile('golden/spaceship-ramp.png'),
);
flameTester.test(
'loads correctly',
(game) async {
final spaceshipRamp = SpaceshipRamp();
await game.ensureAdd(spaceshipRamp);
expect(game.contains(spaceshipRamp), isTrue);
},
);
group('renders correctly', () {
final centerForSpaceshipRamp = Vector2(-13, -55);
flameTester.testGameWidget(
'inactive sprite',
setUp: (game, tester) async {
await game.images.loadAll(assets);
final spaceshipRamp = SpaceshipRamp();
await game.addFromBlueprint(spaceshipRamp);
await game.ready();
await tester.pump();
expect(
spaceshipRamp.spaceshipRampArrow.current,
SpaceshipRampArrowSpriteState.inactive,
);
game.camera.followVector2(centerForSpaceshipRamp);
},
verify: (game, tester) async {
await expectLater(
find.byGame<TestGame>(),
matchesGoldenFile('golden/spaceship_ramp/inactive.png'),
);
},
);
flameTester.testGameWidget(
'active1 sprite',
setUp: (game, tester) async {
await game.images.loadAll(assets);
final spaceshipRamp = SpaceshipRamp();
await game.addFromBlueprint(spaceshipRamp);
await game.ready();
spaceshipRamp.progress();
await tester.pump();
expect(
spaceshipRamp.spaceshipRampArrow.current,
SpaceshipRampArrowSpriteState.active1,
);
game.camera.followVector2(centerForSpaceshipRamp);
},
verify: (game, tester) async {
await expectLater(
find.byGame<TestGame>(),
matchesGoldenFile('golden/spaceship_ramp/active1.png'),
);
},
);
flameTester.testGameWidget(
'active2 sprite',
setUp: (game, tester) async {
await game.images.loadAll(assets);
final spaceshipRamp = SpaceshipRamp();
await game.addFromBlueprint(spaceshipRamp);
await game.ready();
spaceshipRamp
..progress()
..progress();
await tester.pump();
expect(
spaceshipRamp.spaceshipRampArrow.current,
SpaceshipRampArrowSpriteState.active2,
);
game.camera.followVector2(centerForSpaceshipRamp);
},
verify: (game, tester) async {
await expectLater(
find.byGame<TestGame>(),
matchesGoldenFile('golden/spaceship_ramp/active2.png'),
);
},
);
flameTester.testGameWidget(
'active3 sprite',
setUp: (game, tester) async {
await game.images.loadAll(assets);
final spaceshipRamp = SpaceshipRamp();
await game.addFromBlueprint(spaceshipRamp);
await game.ready();
spaceshipRamp
..progress()
..progress()
..progress();
await tester.pump();
expect(
spaceshipRamp.spaceshipRampArrow.current,
SpaceshipRampArrowSpriteState.active3,
);
game.camera.followVector2(centerForSpaceshipRamp);
},
verify: (game, tester) async {
await expectLater(
find.byGame<TestGame>(),
matchesGoldenFile('golden/spaceship_ramp/active3.png'),
);
},
);
flameTester.testGameWidget(
'active4 sprite',
setUp: (game, tester) async {
await game.images.loadAll(assets);
final spaceshipRamp = SpaceshipRamp();
await game.addFromBlueprint(spaceshipRamp);
await game.ready();
spaceshipRamp
..progress()
..progress()
..progress()
..progress();
await tester.pump();
expect(
spaceshipRamp.spaceshipRampArrow.current,
SpaceshipRampArrowSpriteState.active4,
);
game.camera.followVector2(centerForSpaceshipRamp);
},
verify: (game, tester) async {
await expectLater(
find.byGame<TestGame>(),
matchesGoldenFile('golden/spaceship_ramp/active4.png'),
);
},
);
flameTester.testGameWidget(
'active5 sprite',
setUp: (game, tester) async {
await game.images.loadAll(assets);
final spaceshipRamp = SpaceshipRamp();
await game.addFromBlueprint(spaceshipRamp);
await game.ready();
spaceshipRamp
..progress()
..progress()
..progress()
..progress()
..progress();
await tester.pump();
expect(
spaceshipRamp.spaceshipRampArrow.current,
SpaceshipRampArrowSpriteState.active5,
);
game.camera.followVector2(centerForSpaceshipRamp);
},
verify: (game, tester) async {
await expectLater(
find.byGame<TestGame>(),
matchesGoldenFile('golden/spaceship_ramp/active5.png'),
);
},
);
});
});
}

@ -33,6 +33,16 @@ void main() {
Assets.images.sparky.bumper.b.inactive.keyName,
Assets.images.sparky.bumper.c.active.keyName,
Assets.images.sparky.bumper.c.inactive.keyName,
Assets.images.spaceship.ramp.boardOpening.keyName,
Assets.images.spaceship.ramp.railingForeground.keyName,
Assets.images.spaceship.ramp.railingBackground.keyName,
Assets.images.spaceship.ramp.main.keyName,
Assets.images.spaceship.ramp.arrow.inactive.keyName,
Assets.images.spaceship.ramp.arrow.active1.keyName,
Assets.images.spaceship.ramp.arrow.active2.keyName,
Assets.images.spaceship.ramp.arrow.active3.keyName,
Assets.images.spaceship.ramp.arrow.active4.keyName,
Assets.images.spaceship.ramp.arrow.active5.keyName,
];
final flameTester = FlameTester(() => PinballTestGame(assets));
final debugModeFlameTester = FlameTester(() => DebugPinballTestGame(assets));

Loading…
Cancel
Save