From 1e38b0e5ef83bf3e8c9cb1f3f1e206064620e1aa Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 6 Nov 2016 03:31:12 -0800 Subject: [PATCH] FlxTween: add cancelChain() (#1988) --- flixel/tweens/FlxTween.hx | 34 ++++++++++- tests/unit/src/flixel/tweens/FlxTweenTest.hx | 60 ++++++++++++++++++++ 2 files changed, 91 insertions(+), 3 deletions(-) diff --git a/flixel/tweens/FlxTween.hx b/flixel/tweens/FlxTween.hx index b2c9e9c437..35715547de 100644 --- a/flixel/tweens/FlxTween.hx +++ b/flixel/tweens/FlxTween.hx @@ -373,6 +373,7 @@ class FlxTween implements IFlxDestroyable private var _running:Bool = false; private var _waitingForRestart:Bool = false; private var _chainedTweens:Array; + private var _nextTweenInChain:FlxTween; /** * This function is called when tween is created, or recycled. @@ -409,6 +410,7 @@ class FlxTween implements IFlxDestroyable ease = null; manager = null; _chainedTweens = null; + _nextTweenInChain = null; } /** @@ -495,8 +497,10 @@ class FlxTween implements IFlxDestroyable } /** - * Immediately stops the Tween and removes it from the - * TweenManager without calling the complete callback. + * Immediately stops the Tween and removes it from its + * `manager` without calling the `onComplete` callback. + * + * Yields control to the next chained Tween if one exists. */ public function cancel():Void { @@ -505,6 +509,27 @@ class FlxTween implements IFlxDestroyable if (manager != null) manager.remove(this); } + + /** + * Immediately stops the Tween and removes it from its + * `manager` without calling the `onComplete` callback + * or yielding control to the next chained Tween if one exists. + * + * If control has already been passed on, forwards the cancellation + * request along the chain to the currently active Tween. + */ + public function cancelChain():Void + { + // Pass along the cancellation request. + if (_nextTweenInChain != null) + _nextTweenInChain.cancelChain(); + + // Prevent yielding control to any chained tweens. + if (_chainedTweens != null) + _chainedTweens = null; + + cancel(); + } private function finish():Void { @@ -570,7 +595,10 @@ class FlxTween implements IFlxDestroyable if (_chainedTweens == null || _chainedTweens.length <= 0) return; - doNextTween(_chainedTweens.shift()); + // Remember next tween to enable cancellation of the chain. + _nextTweenInChain = _chainedTweens.shift(); + + doNextTween(_nextTweenInChain); _chainedTweens = null; } diff --git a/tests/unit/src/flixel/tweens/FlxTweenTest.hx b/tests/unit/src/flixel/tweens/FlxTweenTest.hx index 9c918b031f..72680fed78 100644 --- a/tests/unit/src/flixel/tweens/FlxTweenTest.hx +++ b/tests/unit/src/flixel/tweens/FlxTweenTest.hx @@ -82,6 +82,66 @@ class FlxTweenTest extends FlxTest step(); } + @Test + function testCancelChainFirstTweenUnfinished() + { + var chain = createChain(4); + + while (!chain.updated[0]) + step(); + + Assert.isFalse(chain.completed[0]); + + chain.tweens[0].cancelChain(); + + for (i in 0...chain.count) + finishTween(chain.tweens[i]); + + for (i in 1...chain.count) + Assert.isFalse(chain.updated[i] || chain.completed[i]); + } + + @Test + function testCancelChainFirstTweenFinished() + { + var chain = createChain(4); + + while (!chain.updated[1]) + step(); + + Assert.isTrue(chain.updated[0] && chain.completed[0]); + Assert.isFalse(chain.completed[1]); + + chain.tweens[0].cancelChain(); + + for (i in 1...chain.count) + finishTween(chain.tweens[i]); + + for (i in 2...chain.count) + Assert.isFalse(chain.updated[i] || chain.completed[i]); + } + + function createChain(count:Int) + { + var updated = [for (i in 0...count) false]; + var completed = [for (i in 0...count) false]; + var tweens = [for (i in 0...count) + makeTween(0.1, + function (_) completed[i] = true, + function (_) updated[i] = true + )]; + + for (i in 1...count) + tweens[0].wait(0.1).then(tweens[i]); + + return { + count: count, + updated: updated, + completed: completed, + tweens: tweens + } + } + @Test function testLinearChain() {