diff --git a/flixel/tweens/FlxTween.hx b/flixel/tweens/FlxTween.hx index 8f1c62afb4..e363e284ab 100644 --- a/flixel/tweens/FlxTween.hx +++ b/flixel/tweens/FlxTween.hx @@ -505,6 +505,7 @@ class FlxTween implements IFlxDestroyable public var active(default, set):Bool = false; public var duration:Float = 0; public var ease:EaseFunction; + public var framerate:Float; public var onStart:TweenCallback; public var onUpdate:TweenCallback; public var onComplete:TweenCallback; @@ -562,6 +563,7 @@ class FlxTween implements IFlxDestroyable onUpdate = Options.onUpdate; onComplete = Options.onComplete; ease = Options.ease; + framerate = Options.framerate != null ? Options.framerate : 0; setDelays(Options.startDelay, Options.loopDelay); this.manager = manager != null ? manager : globalManager; } @@ -619,13 +621,23 @@ class FlxTween implements IFlxDestroyable function update(elapsed:Float):Void { + var preTick:Float = _secondsSinceStart; _secondsSinceStart += elapsed; + var postTick:Float = _secondsSinceStart; + var delay:Float = (executions > 0) ? loopDelay : startDelay; if (_secondsSinceStart < delay) { return; } - scale = Math.max((_secondsSinceStart - delay), 0) / duration; + + if (framerate > 0) + { + preTick = Math.fround(preTick * framerate) / framerate; + postTick = Math.fround(postTick * framerate) / framerate; + } + + scale = Math.max((postTick - delay), 0) / duration; if (ease != null) { scale = ease(scale); @@ -647,7 +659,7 @@ class FlxTween implements IFlxDestroyable } else { - if (onUpdate != null) + if (postTick > preTick && onUpdate != null) onUpdate(this); } } @@ -919,6 +931,12 @@ typedef TweenOptions = */ @:optional var ease:EaseFunction; + /** + * Optional set framerate for this tween to update at. + * This also affects how often `onUpdate` is called. + */ + @:optional var framerate:Null; + /** * Optional start callback function. */ diff --git a/flixel/tweens/misc/FlickerTween.hx b/flixel/tweens/misc/FlickerTween.hx index b139845631..3ebc11d855 100644 --- a/flixel/tweens/misc/FlickerTween.hx +++ b/flixel/tweens/misc/FlickerTween.hx @@ -23,6 +23,13 @@ typedef FlickerTweenOptions = */ @:optional var ease:EaseFunction; + /** + * Optional set framerate for this tween to update at. + * This also affects how often `onUpdate` is called. + * Not to be confused with `period` for flickering. + */ + @:optional var framerate:Null; + /** * Optional start callback function. */ diff --git a/tests/unit/src/flixel/tweens/FlxTweenTest.hx b/tests/unit/src/flixel/tweens/FlxTweenTest.hx index 69a24b34e3..9bd8475f40 100644 --- a/tests/unit/src/flixel/tweens/FlxTweenTest.hx +++ b/tests/unit/src/flixel/tweens/FlxTweenTest.hx @@ -4,6 +4,7 @@ import flixel.FlxBasic; import flixel.FlxG; import flixel.math.FlxPoint; import flixel.tweens.FlxTween.TweenCallback; +import flixel.tweens.FlxTween.TweenOptions; import flixel.util.FlxTimer; import massive.munit.Assert; @@ -432,6 +433,35 @@ class FlxTweenTest extends FlxTest Assert.isTrue(tween3Updated); } + function assertTweenUpdates(duration:Float, ?fps:Float, ?options:TweenOptions, expected:Int) + { + var updates = 0; + + if (options == null) + options = {}; + + if (fps != null) + options.framerate = fps; + + options.onUpdate = function(_) ++updates; + options.onComplete = function(_) Assert.areEqual(expected, updates); + FlxTween.tween({value: 0.0}, {value: 1}, 2.0, options); + } + + @Test + function testTweenFramerate() + { + assertTweenUpdates(2.0, null, null, 59); + assertTweenUpdates(2.0, 0, null, 59); + assertTweenUpdates(2.0, 5, null, 10); + assertTweenUpdates(2.0, 10, {startDelay: 0.5}, 20); + assertTweenUpdates(2.0, 10.1, null, 20); + assertTweenUpdates(2.0, 29.9, null, 59); + assertTweenUpdates(2.0, 100, null, 59); + + step(FlxG.updateFramerate * 3); // 3 full seconds + } + function makeTween(duration:Float, onComplete:TweenCallback, ?onUpdate:TweenCallback):FlxTween { var foo = {f: 0};