feat: add Dash animatronic (#169)

* feat: add Dash animatronic

* refactor: controlled animatronic

* fix: unused import

* refactor: remove animatronic controller

* chore: non-nullable onLoad

* test: animatronic is in forest
pull/183/head
Allison Ryan 3 years ago committed by GitHub
parent f9cd93b77e
commit b424f0a008
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -37,12 +37,14 @@ class FlutterForest extends Component with Controls<_FlutterForestController> {
final smallRightNest = _ControlledSmallDashNestBumper.b(
id: 'small_nest_bumper_b',
)..initialPosition = Vector2(23.3, 46.75);
final dashAnimatronic = DashAnimatronic()..position = Vector2(20, -66);
await addAll([
signPost,
smallLeftNest,
smallRightNest,
bigNest,
dashAnimatronic,
]);
}
}
@ -68,7 +70,13 @@ class _FlutterForestController extends ComponentController<FlutterForest>
void onNewState(GameState state) {
super.onNewState(state);
gameRef.add(
component.firstChild<DashAnimatronic>()?.playing = true;
_addBonusBall();
}
Future<void> _addBonusBall() async {
await Future<void>.delayed(const Duration(milliseconds: 700));
await gameRef.add(
ControlledBall.bonus(theme: gameRef.theme)
..initialPosition = Vector2(17.2, 52.7),
);

@ -25,12 +25,13 @@ extension PinballGameAssetsX on PinballGame {
),
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),
images.load(components.Assets.images.dashBumper.a.inactive.keyName),
images.load(components.Assets.images.dashBumper.b.active.keyName),
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.dash.animatronic.keyName),
images.load(components.Assets.images.dash.bumper.a.active.keyName),
images.load(components.Assets.images.dash.bumper.a.inactive.keyName),
images.load(components.Assets.images.dash.bumper.b.active.keyName),
images.load(components.Assets.images.dash.bumper.b.inactive.keyName),
images.load(components.Assets.images.dash.bumper.main.active.keyName),
images.load(components.Assets.images.dash.bumper.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),

Binary file not shown.

After

Width:  |  Height:  |  Size: 886 KiB

@ -19,8 +19,7 @@ class $AssetsImagesGen {
$AssetsImagesBoundaryGen get boundary => const $AssetsImagesBoundaryGen();
$AssetsImagesChromeDinoGen get chromeDino =>
const $AssetsImagesChromeDinoGen();
$AssetsImagesDashBumperGen get dashBumper =>
const $AssetsImagesDashBumperGen();
$AssetsImagesDashGen get dash => const $AssetsImagesDashGen();
$AssetsImagesDinoGen get dino => const $AssetsImagesDinoGen();
$AssetsImagesFlipperGen get flipper => const $AssetsImagesFlipperGen();
@ -87,13 +86,14 @@ class $AssetsImagesChromeDinoGen {
const AssetGenImage('assets/images/chrome_dino/mouth.png');
}
class $AssetsImagesDashBumperGen {
const $AssetsImagesDashBumperGen();
class $AssetsImagesDashGen {
const $AssetsImagesDashGen();
$AssetsImagesDashBumperAGen get a => const $AssetsImagesDashBumperAGen();
$AssetsImagesDashBumperBGen get b => const $AssetsImagesDashBumperBGen();
$AssetsImagesDashBumperMainGen get main =>
const $AssetsImagesDashBumperMainGen();
/// File path: assets/images/dash/animatronic.png
AssetGenImage get animatronic =>
const AssetGenImage('assets/images/dash/animatronic.png');
$AssetsImagesDashBumperGen get bumper => const $AssetsImagesDashBumperGen();
}
class $AssetsImagesDinoGen {
@ -226,40 +226,13 @@ class $AssetsImagesSparkyGen {
const $AssetsImagesSparkyComputerGen();
}
class $AssetsImagesDashBumperAGen {
const $AssetsImagesDashBumperAGen();
/// File path: assets/images/dash_bumper/a/active.png
AssetGenImage get active =>
const AssetGenImage('assets/images/dash_bumper/a/active.png');
/// File path: assets/images/dash_bumper/a/inactive.png
AssetGenImage get inactive =>
const AssetGenImage('assets/images/dash_bumper/a/inactive.png');
}
class $AssetsImagesDashBumperBGen {
const $AssetsImagesDashBumperBGen();
/// File path: assets/images/dash_bumper/b/active.png
AssetGenImage get active =>
const AssetGenImage('assets/images/dash_bumper/b/active.png');
/// File path: assets/images/dash_bumper/b/inactive.png
AssetGenImage get inactive =>
const AssetGenImage('assets/images/dash_bumper/b/inactive.png');
}
class $AssetsImagesDashBumperGen {
const $AssetsImagesDashBumperGen();
class $AssetsImagesDashBumperMainGen {
$AssetsImagesDashBumperAGen get a => const $AssetsImagesDashBumperAGen();
$AssetsImagesDashBumperBGen get b => const $AssetsImagesDashBumperBGen();
$AssetsImagesDashBumperMainGen get main =>
const $AssetsImagesDashBumperMainGen();
/// File path: assets/images/dash_bumper/main/active.png
AssetGenImage get active =>
const AssetGenImage('assets/images/dash_bumper/main/active.png');
/// File path: assets/images/dash_bumper/main/inactive.png
AssetGenImage get inactive =>
const AssetGenImage('assets/images/dash_bumper/main/inactive.png');
}
class $AssetsImagesSpaceshipRailGen {
@ -346,6 +319,42 @@ class $AssetsImagesSparkyBumperCGen {
const AssetGenImage('assets/images/sparky/bumper/c/inactive.png');
}
class $AssetsImagesDashBumperAGen {
const $AssetsImagesDashBumperAGen();
/// File path: assets/images/dash/bumper/a/active.png
AssetGenImage get active =>
const AssetGenImage('assets/images/dash/bumper/a/active.png');
/// File path: assets/images/dash/bumper/a/inactive.png
AssetGenImage get inactive =>
const AssetGenImage('assets/images/dash/bumper/a/inactive.png');
}
class $AssetsImagesDashBumperBGen {
const $AssetsImagesDashBumperBGen();
/// File path: assets/images/dash/bumper/b/active.png
AssetGenImage get active =>
const AssetGenImage('assets/images/dash/bumper/b/active.png');
/// File path: assets/images/dash/bumper/b/inactive.png
AssetGenImage get inactive =>
const AssetGenImage('assets/images/dash/bumper/b/inactive.png');
}
class $AssetsImagesDashBumperMainGen {
const $AssetsImagesDashBumperMainGen();
/// File path: assets/images/dash/bumper/main/active.png
AssetGenImage get active =>
const AssetGenImage('assets/images/dash/bumper/main/active.png');
/// File path: assets/images/dash/bumper/main/inactive.png
AssetGenImage get inactive =>
const AssetGenImage('assets/images/dash/bumper/main/inactive.png');
}
class Assets {
Assets._();

@ -10,7 +10,7 @@ import 'package:pinball_components/pinball_components.dart';
/// {@endtemplate}
class Ball<T extends Forge2DGame> extends BodyComponent<T>
with Layered, InitialPosition {
/// {@macro ball_body}
/// {@macro ball}
Ball({
required this.baseColor,
}) {

@ -6,6 +6,7 @@ export 'board_side.dart';
export 'boundaries.dart';
export 'camera_zoom.dart';
export 'chrome_dino.dart';
export 'dash_animatronic.dart';
export 'dash_nest_bumper.dart';
export 'dino_walls.dart';
export 'fire_effect.dart';

@ -0,0 +1,53 @@
import 'package:flame/components.dart';
import 'package:pinball_components/pinball_components.dart';
/// {@template dash_animatronic}
/// Animated Dash that sits on top of the [BigDashNestBumper].
/// {@endtemplate}
class DashAnimatronic extends SpriteAnimationComponent with HasGameRef {
/// {@macro dash_animatronic}
DashAnimatronic()
: super(
anchor: Anchor.center,
playing: false,
);
@override
Future<void> onLoad() async {
await super.onLoad();
final spriteSheet = await gameRef.images.load(
Assets.images.dash.animatronic.keyName,
);
const amountPerRow = 12;
const amountPerColumn = 8;
final textureSize = Vector2(
spriteSheet.width / amountPerRow,
spriteSheet.height / amountPerColumn,
);
size = textureSize / 10;
animation = SpriteAnimation.fromFrameData(
spriteSheet,
SpriteAnimationData.sequenced(
amount: amountPerRow * amountPerColumn,
amountPerRow: amountPerRow,
stepTime: 1 / 24,
textureSize: textureSize,
loop: false,
),
);
}
@override
void update(double dt) {
super.update(dt);
if (animation != null) {
if (animation!.isLastFrame) {
animation!.reset();
playing = false;
}
}
}
}

@ -63,8 +63,8 @@ class BigDashNestBumper extends DashNestBumper {
/// {@macro dash_nest_bumper}
BigDashNestBumper()
: super._(
activeAssetPath: Assets.images.dashBumper.main.active.keyName,
inactiveAssetPath: Assets.images.dashBumper.main.inactive.keyName,
activeAssetPath: Assets.images.dash.bumper.main.active.keyName,
inactiveAssetPath: Assets.images.dash.bumper.main.inactive.keyName,
spriteComponent: SpriteComponent(
anchor: Anchor.center,
position: Vector2(0, -0.3),
@ -104,8 +104,8 @@ class SmallDashNestBumper extends DashNestBumper {
/// {@macro dash_nest_bumper}
SmallDashNestBumper.a()
: this._(
activeAssetPath: Assets.images.dashBumper.a.active.keyName,
inactiveAssetPath: Assets.images.dashBumper.a.inactive.keyName,
activeAssetPath: Assets.images.dash.bumper.a.active.keyName,
inactiveAssetPath: Assets.images.dash.bumper.a.inactive.keyName,
spriteComponent: SpriteComponent(
anchor: Anchor.center,
position: Vector2(0.35, -1.2),
@ -115,8 +115,8 @@ class SmallDashNestBumper extends DashNestBumper {
/// {@macro dash_nest_bumper}
SmallDashNestBumper.b()
: this._(
activeAssetPath: Assets.images.dashBumper.b.active.keyName,
inactiveAssetPath: Assets.images.dashBumper.b.inactive.keyName,
activeAssetPath: Assets.images.dash.bumper.b.active.keyName,
inactiveAssetPath: Assets.images.dash.bumper.b.inactive.keyName,
spriteComponent: SpriteComponent(
anchor: Anchor.center,
position: Vector2(0.35, -1.2),

@ -41,9 +41,10 @@ flutter:
- 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/dash/
- 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/

@ -0,0 +1,38 @@
// 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() {
TestWidgetsFlutterBinding.ensureInitialized();
final flameTester = FlameTester(TestGame.new);
group('DashAnimatronic', () {
flameTester.test(
'loads correctly',
(game) async {
final dashAnimatronic = DashAnimatronic();
await game.ensureAdd(dashAnimatronic);
expect(game.contains(dashAnimatronic), isTrue);
},
);
flameTester.test(
'stops animating after animation completes',
(game) async {
final dashAnimatronic = DashAnimatronic();
await game.ensureAdd(dashAnimatronic);
dashAnimatronic.playing = true;
dashAnimatronic.animation?.setToLast();
game.update(1);
expect(dashAnimatronic.playing, isFalse);
},
);
});
}

@ -18,7 +18,6 @@ void main() {
flameTester.test(
'loads correctly',
(game) async {
await game.ready();
final flutterForest = FlutterForest();
await game.ensureAdd(flutterForest);
@ -30,7 +29,6 @@ void main() {
flameTester.test(
'a FlutterSignPost',
(game) async {
await game.ready();
final flutterForest = FlutterForest();
await game.ensureAdd(flutterForest);
@ -41,10 +39,22 @@ void main() {
},
);
flameTester.test(
'a DashAnimatronic',
(game) async {
final flutterForest = FlutterForest();
await game.ensureAdd(flutterForest);
expect(
flutterForest.firstChild<DashAnimatronic>(),
isNotNull,
);
},
);
flameTester.test(
'a BigDashNestBumper',
(game) async {
await game.ready();
final flutterForest = FlutterForest();
await game.ensureAdd(flutterForest);
@ -58,7 +68,6 @@ void main() {
flameTester.test(
'two SmallDashNestBumper',
(game) async {
await game.ready();
final flutterForest = FlutterForest();
await game.ensureAdd(flutterForest);
@ -102,14 +111,15 @@ void main() {
});
flameTester.test(
'onNewState adds a new ball',
'onNewState adds a new ball after a duration',
(game) async {
final flutterForest = FlutterForest();
await game.ready();
await game.ensureAdd(flutterForest);
final previousBalls = game.descendants().whereType<Ball>().length;
flutterForest.controller.onNewState(MockGameState());
await Future<void>.delayed(const Duration(milliseconds: 700));
await game.ready();
expect(
@ -119,6 +129,20 @@ void main() {
},
);
flameTester.test(
'onNewState starts Dash animatronic',
(game) async {
final flutterForest = FlutterForest();
await game.ensureAdd(flutterForest);
flutterForest.controller.onNewState(MockGameState());
final dashAnimatronic =
game.descendants().whereType<DashAnimatronic>().single;
expect(dashAnimatronic.playing, isTrue);
},
);
group('bumpers', () {
late Ball ball;
late GameBloc gameBloc;

Loading…
Cancel
Save