diff --git a/doc/flame/components.md b/doc/flame/components.md index 5da3d89ca..f93aa3d8d 100644 --- a/doc/flame/components.md +++ b/doc/flame/components.md @@ -88,7 +88,7 @@ Example: ```dart class MyGame extends FlameGame { @override - Future onLoad() { + void onLoad() { final myComponent = PositionComponent(priority: 5); add(myComponent); } @@ -135,7 +135,7 @@ class GameOverPanel extends PositionComponent { GameOverPanel(this.spriteImage); @override - Future onLoad() async { + void onLoad() { final gameOverText = GameOverText(spriteImage); // GameOverText is a Component final gameOverButton = GameOverButton(spriteImage); // GameOverRestart is a SpriteComponent @@ -163,7 +163,7 @@ constructor. This approach more closely resembles the standard Flutter API: ```dart class MyGame extends FlameGame { @override - Future onLoad() async { + void onLoad() { add( PositionComponent( position: Vector2(30, 0), @@ -198,7 +198,7 @@ Example: ```dart class MyComponent extends Component with ParentIsA { @override - Future onLoad() async { + void onLoad() { // parent is of type MyParentComponent print(parent.myValue); } @@ -221,7 +221,7 @@ Example: ```dart class MyComponent extends Component with HasAncestor { @override - Future onLoad() async { + void onLoad() { // ancestor is of type MyAncestorComponent. print(ancestor.myValue); } @@ -247,7 +247,7 @@ Example: ```dart @override -Future onLoad() async { +void onLoad() { children.register(); } ``` @@ -442,10 +442,10 @@ class MyGame extends FlameGame { final player = SpriteComponent(size: size, sprite: sprite); // Vector2(0.0, 0.0) by default, can also be set in the constructor - player.position = ... + player.position = Vector2(10, 20); // 0 by default, can also be set in the constructor - player.angle = ... + player.angle = 0; // Adds the component add(player); @@ -461,32 +461,36 @@ This class is used to represent a Component that has sprites that run in a singl This will create a simple three frame animation using 3 different images: ```dart -final sprites = [0, 1, 2] - .map((i) => Sprite.load('player_$i.png')); -final animation = SpriteAnimation.spriteList( - await Future.wait(sprites), - stepTime: 0.01, -); -this.player = SpriteAnimationComponent( - animation: animation, - size: Vector2.all(64.0), -); +Future onLoad() async { + final sprites = [0, 1, 2] + .map((i) => Sprite.load('player_$i.png')); + final animation = SpriteAnimation.spriteList( + await Future.wait(sprites), + stepTime: 0.01, + ); + this.player = SpriteAnimationComponent( + animation: animation, + size: Vector2.all(64.0), + ); +} ``` If you have a sprite sheet, you can use the `sequenced` constructor from the `SpriteAnimationData` class (check more details on [Images > Animation](rendering/images.md#animation)): ```dart -final size = Vector2.all(64.0); -final data = SpriteAnimationData.sequenced( - textureSize: size, - amount: 2, - stepTime: 0.1, -); -this.player = SpriteAnimationComponent.fromFrameData( - await images.load('player.png'), - data, -); +Future onLoad() async { + final size = Vector2.all(64.0); + final data = SpriteAnimationData.sequenced( + textureSize: size, + amount: 2, + stepTime: 0.1, + ); + this.player = SpriteAnimationComponent.fromFrameData( + await images.load('player.png'), + data, + ); +} ``` If you are not using `FlameGame`, don't forget this component needs to be updated, because the @@ -580,7 +584,7 @@ class ButtonComponent extends SpriteGroupComponent @override Future? onLoad() async { final pressedSprite = await gameRef.loadSprite(/* omitted */); - final unpressedSprite = await gameRef.loadSprite(/* omitted /*); + final unpressedSprite = await gameRef.loadSprite(/* omitted */); sprites = { ButtonState.pressed: pressedSprite, @@ -604,12 +608,14 @@ This component uses an instance of `Svg` class to represent a Component that has rendered in the game: ```dart -final svg = await Svg.load('android.svg'); -final android = SvgComponent.fromSvg( - svg, - position: Vector2.all(100), - size: Vector2.all(100), -); +Future onLoad() async { + final svg = await Svg.load('android.svg'); + final android = SvgComponent.fromSvg( + svg, + position: Vector2.all(100), + size: Vector2.all(100), + ); +} ``` @@ -711,7 +717,7 @@ class MyParallaxComponent extends ParallaxComponent { class MyGame extends FlameGame { @override - Future onLoad() async { + void onLoad() { add(MyParallaxComponent()); } } @@ -726,20 +732,24 @@ They simplest way is to set the named optional parameters `baseVelocity` and background images along the X-axis with a faster speed the "closer" the image is: ```dart -final parallaxComponent = await loadParallaxComponent( - _dataList, - baseVelocity: Vector2(20, 0), - velocityMultiplierDelta: Vector2(1.8, 1.0), -); +Future onLoad() async { + final parallaxComponent = await loadParallaxComponent( + _dataList, + baseVelocity: Vector2(20, 0), + velocityMultiplierDelta: Vector2(1.8, 1.0), + ); +} ``` You can set the baseSpeed and layerDelta at any time, for example if your character jumps or your game speeds up. ```dart -final parallax = parallaxComponent.parallax; -parallax.baseSpeed = Vector2(100, 0); -parallax.velocityMultiplierDelta = Vector2(2.0, 1.0); +Future onLoad() async { + final parallax = parallaxComponent.parallax; + parallax.baseSpeed = Vector2(100, 0); + parallax.velocityMultiplierDelta = Vector2(2.0, 1.0); +} ``` By default, the images are aligned to the bottom left, repeated along the X-axis and scaled @@ -997,20 +1007,23 @@ then add animation. Removing the stack will not remove the tiles from the map. > **Note**: This currently only supports position based effects. ```dart - final stack = map.tileMap.tileStack(4, 0, named: {'floor_under'}); - stack.add( - SequenceEffect( - [ - MoveEffect.by( - Vector2(5, 0), - NoiseEffectController(duration: 1, frequency: 20), - ), - MoveEffect.by(Vector2.zero(), LinearEffectController(2)), - ], - repeatCount: 3, - )..onComplete = () => stack.removeFromParent(), - ); - map.add(stack); +void onLoad() { + final stack = map.tileMap.tileStack(4, 0, named: {'floor_under'}); + stack.add( + SequenceEffect( + [ + MoveEffect.by( + Vector2(5, 0), + NoiseEffectController(duration: 1, frequency: 20), + ), + MoveEffect.by(Vector2.zero(), LinearEffectController(2)), + ], + repeatCount: 3, + ) + ..onComplete = () => stack.removeFromParent(), + ); + map.add(stack); +} ``` @@ -1111,19 +1124,20 @@ be used: class MyGame extends FlameGame { int lives = 2; - Future onLoad() { - final playerNotifier = componentsNotifier() - ..addListener(() { - final player = playerNotifier.single; - if (player == null) { - lives--; - if (lives == 0) { - add(GameOverComponent()); - } else { - add(Player()); - } - } - }); + @override + void onLoad() { + final playerNotifier = componentsNotifier() + ..addListener(() { + final player = playerNotifier.single; + if (player == null) { + lives--; + if (lives == 0) { + add(GameOverComponent()); + } else { + add(Player()); + } + } + }); } } ``` @@ -1152,16 +1166,17 @@ Then our hud component could look like: ```dart class Hud extends PositionComponent with HasGameRef { - Future onLoad() { - final playerNotifier = gameRef.componentsNotifier() - ..addListener(() { - final player = playerNotifier.single; - if (player != null) { - if (player.health <= .5) { - add(BlinkEffect()); - } - } - }); + @override + void onLoad() { + final playerNotifier = gameRef.componentsNotifier() + ..addListener(() { + final player = playerNotifier.single; + if (player != null) { + if (player.health <= .5) { + add(BlinkEffect()); + } + } + }); } } ``` diff --git a/examples/lib/stories/bridge_libraries/flame_isolate/simple_isolate_example.dart b/examples/lib/stories/bridge_libraries/flame_isolate/simple_isolate_example.dart index c83ecccfe..9ade280f1 100644 --- a/examples/lib/stories/bridge_libraries/flame_isolate/simple_isolate_example.dart +++ b/examples/lib/stories/bridge_libraries/flame_isolate/simple_isolate_example.dart @@ -79,10 +79,9 @@ class CalculatePrimeNumber extends PositionComponent DiscardNewBackPressureStrategy(); @override - Future? onLoad() { + void onLoad() { width = 200; height = 70; - return super.onLoad(); } @override diff --git a/examples/lib/stories/camera_and_viewport/camera_component_example.dart b/examples/lib/stories/camera_and_viewport/camera_component_example.dart index 7f94c1cd1..0ed63b27c 100644 --- a/examples/lib/stories/camera_and_viewport/camera_component_example.dart +++ b/examples/lib/stories/camera_and_viewport/camera_component_example.dart @@ -97,7 +97,7 @@ class Bezel extends PositionComponent { late final Paint specularPaint; @override - Future onLoad() async { + void onLoad() { rim = Path()..addOval(Rect.fromLTRB(-radius, -radius, radius, radius)); final outer = radius + rimWidth / 2; final inner = radius - rimWidth / 2; diff --git a/examples/lib/stories/collision_detection/bouncing_ball_example.dart b/examples/lib/stories/collision_detection/bouncing_ball_example.dart index 4e94845ac..bbabba8fb 100644 --- a/examples/lib/stories/collision_detection/bouncing_ball_example.dart +++ b/examples/lib/stories/collision_detection/bouncing_ball_example.dart @@ -12,12 +12,11 @@ class BouncingBallExample extends FlameGame with HasCollisionDetection { collides with the screen boundaries and then update it to bounce off these boundaries. '''; @override - Future? onLoad() { + void onLoad() { addAll([ ScreenHitbox(), Ball(), ]); - return super.onLoad(); } } diff --git a/examples/lib/stories/collision_detection/raycast_max_distance_example.dart b/examples/lib/stories/collision_detection/raycast_max_distance_example.dart index e5ab5e19f..483bd3253 100644 --- a/examples/lib/stories/collision_detection/raycast_max_distance_example.dart +++ b/examples/lib/stories/collision_detection/raycast_max_distance_example.dart @@ -30,7 +30,7 @@ This examples showcases how raycast APIs can be used to detect hits within certa )..positionType = PositionType.viewport; @override - Future? onLoad() { + void onLoad() { camera.viewport = FixedResolutionViewport(Vector2(320, 180)); _addMovingWall(); @@ -49,8 +49,6 @@ This examples showcases how raycast APIs can be used to detect hits within certa origin: _character.absolutePosition, direction: Vector2(1, 0), ); - - return super.onLoad(); } void _addMovingWall() { diff --git a/packages/flame/lib/src/components/core/component.dart b/packages/flame/lib/src/components/core/component.dart index df5d572d1..1a6c69f88 100644 --- a/packages/flame/lib/src/components/core/component.dart +++ b/packages/flame/lib/src/components/core/component.dart @@ -409,18 +409,17 @@ class Component { /// ``` /// /// Alternatively, if your [onLoad] function doesn't use any `await`ing, then - /// you can declare it as a regular method and then return `null`: + /// you can declare it as a regular method returning `void`: /// ```dart /// @override - /// Future? onLoad() { + /// void onLoad() { /// // your code here - /// return null; /// } /// ``` /// /// The engine ensures that this method will be called exactly once during /// the lifetime of the [Component] object. Do not call this method manually. - Future? onLoad() => null; + FutureOr onLoad() => null; /// Called when the component is added to its parent. /// @@ -530,14 +529,14 @@ class Component { /// try to add it to multiple parents, or even to the same parent multiple /// times. If you need to change the parent of a component, use the /// [changeParent] method. - Future? add(Component component) => component.addToParent(this); + FutureOr add(Component component) => component.addToParent(this); /// A convenience method to [add] multiple children at once. Future addAll(Iterable components) { final futures = >[]; for (final component in components) { final future = add(component); - if (future != null) { + if (future is Future) { futures.add(future); } } @@ -545,7 +544,7 @@ class Component { } /// Adds this component as a child of [parent] (see [add] for details). - Future? addToParent(Component parent) { + FutureOr addToParent(Component parent) { assert( _parent == null, '$this cannot be added to $parent because it already has a parent: ' @@ -556,7 +555,6 @@ class Component { if (!isLoaded && (parent.findGame()?.hasLayout ?? false)) { return _startLoading(); } - return null; } /// Removes a component from the component tree. @@ -760,7 +758,7 @@ class Component { }); } - Future? _startLoading() { + FutureOr _startLoading() { assert(_state == _initial); assert(_parent != null); assert(_parent!.findGame() != null); @@ -768,11 +766,10 @@ class Component { _setLoadingBit(); onGameResize(_parent!.findGame()!.canvasSize); final onLoadFuture = onLoad(); - if (onLoadFuture == null) { - _finishLoading(); - return null; + if (onLoadFuture is Future) { + return onLoadFuture.then((dynamic _) => _finishLoading()); } else { - return onLoadFuture.then((_) => _finishLoading()); + _finishLoading(); } } diff --git a/packages/flame/lib/src/game/game.dart b/packages/flame/lib/src/game/game.dart index f4e9ac449..f40f8c8ef 100644 --- a/packages/flame/lib/src/game/game.dart +++ b/packages/flame/lib/src/game/game.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:flame/cache.dart'; import 'package:flame/components.dart'; import 'package:flame/extensions.dart'; @@ -51,12 +53,12 @@ abstract class Game { Vector2? _size; /// This variable ensures that Game's [onLoad] is called no more than once. - late final Future? _onLoadFuture = onLoad(); + late final FutureOr _onLoadFuture = onLoad(); bool _debugOnLoadStarted = false; @internal - Future? get onLoadFuture { + FutureOr get onLoadFuture { assert( () { _debugOnLoadStarted = true; @@ -69,7 +71,7 @@ abstract class Game { /// To be used for tests that needs to evaluate the game after it has been /// loaded by the game widget. @visibleForTesting - Future? toBeLoaded() { + FutureOr toBeLoaded() { assert( _debugOnLoadStarted, 'Make sure the game has passed to a mounted ' @@ -159,7 +161,7 @@ abstract class Game { /// /// The engine ensures that this method will be called exactly once during /// the lifetime of the [Game] instance. Do not call this method manually. - Future? onLoad() => null; + FutureOr onLoad() => null; void onMount() {} diff --git a/packages/flame_isolate/example/lib/brains/worker_overmind_hud.dart b/packages/flame_isolate/example/lib/brains/worker_overmind_hud.dart index ddaec02d4..58162f062 100644 --- a/packages/flame_isolate/example/lib/brains/worker_overmind_hud.dart +++ b/packages/flame_isolate/example/lib/brains/worker_overmind_hud.dart @@ -16,13 +16,12 @@ class WorkerOvermindHud extends PositionComponent with Tappable { ComputeType computeType = ComputeType.isolate; @override - Future? onLoad() { + void onLoad() { x = 10; y = 10; width = 210; height = 80; positionType = PositionType.viewport; - return super.onLoad(); } @override diff --git a/packages/flame_isolate/example/lib/units/actions/movable.dart b/packages/flame_isolate/example/lib/units/actions/movable.dart index 07618a90d..057d87e95 100755 --- a/packages/flame_isolate/example/lib/units/actions/movable.dart +++ b/packages/flame_isolate/example/lib/units/actions/movable.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:flame/components.dart'; import 'package:flame/effects.dart'; import 'package:flutter/material.dart'; @@ -40,7 +42,7 @@ mixin Movable on PositionComponent, HasGameRef { @override @mustCallSuper - Future? onLoad() { + FutureOr onLoad() { anchor = Anchor.center; return super.onLoad(); } diff --git a/packages/flame_lottie/example/pubspec.yaml b/packages/flame_lottie/example/pubspec.yaml index b56761547..48901d7a0 100644 --- a/packages/flame_lottie/example/pubspec.yaml +++ b/packages/flame_lottie/example/pubspec.yaml @@ -5,7 +5,7 @@ publish_to: 'none' version: 0.0.1+1 environment: - sdk: '>=2.18.2 <3.0.0' + sdk: '>=2.17.0 <3.0.0' dependencies: flame: ^1.5.0 diff --git a/packages/flame_rive/example/lib/main.dart b/packages/flame_rive/example/lib/main.dart index 223bb70ba..5fa1901cd 100644 --- a/packages/flame_rive/example/lib/main.dart +++ b/packages/flame_rive/example/lib/main.dart @@ -50,7 +50,7 @@ class SkillsAnimationComponent extends RiveComponent with Tappable { SMIInput? _levelInput; @override - Future? onLoad() { + void onLoad() { final controller = StateMachineController.fromArtboard( artboard, "Designer's Test", @@ -60,7 +60,6 @@ class SkillsAnimationComponent extends RiveComponent with Tappable { _levelInput = controller.findInput('Level'); _levelInput?.value = 0; } - return super.onLoad(); } @override