From b60f45c388baef35849e30d0d2ae15e9e23e8855 Mon Sep 17 00:00:00 2001 From: Lukas Klingsbo Date: Sun, 4 Oct 2020 21:26:04 +0200 Subject: [PATCH] Use a list of vector2 for MoveEffect --- CHANGELOG.md | 2 +- doc/effects.md | 10 +++++-- .../effects/sequence_effect/lib/main.dart | 15 +++++----- .../effects/simple/lib/main_move.dart | 13 ++++++++- lib/effects/effects.dart | 8 ++++++ lib/effects/move_effect.dart | 16 +++++++---- lib/effects/sequence_effect.dart | 28 +++++++++++++------ 7 files changed, 68 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 45daeaf19..5e5990245 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ - Make `Resizable` have a `gameSize` property instead of `size` - Fix bug with CombinedEffect inside SequenceEffect - Fix wrong end angle for relative rotational effects - - Use a list of Vector2 for Move effect to open up for more capabilities + - Use a list of Vector2 for Move effect to open up for more advanced move effects ## [next] - Fix spriteAsWidget deprecation message diff --git a/doc/effects.md b/doc/effects.md index 9cfea0d89..bc668b20c 100644 --- a/doc/effects.md +++ b/doc/effects.md @@ -20,7 +20,7 @@ When an effect is completed the callback `onComplete` will be called, it can be ## MoveEffect -Applied to `PositionComponent`s, this effect can be used to move the component to a new position, using an [animation curve](https://api.flutter.dev/flutter/animation/Curves-class.html). +Applied to `PositionComponent`s, this effect can be used to move the component to a new positions, using an [animation curve](https://api.flutter.dev/flutter/animation/Curves-class.html). Usage example: ```dart @@ -28,12 +28,18 @@ import 'package:flame/effects/effects.dart'; // Square is a PositionComponent square.addEffect(MoveEffect( - destination: Position(200, 200), + path: [Vector2(200, 200), Vector2(200, 100), Vector(0, 50)], speed: 250.0, curve: Curves.bounceInOut, + isRelative: false, )); ``` +If you want the positions in the path list to be relative to the components last position, and not absolute values on the screen, then you can set `isRelative = true`. +When you use that, the next position in the list will be relative to the previous position in the list, or if it is the first element of the list it is relative to the components position. +So if you have a component which is positioned at `Vector2(100, 100)` and you use `isRelative = true` with the following path list `path: [Vector(20, 0), Vector(0, 50)]`, then the component will +first move to `(120, 0)` and then to `(120, 100)`. + ## ScaleEffect Applied to `PositionComponent`s, this effect can be used to change the width and height of the component, using an [animation curve](https://api.flutter.dev/flutter/animation/Curves-class.html). diff --git a/doc/examples/effects/sequence_effect/lib/main.dart b/doc/examples/effects/sequence_effect/lib/main.dart index 689a48924..abdefac93 100644 --- a/doc/examples/effects/sequence_effect/lib/main.dart +++ b/doc/examples/effects/sequence_effect/lib/main.dart @@ -44,9 +44,9 @@ class MyGame extends BaseGame with TapDetector { final move2 = MoveEffect( path: [ - Vector2(dx, dy + 20), - Vector2(dx - 20, dy - 20), - Vector2(dx + 20, dy), + Vector2(dx, dy + 50), + Vector2(dx - 50, dy - 50), + Vector2(dx + 50, dy), ], speed: 150.0, curve: Curves.easeIn, @@ -72,14 +72,15 @@ class MyGame extends BaseGame with TapDetector { final combination = CombinedEffect( effects: [move2, rotate], - isAlternating: true, + isAlternating: false, + isInfinite: true, ); final sequence = SequenceEffect( effects: [move1, scale, combination], - isInfinite: false, - isAlternating: true, + isInfinite: true, + isAlternating: false, ); - greenSquare.addEffect(sequence); + greenSquare.addEffect(combination); } } diff --git a/doc/examples/effects/simple/lib/main_move.dart b/doc/examples/effects/simple/lib/main_move.dart index 73a9f0c5e..ab09b0220 100644 --- a/doc/examples/effects/simple/lib/main_move.dart +++ b/doc/examples/effects/simple/lib/main_move.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flame/extensions/vector2.dart'; import 'package:flame/game.dart'; import 'package:flame/gestures.dart'; import 'package:flame/effects/effects.dart'; @@ -17,9 +18,19 @@ class MyGame extends BaseGame with TapDetector { @override void onTapUp(details) { square.addEffect(MoveEffect( - path: [details.localPosition.toVector2()], + path: [ + details.localPosition.toVector2().clone(), + Vector2(100, 100), + Vector2(50, 120), + Vector2(200, 400), + Vector2(150, 0), + Vector2(100, 300), + ], speed: 250.0, curve: Curves.bounceInOut, + isRelative: false, + isInfinite: true, + isAlternating: true, )); } } diff --git a/lib/effects/effects.dart b/lib/effects/effects.dart index 15d136925..1dc87ff76 100644 --- a/lib/effects/effects.dart +++ b/lib/effects/effects.dart @@ -31,6 +31,11 @@ abstract class PositionComponentEffect { double driftTime = 0.0; int curveDirection = 1; + /// Used to be able to determine the start state of the component + Vector2 originalPosition; + double originalAngle; + Vector2 originalSize; + /// Used to be able to determine the end state of a sequence of effects Vector2 endPosition; double endAngle; @@ -70,6 +75,9 @@ abstract class PositionComponentEffect { @mustCallSuper void initialize(PositionComponent _comp) { component = _comp; + originalPosition = component.position; + originalAngle = component.angle; + originalSize = component.size; /// You need to set the travelTime during the initialization of the /// extending effect diff --git a/lib/effects/move_effect.dart b/lib/effects/move_effect.dart index 9b328de5e..631367096 100644 --- a/lib/effects/move_effect.dart +++ b/lib/effects/move_effect.dart @@ -25,7 +25,6 @@ class MoveEffect extends PositionComponentEffect { double speed; Curve curve; Vector2 _startPosition; - Vector2 _peakPosition; MoveEffect({ @required this.path, @@ -61,10 +60,10 @@ class MoveEffect extends PositionComponentEffect { } else { _movePath = path; } - print(_movePath); - _peakPosition = isRelative ? path.last : path.last - _startPosition; if (!isAlternating) { - endPosition = _peakPosition; + endPosition = _movePath.last; + } else { + endPosition = _startPosition; } double pathLength = 0; @@ -91,9 +90,16 @@ class MoveEffect extends PositionComponentEffect { ); lastPosition = v; } - print(_percentagePath); travelTime = pathLength / speed; } + + @override + void reset() { + super.reset(); + if(_percentagePath?.isNotEmpty ?? false) { + _currentSubPath = _percentagePath.first; + } + } @override void update(double dt) { diff --git a/lib/effects/sequence_effect.dart b/lib/effects/sequence_effect.dart index 6f89b1e1d..66ed7c43a 100644 --- a/lib/effects/sequence_effect.dart +++ b/lib/effects/sequence_effect.dart @@ -5,10 +5,10 @@ import 'effects.dart'; class SequenceEffect extends PositionComponentEffect { final List effects; - int _currentIndex = 0; + int _currentIndex; PositionComponentEffect currentEffect; bool _currentWasAlternating; - double _driftModifier = 0.0; + double _driftModifier; SequenceEffect({ @required this.effects, @@ -26,9 +26,7 @@ class SequenceEffect extends PositionComponentEffect { void initialize(PositionComponent _comp) { super.initialize(_comp); _currentIndex = 0; - final originalSize = _comp.size; - final originalPosition = _comp.position; - final originalAngle = _comp.angle; + _driftModifier = 0.0; effects.forEach((effect) { effect.reset(); _comp.size = endSize; @@ -43,9 +41,9 @@ class SequenceEffect extends PositionComponentEffect { 0, (time, effect) => time + effect.totalTravelTime, ); - component.size = originalSize; component.position = originalPosition; component.angle = originalAngle; + component.size = originalSize; currentEffect = effects.first; _currentWasAlternating = currentEffect.isAlternating; } @@ -57,20 +55,30 @@ class SequenceEffect extends PositionComponentEffect { } super.update(dt); + // If the last effect's time to completion overshot its total time, add that + // time to the first time step of the next effect. currentEffect.update(dt + _driftModifier); _driftModifier = 0.0; if (currentEffect.hasFinished()) { _driftModifier = currentEffect.driftTime; - currentEffect.isAlternating = _currentWasAlternating; _currentIndex++; final iterationSize = isAlternating ? effects.length * 2 : effects.length; - if (_currentIndex != 0 && _currentIndex % iterationSize == 0) { + if (_currentIndex != 0 + && _currentIndex == iterationSize + && (currentEffect.isAlternating || + currentEffect.isAlternating == isAlternating)) { isInfinite ? reset() : dispose(); return; } final orderedEffects = curveDirection.isNegative ? effects.reversed.toList() : effects; + // Make sure the current effect has the `isAlternating` value it + // initially started with + currentEffect.isAlternating = _currentWasAlternating; + // Get the next effect that should be executed currentEffect = orderedEffects[_currentIndex % effects.length]; + // Keep track of what value of `isAlternating` the effect had from the + // start _currentWasAlternating = currentEffect.isAlternating; if (isAlternating && !currentEffect.isAlternating && @@ -84,6 +92,10 @@ class SequenceEffect extends PositionComponentEffect { @override void reset() { super.reset(); + component.position = originalPosition; + component.angle = originalAngle; + component.size = originalSize; initialize(component); + //effects.forEach((e) => e.reset()); } }