291 lines
10 KiB
Haxe
291 lines
10 KiB
Haxe
package iron.system;
|
|
|
|
class Tween {
|
|
|
|
static inline var DEFAULT_OVERSHOOT: Float = 1.70158;
|
|
|
|
static var eases: Array<Float->Float> = [
|
|
easeLinear,
|
|
easeSineIn, easeSineOut, easeSineInOut,
|
|
easeQuadIn, easeQuadOut, easeQuadInOut,
|
|
easeCubicIn, easeCubicOut, easeCubicInOut,
|
|
easeQuartIn, easeQuartOut, easeQuartInOut,
|
|
easeQuintIn, easeQuintOut, easeQuintInOut,
|
|
easeExpoIn, easeExpoOut, easeExpoInOut,
|
|
easeCircIn, easeCircOut, easeCircInOut,
|
|
easeBackIn, easeBackOut, easeBackInOut,
|
|
easeBounceIn, easeBounceOut, easeBounceInOut,
|
|
easeElasticIn, easeElasticOut, easeElasticInOut
|
|
];
|
|
|
|
static var anims: Array<TAnim> = [];
|
|
|
|
static var registered = false;
|
|
static inline function register() {
|
|
registered = true;
|
|
App.notifyOnUpdate(update);
|
|
App.notifyOnReset(function() { App.notifyOnUpdate(update); reset(); });
|
|
}
|
|
|
|
public static function to(anim: TAnim): TAnim {
|
|
if (!registered) register();
|
|
anim._time = 0;
|
|
anim.isPlaying = (anim.delay != null && anim.delay > 0.0) ? false : true;
|
|
|
|
if (anim.ease == null) anim.ease = Ease.Linear;
|
|
|
|
if (anim.target != null && anim.props != null) {
|
|
|
|
anim._comps = []; anim._x = []; anim._y = []; anim._z = []; anim._w = []; anim._normalize = [];
|
|
for (p in Reflect.fields(anim.props)) {
|
|
var val: Dynamic = Reflect.getProperty(anim.target, p);
|
|
if (Std.isOfType(val, iron.math.Vec4) || Std.isOfType(val, iron.math.Quat)) {
|
|
anim._comps.push(4);
|
|
anim._x.push(val.x);
|
|
anim._y.push(val.y);
|
|
anim._z.push(val.z);
|
|
anim._w.push(val.w);
|
|
anim._normalize.push(Std.isOfType(val, iron.math.Quat));
|
|
}
|
|
else {
|
|
anim._comps.push(1);
|
|
anim._x.push(val);
|
|
anim._y.push(0);
|
|
anim._z.push(0);
|
|
anim._w.push(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
anims.push(anim);
|
|
return anim;
|
|
}
|
|
|
|
public static function timer(delay: Float, done: Void->Void): TAnim {
|
|
return to({ target: null, props: null, duration: 0, delay: delay, done: done });
|
|
}
|
|
|
|
public static function stop(anim: TAnim) {
|
|
anim.isPlaying = false;
|
|
anims.remove(anim);
|
|
}
|
|
|
|
public static function reset() {
|
|
anims = [];
|
|
}
|
|
|
|
public static function update() {
|
|
var d = Time.delta;
|
|
var i = anims.length;
|
|
while (i-- > 0 && anims.length > 0) {
|
|
var a = anims[i];
|
|
|
|
if (a.delay > 0) { // Delay
|
|
a.delay -= d;
|
|
if (a.delay > 0) continue;
|
|
}
|
|
|
|
a._time += d;
|
|
a.isPlaying = a._time < a.duration;
|
|
|
|
if (a.target != null) {
|
|
|
|
if (Std.isOfType(a.target, iron.object.Transform)) a.target.dirty = true;
|
|
|
|
// Way too much Reflect trickery..
|
|
var ps = Reflect.fields(a.props);
|
|
for (i in 0...ps.length) {
|
|
var p = ps[i];
|
|
var k = a._time / a.duration;
|
|
if (k > 1) k = 1;
|
|
|
|
if (a._comps[i] == 1) {
|
|
var fromVal: Float = a._x[i];
|
|
var toVal: Float = Reflect.getProperty(a.props, p);
|
|
var val: Float = fromVal + (toVal - fromVal) * eases[a.ease](k);
|
|
Reflect.setProperty(a.target, p, val);
|
|
}
|
|
else { // _comps[i] == 4
|
|
var obj = Reflect.getProperty(a.props, p);
|
|
var toX: Float = Reflect.getProperty(obj, "x");
|
|
var toY: Float = Reflect.getProperty(obj, "y");
|
|
var toZ: Float = Reflect.getProperty(obj, "z");
|
|
var toW: Float = Reflect.getProperty(obj, "w");
|
|
if (a._normalize[i]) {
|
|
var qdot = (a._x[i] * toX) + (a._y[i] * toY) + (a._z[i] * toZ) + (a._w[i] * toW);
|
|
if (qdot < 0.0) {
|
|
toX = -toX; toY = -toY; toZ = -toZ; toW = -toW;
|
|
}
|
|
}
|
|
var x: Float = a._x[i] + (toX - a._x[i]) * eases[a.ease](k);
|
|
var y: Float = a._y[i] + (toY - a._y[i]) * eases[a.ease](k);
|
|
var z: Float = a._z[i] + (toZ - a._z[i]) * eases[a.ease](k);
|
|
var w: Float = a._w[i] + (toW - a._w[i]) * eases[a.ease](k);
|
|
if (a._normalize[i]) {
|
|
var l = Math.sqrt(x * x + y * y + z * z + w * w);
|
|
if (l > 0.0) {
|
|
l = 1.0 / l;
|
|
x *= l; y *= l; z *= l; w *= l;
|
|
}
|
|
}
|
|
var t = Reflect.getProperty(a.target, p);
|
|
Reflect.setProperty(t, "x", x);
|
|
Reflect.setProperty(t, "y", y);
|
|
Reflect.setProperty(t, "z", z);
|
|
Reflect.setProperty(t, "w", w);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (a.isPlaying) {
|
|
if (a.tick != null) a.tick();
|
|
}
|
|
else {
|
|
anims.splice(i, 1);
|
|
i--;
|
|
a.isPlaying = false;
|
|
if (a.done != null) a.done();
|
|
}
|
|
}
|
|
}
|
|
|
|
public static function easeLinear(k: Float): Float { return k; }
|
|
public static function easeSineIn(k: Float): Float { if (k == 0) { return 0; } else if (k == 1) { return 1; } else { return 1 - Math.cos(k * Math.PI / 2); } }
|
|
public static function easeSineOut(k: Float): Float { if (k == 0) { return 0; } else if (k == 1) { return 1; } else { return Math.sin(k * (Math.PI * 0.5)); } }
|
|
public static function easeSineInOut(k: Float): Float { if (k == 0) { return 0; } else if (k == 1) { return 1; } else { return -0.5 * (Math.cos(Math.PI * k) - 1); } }
|
|
public static function easeQuadIn(k: Float): Float { return k * k; }
|
|
public static function easeQuadOut(k: Float): Float { return -k * (k - 2); }
|
|
public static function easeQuadInOut(k: Float): Float { return (k < 0.5) ? 2 * k * k : -2 * ((k -= 1) * k) + 1; }
|
|
public static function easeCubicIn(k: Float): Float { return k * k * k; }
|
|
public static function easeCubicOut(k: Float): Float { return (k = k - 1) * k * k + 1; }
|
|
public static function easeCubicInOut(k: Float): Float { return ((k *= 2) < 1) ? 0.5 * k * k * k : 0.5 * ((k -= 2) * k * k + 2); }
|
|
public static function easeQuartIn(k: Float): Float { return (k *= k) * k; }
|
|
public static function easeQuartOut(k: Float): Float { return 1 - (k = (k = k - 1) * k) * k; }
|
|
public static function easeQuartInOut(k: Float): Float { return ((k *= 2) < 1) ? 0.5 * (k *= k) * k : -0.5 * ((k = (k -= 2) * k) * k - 2); }
|
|
public static function easeQuintIn(k: Float): Float { return k * (k *= k) * k; }
|
|
public static function easeQuintOut(k: Float): Float { return (k = k - 1) * (k *= k) * k + 1; }
|
|
public static function easeQuintInOut(k: Float): Float { return ((k *= 2) < 1) ? 0.5 * k * (k *= k) * k : 0.5 * (k -= 2) * (k *= k) * k + 1; }
|
|
public static function easeExpoIn(k: Float): Float { return k == 0 ? 0 : Math.pow(2, 10 * (k - 1)); }
|
|
public static function easeExpoOut(k: Float): Float { return k == 1 ? 1 : (1 - Math.pow(2, -10 * k)); }
|
|
public static function easeExpoInOut(k: Float): Float { if (k == 0) { return 0; } if (k == 1) { return 1; } if ((k /= 1 / 2.0) < 1.0) { return 0.5 * Math.pow(2, 10 * (k - 1)); } return 0.5 * (2 - Math.pow(2, -10 * --k)); }
|
|
public static function easeCircIn(k: Float): Float { return -(Math.sqrt(1 - k * k) - 1); }
|
|
public static function easeCircOut(k: Float): Float { return Math.sqrt(1 - (k - 1) * (k - 1)); }
|
|
public static function easeCircInOut(k: Float): Float { return k <= .5 ? (Math.sqrt(1 - k * k * 4) - 1) / -2 : (Math.sqrt(1 - (k * 2 - 2) * (k * 2 - 2)) + 1) / 2; }
|
|
public static function easeBackIn(k: Float): Float { if (k == 0) { return 0; } else if (k == 1) { return 1; } else { return k * k * ((DEFAULT_OVERSHOOT + 1) * k - DEFAULT_OVERSHOOT); } }
|
|
public static function easeBackOut(k: Float): Float { if (k == 0) { return 0; } else if (k == 1) { return 1; } else { return ((k = k - 1) * k * ((DEFAULT_OVERSHOOT + 1) * k + DEFAULT_OVERSHOOT) + 1); } }
|
|
public static function easeBackInOut(k: Float): Float { if (k == 0) { return 0; } else if (k == 1) { return 1; } else if ((k *= 2) < 1) { return (0.5 * (k * k * (((DEFAULT_OVERSHOOT * 1.525) + 1) * k - DEFAULT_OVERSHOOT * 1.525))); } else { return (0.5 * ((k -= 2) * k * (((DEFAULT_OVERSHOOT * 1.525) + 1) * k + DEFAULT_OVERSHOOT * 1.525) + 2)); } }
|
|
public static function easeBounceIn(k: Float): Float { return 1 - easeBounceOut(1 - k); }
|
|
public static function easeBounceOut(k: Float): Float { return if (k < (1 / 2.75)) { 7.5625 * k * k; } else if (k < (2 / 2.75)) { 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75; } else if (k < (2.5 / 2.75)) { 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375; } else { 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375; } }
|
|
public static function easeBounceInOut(k: Float): Float { return (k < 0.5) ? easeBounceIn(k * 2) * 0.5 : easeBounceOut(k * 2 - 1) * 0.5 + 0.5; }
|
|
|
|
public static function easeElasticIn(k: Float): Float {
|
|
var s: Null<Float> = null;
|
|
var a = 0.1, p = 0.4;
|
|
if (k == 0) {
|
|
return 0;
|
|
}
|
|
if (k == 1) {
|
|
return 1;
|
|
}
|
|
if (a < 1) {
|
|
a = 1;
|
|
s = p / 4;
|
|
}
|
|
else {
|
|
s = p * Math.asin(1 / a) / (2 * Math.PI);
|
|
}
|
|
return -(a * Math.pow(2, 10 * (k -= 1)) * Math.sin((k - s) * (2 * Math.PI) / p));
|
|
}
|
|
|
|
public static function easeElasticOut(k: Float): Float {
|
|
var s: Null<Float> = null;
|
|
var a = 0.1, p = 0.4;
|
|
if (k == 0) {
|
|
return 0;
|
|
}
|
|
if (k == 1) {
|
|
return 1;
|
|
}
|
|
if (a < 1) {
|
|
a = 1;
|
|
s = p / 4;
|
|
}
|
|
else {
|
|
s = p * Math.asin(1 / a) / (2 * Math.PI);
|
|
}
|
|
return (a * Math.pow(2, -10 * k) * Math.sin((k - s) * (2 * Math.PI) / p) + 1);
|
|
}
|
|
|
|
public static function easeElasticInOut(k: Float): Float {
|
|
var s, a = 0.1, p = 0.4;
|
|
if (k == 0) {
|
|
return 0;
|
|
}
|
|
if (k == 1) {
|
|
return 1;
|
|
}
|
|
if (a != 0 || a < 1) {
|
|
a = 1;
|
|
s = p / 4;
|
|
}
|
|
else {
|
|
s = p * Math.asin(1 / a) / (2 * Math.PI);
|
|
}
|
|
if ((k *= 2) < 1) return - 0.5 * (a * Math.pow(2, 10 * (k -= 1)) * Math.sin((k - s) * (2 * Math.PI) / p));
|
|
return a * Math.pow(2, -10 * (k -= 1)) * Math.sin((k - s) * (2 * Math.PI) / p) * 0.5 + 1;
|
|
}
|
|
}
|
|
|
|
typedef TAnim = {
|
|
var target: Dynamic;
|
|
var props: Dynamic;
|
|
var duration: Float;
|
|
@:optional var isPlaying: Null<Bool>;
|
|
@:optional var done: Void->Void;
|
|
@:optional var tick: Void->Void;
|
|
@:optional var delay: Null<Float>;
|
|
@:optional var ease: Null<Ease>;
|
|
// Internal
|
|
@:optional var _time: Null<Float>;
|
|
@:optional var _comps: Array<Int>;
|
|
@:optional var _x: Array<Float>;
|
|
@:optional var _y: Array<Float>;
|
|
@:optional var _z: Array<Float>;
|
|
@:optional var _w: Array<Float>;
|
|
@:optional var _normalize: Array<Bool>;
|
|
}
|
|
|
|
@:enum abstract Ease(Int) from Int to Int {
|
|
var Linear = 0;
|
|
var SineIn = 1;
|
|
var SineOut = 2;
|
|
var SineInOut = 3;
|
|
var QuadIn = 4;
|
|
var QuadOut = 5;
|
|
var QuadInOut = 6;
|
|
var CubicIn = 7;
|
|
var CubicOut = 8;
|
|
var CubicInOut = 9;
|
|
var QuartIn = 10;
|
|
var QuartOut = 11;
|
|
var QuartInOut = 12;
|
|
var QuintIn = 13;
|
|
var QuintOut = 14;
|
|
var QuintInOut = 15;
|
|
var ExpoIn = 16;
|
|
var ExpoOut = 17;
|
|
var ExpoInOut = 18;
|
|
var CircIn = 19;
|
|
var CircOut = 20;
|
|
var CircInOut = 21;
|
|
var BackIn = 22;
|
|
var BackOut = 23;
|
|
var BackInOut = 24;
|
|
var BounceIn = 25;
|
|
var BounceOut = 26;
|
|
var BounceInOut = 27;
|
|
var ElasticIn = 28;
|
|
var ElasticOut = 29;
|
|
var ElasticInOut = 30;
|
|
}
|