diff --git a/lib/game/components/flutter_forest.dart b/lib/game/components/flutter_forest.dart index 9731b7ae..8874ffa3 100644 --- a/lib/game/components/flutter_forest.dart +++ b/lib/game/components/flutter_forest.dart @@ -37,7 +37,8 @@ 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(); + final dashAnimatronic = _ControlledDashAnimatronic() + ..position = Vector2(20, -66); await addAll([ signPost, @@ -75,7 +76,7 @@ class _FlutterForestController extends ComponentController } void _startDashAnimatronic() { - component.descendants().whereType<_DashAnimatronic>().single.playing = true; + component.firstChild<_ControlledDashAnimatronic>()?.controller.start(); } Future _addBonusBall() async { @@ -87,45 +88,20 @@ class _FlutterForestController extends ComponentController } } -class _DashAnimatronic extends SpriteAnimationComponent with HasGameRef { - _DashAnimatronic() - : super( - size: Vector2(15, 15), - anchor: Anchor.center, - position: Vector2(20, -66), - playing: false, - ); - - late final SpriteAnimation _animation; - - @override - Future? onLoad() async { - await super.onLoad(); - - final spriteSheet = await gameRef.images.load( - Assets.images.dash.animatronic.keyName, - ); - - _animation = SpriteAnimation.fromFrameData( - spriteSheet, - SpriteAnimationData.sequenced( - amount: 96, - amountPerRow: 12, - stepTime: 1 / 24, - textureSize: Vector2(150, 150), - loop: false, - ), - ); - animation = _animation; +class _ControlledDashAnimatronic extends DashAnimatronic + with Controls<_DashAnimatronicController> { + _ControlledDashAnimatronic() { + controller = _DashAnimatronicController(this); } +} - @override - void update(double dt) { - super.update(dt); - if (_animation.isLastFrame) { - _animation.reset(); - playing = false; - } +class _DashAnimatronicController extends ComponentController + with HasGameRef { + _DashAnimatronicController(DashAnimatronic dashAnimatronic) + : super(dashAnimatronic); + + void start() { + component.playing = true; } } diff --git a/packages/pinball_components/lib/src/components/ball.dart b/packages/pinball_components/lib/src/components/ball.dart index 6aaf88de..5c280895 100644 --- a/packages/pinball_components/lib/src/components/ball.dart +++ b/packages/pinball_components/lib/src/components/ball.dart @@ -10,7 +10,7 @@ import 'package:pinball_components/pinball_components.dart'; /// {@endtemplate} class Ball extends BodyComponent with Layered, InitialPosition { - /// {@macro ball_body} + /// {@macro ball} Ball({ required this.baseColor, }) { diff --git a/packages/pinball_components/lib/src/components/components.dart b/packages/pinball_components/lib/src/components/components.dart index b71f7c13..e1b76b6e 100644 --- a/packages/pinball_components/lib/src/components/components.dart +++ b/packages/pinball_components/lib/src/components/components.dart @@ -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'; diff --git a/packages/pinball_components/lib/src/components/dash_animatronic.dart b/packages/pinball_components/lib/src/components/dash_animatronic.dart new file mode 100644 index 00000000..6787eb80 --- /dev/null +++ b/packages/pinball_components/lib/src/components/dash_animatronic.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? 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; + } + } + } +} diff --git a/packages/pinball_components/test/src/components/dash_animatronic_test.dart b/packages/pinball_components/test/src/components/dash_animatronic_test.dart new file mode 100644 index 00000000..b268fee0 --- /dev/null +++ b/packages/pinball_components/test/src/components/dash_animatronic_test.dart @@ -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); + }, + ); + }); +} diff --git a/test/game/components/flutter_forest_test.dart b/test/game/components/flutter_forest_test.dart index b01018d7..2761aa66 100644 --- a/test/game/components/flutter_forest_test.dart +++ b/test/game/components/flutter_forest_test.dart @@ -19,7 +19,6 @@ void main() { flameTester.test( 'loads correctly', (game) async { - await game.ready(); final flutterForest = FlutterForest(); await game.ensureAdd(flutterForest); @@ -31,7 +30,6 @@ void main() { flameTester.test( 'a FlutterSignPost', (game) async { - await game.ready(); final flutterForest = FlutterForest(); await game.ensureAdd(flutterForest); @@ -45,7 +43,6 @@ void main() { flameTester.test( 'a BigDashNestBumper', (game) async { - await game.ready(); final flutterForest = FlutterForest(); await game.ensureAdd(flutterForest); @@ -59,7 +56,6 @@ void main() { flameTester.test( 'two SmallDashNestBumper', (game) async { - await game.ready(); final flutterForest = FlutterForest(); await game.ensureAdd(flutterForest); @@ -106,12 +102,11 @@ void main() { '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().length; flutterForest.controller.onNewState(MockGameState()); - await game.ready(); + await Future.delayed(const Duration(milliseconds: 700)); await game.ready(); @@ -126,35 +121,13 @@ void main() { 'onNewState starts Dash animatronic', (game) async { final flutterForest = FlutterForest(); - await game.ready(); await game.ensureAdd(flutterForest); flutterForest.controller.onNewState(MockGameState()); - await game.ready(); - final dashAnimatronic = - game.descendants().whereType().single; - expect(dashAnimatronic.playing, isTrue); - }, - ); + game.descendants().whereType().single; - flameTester.test( - 'Dash animatronic stops animating after animation completes', - (game) async { - final flutterForest = FlutterForest(); - await game.ready(); - await game.ensureAdd(flutterForest); - - flutterForest.controller.onNewState(MockGameState()); - await game.ready(); - - final dashAnimatronic = - game.descendants().whereType().single; expect(dashAnimatronic.playing, isTrue); - - dashAnimatronic.animation?.setToLast(); - game.update(1); - expect(dashAnimatronic.playing, isFalse); }, );