flixel/effects/FlxFlicker.hx
package flixel.effects;
import flixel.FlxObject;
import flixel.util.FlxDestroyUtil.IFlxDestroyable;
import flixel.util.FlxPool;
import flixel.util.FlxTimer;
/**
* The retro flickering effect with callbacks.
* You can use this as a mixin in any FlxObject subclass or by calling the static functions.
* @author pixelomatic
*/
class FlxFlicker implements IFlxDestroyable
{
static var _pool:FlxPool<FlxFlicker> = new FlxPool<FlxFlicker>(FlxFlicker.new);
/**
* Internal map for looking up which objects are currently flickering and getting their flicker data.
*/
static var _boundObjects:Map<FlxObject, FlxFlicker> = new Map<FlxObject, FlxFlicker>();
/**
* A simple flicker effect for sprites using a `FlxTimer` to toggle visibility.
*
* @param Object The object.
* @param Duration How long to flicker for (in seconds). `0` means "forever".
* @param Interval In what interval to toggle visibility. Set to `FlxG.elapsed` if `<= 0`!
* @param EndVisibility Force the visible value when the flicker completes,
* useful with fast repetitive use.
* @param ForceRestart Force the flicker to restart from beginning,
* discarding the flickering effect already in progress if there is one.
* @param CompletionCallback An optional callback that will be triggered when a flickering has finished.
* @param ProgressCallback An optional callback that will be triggered when visibility is toggled.
* @return The `FlxFlicker` object. `FlxFlicker`s are pooled internally, so beware of storing references.
*/
public static function flicker(Object:FlxObject, Duration:Float = 1, Interval:Float = 0.04, EndVisibility:Bool = true, ForceRestart:Bool = true,
?CompletionCallback:FlxFlicker->Void, ?ProgressCallback:FlxFlicker->Void):FlxFlicker
{
if (isFlickering(Object))
{
if (ForceRestart)
{
stopFlickering(Object);
}
else
{
// Ignore this call if object is already flickering.
return _boundObjects[Object];
}
}
if (Interval <= 0)
{
Interval = FlxG.elapsed;
}
var flicker:FlxFlicker = _pool.get();
flicker.start(Object, Duration, Interval, EndVisibility, CompletionCallback, ProgressCallback);
return _boundObjects[Object] = flicker;
}
/**
* Returns whether the object is flickering or not.
*
* @param Object The object to test.
*/
public static function isFlickering(Object:FlxObject):Bool
{
return _boundObjects.exists(Object);
}
/**
* Stops flickering of the object. Also it will make the object visible.
*
* @param Object The object to stop flickering.
*/
public static function stopFlickering(Object:FlxObject):Void
{
var boundFlicker:FlxFlicker = _boundObjects[Object];
if (boundFlicker != null)
{
boundFlicker.stop();
}
}
/**
* The flickering object.
*/
public var object(default, null):FlxObject;
/**
* The final visibility of the object after flicker is complete.
*/
public var endVisibility(default, null):Bool;
/**
* The flicker timer. You can check how many seconds has passed since flickering started etc.
*/
public var timer(default, null):FlxTimer;
/**
* The callback that will be triggered after flicker has completed.
*/
public var completionCallback(default, null):FlxFlicker->Void;
/**
* The callback that will be triggered every time object visiblity is changed.
*/
public var progressCallback(default, null):FlxFlicker->Void;
/**
* The duration of the flicker (in seconds). `0` means "forever".
*/
public var duration(default, null):Float;
/**
* The interval of the flicker.
*/
public var interval(default, null):Float;
/**
* Nullifies the references to prepare object for reuse and avoid memory leaks.
*/
public function destroy():Void
{
object = null;
timer = null;
completionCallback = null;
progressCallback = null;
}
/**
* Starts flickering behavior.
*/
function start(Object:FlxObject, Duration:Float, Interval:Float, EndVisibility:Bool, ?CompletionCallback:FlxFlicker->Void,
?ProgressCallback:FlxFlicker->Void):Void
{
object = Object;
duration = Duration;
interval = Interval;
completionCallback = CompletionCallback;
progressCallback = ProgressCallback;
endVisibility = EndVisibility;
timer = new FlxTimer().start(interval, flickerProgress, Std.int(duration / interval));
}
/**
* Temporarily pause the flickering, so it can be resumed later.
*/
public function pause():Void
{
if (timer == null)
return;
timer.active = false;
}
/**
* Resume the flickering after it has been temporarily paused.
*/
public function resume():Void
{
if (timer == null)
return;
timer.active = true;
}
/**
* Prematurely ends flickering.
*/
public function stop():Void
{
timer.cancel();
object.visible = true;
release();
}
/**
* Unbinds the object from flicker and releases it into pool for reuse.
*/
function release():Void
{
_boundObjects.remove(object);
_pool.put(this);
}
/**
* Just a helper function for flicker() to update object's visibility.
*/
function flickerProgress(timer:FlxTimer):Void
{
object.visible = !object.visible;
if (progressCallback != null)
progressCallback(this);
if (timer.loops > 0 && timer.loopsLeft == 0)
{
object.visible = endVisibility;
if (completionCallback != null)
completionCallback(this);
if (this.timer == timer)
release();
}
}
/**
* Internal constructor. Use static methods.
*/
@:keep
function new() {}
}