diff --git a/source/engine/script.c b/source/engine/script.c index c98527c..a6f78c3 100644 --- a/source/engine/script.c +++ b/source/engine/script.c @@ -195,6 +195,7 @@ static struct callee update_callee; void register_update(struct callee c) { update_callee = c; } + void call_updates(double dt) { callee_dbl(update_callee, dt); } diff --git a/source/scripts/base.js b/source/scripts/base.js index 832aef4..46491f1 100644 --- a/source/scripts/base.js +++ b/source/scripts/base.js @@ -467,15 +467,39 @@ Object.defineProperty(Array.prototype, 'mirrored', { } }); +Object.defineProperty(Array.prototype, 'lerp', { + value: function(to, t) { + var c = []; + this.forEach(function(x,i) { + c[i] = (to[i] - x) * t + x; + }); + return c; + } +}); + +Object.defineProperty(Object.prototype, 'lerp', { + value: function(to, t) { + var self = this; + var obj = {}; + + Object.keys(self).forEach(function(key) { + obj[key] = self[key].lerp(to[key],t); + }); + + return obj; + } +}); /* MATH EXTENSIONS */ +Object.defineProperty(Number.prototype, 'lerp', { + value: function(to, t) { + var s = this; + return (to - this) * t + this; + } +}); Math.clamp = function (x, l, h) { return x > h ? h : x < l ? l : x; } -Math.lerp = function (s, f, dt) { - return s + (Math.clamp(dt, 0, 1) * (f - s)); -}; - Math.random_range = function(min,max) { return Math.random() * (max-min) + min; }; Math.snap = function(val, grid) { diff --git a/source/scripts/engine.js b/source/scripts/engine.js index 4f1d42d..2f00745 100644 --- a/source/scripts/engine.js +++ b/source/scripts/engine.js @@ -347,27 +347,88 @@ var timer = { get pct() { return this.remain / this.time; }, }; +/* Take numbers from 0 to 1 and remap them to easing functions */ +var Ease = { + linear(t) { return t; }, + + in(t) { return t*t; }, + + out(t) { + var d = 1-t; + return 1 - d*d + }, + + inout(t) { + var d = -2*t + 2; + return t < 0.5 ? 2 * t * t : 1 - (d * d) / 2; + }, +}; + +Ease.sine = { + in(t) { return 1 - Math.cos((t * Math.PI)/2); }, + + out(t) { return Math.sin((t*Math.PI)/2); }, + + inout(t) { return -(Math.cos(Math.PI*t) - 1) / 2; } +}; + +Ease.elastic = { + in(t) { + return t === 0 ? 0 : t === 1 ? 1 : -Math.pow(2, 10*t-10) * Math.sin((t * 10 - 10.75) * this.c4); + }, + + out(t) { + return t === 0 ? 0 : t === 1 ? 1 : Math.pow(2, -10*t) * Math.sin((t * 10 - 0.75) * this.c4) + 1; + }, + + inout(t) { + t === 0 ? 0 : t === 1 ? 1 : t < 0.5 ? + -(Math.pow(2, 20 * t - 10) * Math.sin((20 * t - 11.125) * this.c5)) / 2 + : (Math.pow(2, -20 * t + 10) * Math.sin((20 * t - 11.125) * this.c5)) / 2 + 1; + }, +}; +Ease.elastic.c4 = 2*Math.PI/3; +Ease.elastic.c5 = 2*Math.PI / 4.5; + var Tween = { default: { ease: "inout", /* easing at end and beginning of tween */ loop: "restart", /* none, restart, yoyo, increment */ time: 1, /* seconds to do */ + ease: Ease.linear }, - start(target, start, end, options) + start(obj, target, start, end, options) { var defn = Object.create(this.default); - Object.apply(defn, options); - - var newtimer = timer.make(null, defn.time, null, true); - newtimer.pause(); - - var tween_fn = function() { - Log.warn(newtimer.pct); - }; - timer.callback = tween_fn; - timer.callback(); - timer.start(); + Object.assign(defn, options); + + defn.accum = 0; + + if (defn.loop === 'yoyo') + defn.fn = function(dt) { + defn.accum += dt; + defn.pct = (defn.accum % (defn.time*2)) / (defn.time*2); + + if (defn.pct < 0.5) + obj[target] = start.lerp(end, defn.ease(defn.pct/0.5)); + else + obj[target] = end.lerp(start, defn.ease((defn.pct-0.5)/0.5)); + }; + else + defn.fn = function(dt) { + defn.accum += dt; + defn.pct = (defn.accum % defn.time) / defn.time; + obj[target] = start.lerp(end, defn.ease(defn.pct)); + }; + + defn.restart = function() { defn.accum = 0; }; + defn.stop = function() { defn.pause(); defn.restart(); }; + defn.pause = function() { unregister_update(defn.fn); }; + + register_update(defn.fn, defn); + + return defn; }, lerp(s, e, t) @@ -739,6 +800,12 @@ function register_update(fn, obj) { Register.updates.push([fn, obj ? obj : null]); }; +function unregister_update(fn) { + Register.updates = Register.updates.filter(function(updatefn) { + return fn === updatefn; + }); +}; + function register_physupdate(fn, obj) { Register.physupdates.push([fn, obj ? obj : null]); };