haxepunk/HXP.hx
package haxepunk;
import haxe.Timer;
import haxepunk.Tween.TweenType;
import haxepunk.input.Mouse;
import haxepunk.math.MathUtil;
import haxepunk.math.Random;
import haxepunk.math.Rectangle;
import haxepunk.math.Vector2;
import haxepunk.tweens.misc.Alarm;
import haxepunk.tweens.misc.MultiVarTween;
import haxepunk.utils.HaxelibInfo;
/**
* Static catch-all class used to access global properties and functions.
*/
class HXP
{
/**
* The HaxePunk version.
* Format: Major.Minor.Patch
*/
public static inline var VERSION:String = HaxelibInfo.version;
/**
* Width of the game.
*/
public static var width:Int;
/**
* Height of the game.
*/
public static var height:Int;
/**
* Width of the window.
*/
public static var windowWidth:Int = 0;
/**
* Height of the window.
*/
public static var windowHeight:Int = 0;
/**
* If the game is running at a fixed framerate.
*/
public static var fixed:Bool;
/**
* The framerate assigned to the stage.
*/
public static var frameRate:Float = 0;
/**
* The framerate assigned to the stage.
*/
public static var assignedFrameRate:Float;
/**
* Game time elapsed since the last frame. For fixed framerate, this will be
* a constant 1/framerate.
*/
public static var elapsed:Float;
/**
* Timescale applied to HXP.elapsed.
*/
public static var rate:Float = 1;
/**
* The Screen object, use to transform or offset the Screen.
*/
public static var screen:Screen;
/**
* A rectangle representing the size of the screen.
*/
public static var bounds:Rectangle;
/**
* The default font file to use, by default: font/monofonto.ttf.
*/
public static var defaultFont:String = "font/monofonto";
/**
* Point used to determine drawing offset in the render loop.
*/
public static var camera(get, never):Camera;
static inline function get_camera() return scene == null ? null : scene.camera;
/**
* Global tweener for tweening between multiple scenes
*/
public static var tweener:Tweener = new Tweener();
/**
* Whether the game has focus or not
*/
public static var focused:Bool = false;
/**
* Half the screen width.
*/
public static var halfWidth(default, null):Float;
/**
* Half the screen height.
*/
public static var halfHeight(default, null):Float;
/**
* Defines the allowed orientations
*/
public static var orientations:Array<Int> = [];
/**
* True if the scale of the screen has changed.
*/
public static var needsResize:Bool = false;
public static var cursor(default, set):Cursor;
static inline function set_cursor(cursor:Cursor = null):Cursor
{
if (HXP.cursor == cursor) return cursor;
if (cursor == null) Mouse.showCursor();
else Mouse.hideCursor();
return HXP.cursor = cursor;
}
/**
* The choose function randomly chooses and returns one of the provided values.
*/
public static var choose(get, null):Dynamic;
static function get_choose():Dynamic
{
return Reflect.makeVarArgs(_choose);
}
static inline function _choose(objs:Array<Dynamic>):Dynamic
{
if (objs == null || objs.length == 0)
{
throw "Can't choose a random element on an empty array";
}
if (Std.isOfType(objs[0], Array)) // Passed an Array
{
var c:Array<Dynamic> = cast(objs[0], Array<Dynamic>);
if (c.length != 0)
{
return c[Random.randInt(c.length)];
}
else
{
throw "Can't choose a random element on an empty array";
}
}
else // Passed multiple args
{
return objs[Random.randInt(objs.length)];
}
}
/**
* The currently active Scene object. When you set this, the Scene is flagged
* to switch, but won't actually do so until the end of the current frame.
*/
public static var scene(get, set):Scene;
static inline function get_scene():Scene return engine.scene;
static inline function set_scene(value:Scene):Scene return engine.scene = value;
/**
* If we're currently rendering, this is the Scene being rendered now.
*/
public static var renderingScene:Scene;
/**
* Resize the screen.
* @param width New width.
* @param height New height.
*/
public static function resize(width:Int, height:Int)
{
// resize scene to scale
HXP.windowWidth = width;
HXP.windowHeight = height;
HXP.screen.resize(width, height);
HXP.halfWidth = HXP.width / 2;
HXP.halfHeight = HXP.height / 2;
HXP.bounds.width = width;
HXP.bounds.height = height;
for (scene in HXP.engine) scene._resize();
HXP.needsResize = false;
}
/**
* Empties an array of its' contents
* @param array filled array
*/
public static inline function clear<T>(array:Array<T>)
{
#if cpp
// splice causes Array allocation, so prefer pop for most arrays
if (array.length > 256) array.splice(0, array.length);
else while (array.length > 0) array.pop();
#else
untyped array.length = 0;
#end
}
/**
* Sets the camera position.
* @param x X position.
* @param y Y position.
*/
public static inline function setCamera(x:Float = 0, y:Float = 0)
{
camera.x = x;
camera.y = y;
}
/**
* Resets the camera position.
*/
public static inline function resetCamera()
{
camera.x = camera.y = 0;
}
/**
* Toggles between windowed and fullscreen modes
*/
public static var fullscreen(get, set):Bool;
static inline function get_fullscreen():Bool return HXP.app.fullscreen;
static inline function set_fullscreen(value:Bool):Bool return HXP.app.fullscreen = value;
/**
* Global volume factor for all sounds, a value from 0 to 1.
*/
public static var volume(default, set):Float = 1;
static function set_volume(value:Float):Float
{
value = MathUtil.clamp(value, 0, 1);
if (volume == value) return value;
volume = value;
Sfx.onGlobalUpdated(false);
return volume;
}
/**
* Global panning factor for all sounds, a value from -1 to 1.
* Panning only applies to mono sounds. It is ignored on stereo.
*/
public static var pan(get, set):Float;
static inline function get_pan():Float return _pan;
static function set_pan(value:Float):Float
{
if (value < -1) value = -1;
if (value > 1) value = 1;
if (_pan == value) return value;
_pan = value;
Sfx.onGlobalUpdated(true);
return _pan;
}
/**
* Optimized version of Lambda.indexOf for Array on dynamic platforms (Lambda.indexOf is less performant on those targets).
*
* @param arr The array to look into.
* @param param The value to look for.
* @return Returns the index of the first element [v] within Array [arr].
* This function uses operator [==] to check for equality.
* If [v] does not exist in [arr], the result is -1.
**/
public static inline function indexOf<T>(arr:Array<T>, v:T):Int
{
#if (haxe_ver >= 3.1)
return arr.indexOf(v);
#elseif js
return untyped arr.indexOf(v);
#else
return std.Lambda.indexOf(arr, v);
#end
}
/**
* Returns the next item after current in the list of options.
* @param current The currently selected item (must be one of the options).
* @param options An array of all the items to cycle through.
* @param loop If true, will jump to the first item after the last item is reached.
* @return The next item in the list.
*/
public static inline function next<T>(current:T, options:Array<T>, loop:Bool = true):T
{
if (loop)
return options[(indexOf(options, current) + 1) % options.length];
else
return options[Std.int(Math.min(indexOf(options, current) + 1, options.length - 1))];
}
/**
* Returns the item previous to the current in the list of options.
* @param current The currently selected item (must be one of the options).
* @param options An array of all the items to cycle through.
* @param loop If true, will jump to the last item after the first is reached.
* @return The previous item in the list.
*/
public static inline function prev<T>(current:T, options:Array<T>, loop:Bool = true):T
{
if (loop)
return options[((indexOf(options, current) - 1) + options.length) % options.length];
else
return options[Std.int(Math.max(indexOf(options, current) - 1, 0))];
}
/**
* Swaps the current item between a and b. Useful for quick state/string/value swapping.
* @param current The currently selected item.
* @param a Item a.
* @param b Item b.
* @return Returns a if current is b, and b if current is a.
*/
public static inline function swap<T>(current:T, a:T, b:T):T
{
return current == a ? b : a;
}
/**
* Binary insertion sort
* @param list A list to insert into
* @param key The key to insert
* @param compare A comparison function to determine sort order
*/
public static function insertSortedKey<T>(list:Array<T>, key:T, compare:T->T->Int):Void
{
var result:Int = 0,
mid:Int = 0,
min:Int = 0,
max:Int = list.length - 1;
while (max >= min)
{
mid = min + Std.int((max - min) / 2);
result = compare(list[mid], key);
if (result > 0) max = mid - 1;
else if (result < 0) min = mid + 1;
else return;
}
list.insert(result > 0 ? mid : mid + 1, key);
}
/**
* Sets a time flag.
* @return Time elapsed (in milliseconds) since the last time flag was set.
*/
public static inline function timeFlag():Float
{
var t:Float = Timer.stamp(),
e:Float = t - _time;
_time = t;
return e;
}
/**
* Tweens numeric public properties of an Object. Shorthand for creating a MultiVarTween tween, starting it and adding it to a Tweener.
* @param object The object containing the properties to tween.
* @param values An object containing key/value pairs of properties and target values.
* @param duration Duration of the tween.
* @param options An object containing key/value pairs of the following optional parameters:
* type Tween type.
* complete Optional completion callback function.
* ease Optional easer function.
* tweener The Tweener to add this Tween to.
* @return The added MultiVarTween object.
*
* Example: HXP.tween(object, { x: 500, y: 350 }, 2.0, { ease: Float -> Float, complete: onComplete } );
*/
public static function tween(object:Dynamic, values:Dynamic, duration:Float, options:Dynamic = null):MultiVarTween
{
if (options != null && Reflect.hasField(options, "delay"))
{
var delay:Float = options.delay;
Reflect.deleteField( options, "delay" );
HXP.alarm(delay, function () HXP.tween(object, values, duration, options));
return null;
}
var type:TweenType = TweenType.OneShot,
complete:Void -> Void = null,
ease:Float -> Float = null,
tweener:Tweener = HXP.tweener;
if (Std.isOfType(object, Tweener)) tweener = cast(object, Tweener);
if (options != null)
{
if (Reflect.hasField(options, "type")) type = options.type;
if (Reflect.hasField(options, "complete")) complete = options.complete;
if (Reflect.hasField(options, "ease")) ease = options.ease;
if (Reflect.hasField(options, "tweener")) tweener = options.tweener;
}
var tween:MultiVarTween = new MultiVarTween(type);
if (complete != null) tween.onComplete.bind(complete);
tween.tween(object, values, duration, ease);
tweener.addTween(tween, true);
return tween;
}
/**
* Schedules a callback for the future. Shorthand for creating an Alarm tween, starting it and adding it to a Tweener.
* @param delay The duration to wait before calling the callback.
* @param complete The function to be called when complete.
* @param type Tween type.
* @param tweener The Tweener object to add this Alarm to. Defaults to HXP.tweener.
* @return The added Alarm object.
*
* Example: HXP.alarm(5.0, callbackFunction, TweenType.Looping); // Calls callbackFunction every 5 seconds
*/
public static function alarm(delay:Float, complete:Void -> Void, ?type:TweenType, ?tweener:Tweener):Alarm
{
if (type == null) type = TweenType.OneShot;
if (tweener == null) tweener = HXP.tweener;
var alarm:Alarm = new Alarm(delay, complete, type);
tweener.addTween(alarm, true);
return alarm;
}
/**
* Gets an array of frame indices.
* @param from Starting frame.
* @param to Ending frame.
* @param skip Skip amount every frame (eg. use 1 for every 2nd frame).
*
* @return The array.
*/
public static function frames(from:Int, to:Int, skip:Int = 0):Array<Int>
{
var a:Array<Int> = new Array<Int>();
skip++;
if (from < to)
{
while (from <= to)
{
a.push(from);
from += skip;
}
}
else
{
while (from >= to)
{
a.push(from);
from -= skip;
}
}
return a;
}
/**
* Shuffles the elements in the array.
* @param a The Object to shuffle (an Array or Vector).
*/
public static function shuffle<T>(a:Array<T>)
{
var i:Int = a.length, j:Int, t:T;
while (--i > 0)
{
t = a[i];
a[i] = a[j = Random.randInt(i + 1)];
a[j] = t;
}
}
public static var time(null, set):Float;
static inline function set_time(value:Float):Float
{
_time = value;
return _time;
}
// Time information.
static var _time:Float;
@:dox(hide) public static var _updateTime:Float;
@:dox(hide) public static var _gameTime:Float;
@:dox(hide) public static var _systemTime:Float;
// Volume control.
static var _pan:Float = 0;
/** The Engine instance. */
public static var engine:Engine;
public static var app:App;
// Global objects used for rendering, collision, etc.
@:dox(hide) public static var point:Vector2 = new Vector2();
@:dox(hide) public static var point2:Vector2 = new Vector2();
@:dox(hide) public static var zeroCamera:Camera = new Camera();
@:dox(hide) public static var rect:Rectangle = new Rectangle();
@:dox(hide) public static var entity:Entity;
}