diff --git a/flixel/tweens/FlxTween.hx b/flixel/tweens/FlxTween.hx index 8f1c62afb4..93562adcbf 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:Null; 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; setDelays(Options.startDelay, Options.loopDelay); this.manager = manager != null ? manager : globalManager; } @@ -619,13 +621,22 @@ class FlxTween implements IFlxDestroyable function update(elapsed:Float):Void { - _secondsSinceStart += elapsed; + var preTick:Float = _secondsSinceStart; + var postTick:Float = (_secondsSinceStart += elapsed); + var delay:Float = (executions > 0) ? loopDelay : startDelay; if (_secondsSinceStart < delay) { return; } - scale = Math.max((_secondsSinceStart - delay), 0) / duration; + + if (framerate != null && 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 +658,7 @@ class FlxTween implements IFlxDestroyable } else { - if (onUpdate != null) + if (postTick > preTick && onUpdate != null) onUpdate(this); } } @@ -919,6 +930,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:Float; + /** * Optional start callback function. */ diff --git a/flixel/tweens/misc/FlickerTween.hx b/flixel/tweens/misc/FlickerTween.hx index b139845631..4c1032bd9a 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:Float; + /** * Optional start callback function. */ diff --git a/tests/unit/src/flixel/tweens/FlxTweenTest.hx b/tests/unit/src/flixel/tweens/FlxTweenTest.hx index 69a24b34e3..0689de2723 100644 --- a/tests/unit/src/flixel/tweens/FlxTweenTest.hx +++ b/tests/unit/src/flixel/tweens/FlxTweenTest.hx @@ -432,6 +432,26 @@ class FlxTweenTest extends FlxTest Assert.isTrue(tween3Updated); } + @Test + function testTweenFramerate() + { + // no given tween framerate + var tweenUpdatesDefault:Int = 0; + var tweenDefault:FlxTween = FlxTween.tween(this, {value: 1000}, 2, {startDelay: 0.54321, onUpdate: function(_) tweenUpdatesDefault++}); + step(FlxG.updateFramerate * 3); // 3 full seconds + Assert.areEqual(FlxG.updateFramerate * 2, tweenUpdatesDefault); + + // various tween framerate values + var testFramerates:Array = [5, 10, 10.1, 24, 29.9, 30, 30.1, 31, 59.9, 60, 100]; + for (framerate in testFramerates) + { + var tweenUpdates:Int = 0; + var tween:FlxTween = FlxTween.tween(this, {value: 1000}, 2, {startDelay: 0.54321, framerate: framerate, onUpdate: function(_) tweenUpdates++}); + step(FlxG.updateFramerate * 3); // 3 full seconds + Assert.areEqual(Std.int(Math.ceil(Math.min(framerate, FlxG.updateFramerate) * 2)), tweenUpdates); + } + } + function makeTween(duration:Float, onComplete:TweenCallback, ?onUpdate:TweenCallback):FlxTween { var foo = {f: 0};