Timing and part of easing algorithms

feature/coffeescript
Sven Slootweg 10 years ago
parent 783bcc7d3b
commit 0b51cde152

@ -21,6 +21,9 @@
this.createScene = __bind(this.createScene, this);
this.setPreloadScene = __bind(this.setPreloadScene, this);
this.setInitialScene = __bind(this.setInitialScene, this);
this.skipTimers = __bind(this.skipTimers, this);
this.updateTimers = __bind(this.updateTimers, this);
this.updateEasings = __bind(this.updateEasings, this);
this.iteration = __bind(this.iteration, this);
this.loop = __bind(this.loop, this);
this.start = __bind(this.start, this);
@ -33,11 +36,15 @@
this.last_frameskip_collection = Math.floor(Date.now());
this.frameskip = 0;
this.current_frameskip = 0;
this.current_frame = 0;
this.scenes = {};
this.objects = {};
this.sounds = {};
this.sprites = {};
this.tilesets = {};
this.easings = [];
this.named_timers = {};
this.unnamed_timers = [];
}
Engine.prototype.addCanvas = function(canvas, label) {
@ -79,15 +86,18 @@
};
Engine.prototype.iteration = function() {
var belated_timeout, current_frame, frame_interval, name, next_frame, overtime, scene, _ref;
var belated_timeout, current_frame, frame_interval, name, next_frame, overtime, scene, skipped_frames, _ref;
frame_interval = 1000 / this.fps;
current_frame = Date.now();
next_frame = current_frame + frame_interval;
this.current_frame += 1;
if (Math.floor(current_frame) > this.last_frameskip_collection) {
this.frameskip = this.current_frameskip;
this.current_frameskip = 0;
this.last_frameskip_collection = Math.floor(current_frame);
}
this.updateEasings();
this.updateTimers();
_ref = this.scenes;
for (name in _ref) {
scene = _ref[name];
@ -99,12 +109,89 @@
return setTimeout(this.iteration, next_frame - Date.now());
} else {
overtime = Date.now() - next_frame;
this.current_frameskip += Math.floor(overtime / frame_interval);
skipped_frames = Math.floor(overtime / frame_interval);
this.current_frameskip += skipped_frames;
this.current_frame += skipped_frames;
this.skipTimers(skipped_frames);
belated_timeout = overtime % frame_interval;
return setTimeout(this.iteration, belated_timeout);
}
};
Engine.prototype.updateEasings = function() {
var easing, _i, _len, _ref;
_ref = this.easings;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
easing = _ref[_i];
if (this.current_frame >= (easing.start_frame + easing.duration)) {
if (easing.infinite) {
easing.start_frame = this.current_frame;
easing.updateValue(this.current_frame);
} else {
easing.finished = true;
easing.value = easing.end;
}
} else {
easing.updateValue(this.current_frame);
}
}
return this.easings = this.easings.filter(function(obj) {
return !obj.finished;
});
};
Engine.prototype.updateTimers = function() {
var key, timer, timer_name, val, _i, _len, _ref, _ref1, _results;
_ref = this.unnamed_timers.concat((function() {
var _ref, _results;
_ref = this.named_timers;
_results = [];
for (key in _ref) {
val = _ref[key];
_results.push(val);
}
return _results;
}).call(this));
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
timer = _ref[_i];
timer.step();
}
this.unnamed_timers = this.unnamed_timers.filter(function(obj) {
return !obj.finished;
});
_ref1 = this.named_timers;
_results = [];
for (timer_name in _ref1) {
timer = _ref1[timer_name];
if (timer.finished) {
_results.push(delete this.named_timers[timer_name]);
} else {
_results.push(void 0);
}
}
return _results;
};
Engine.prototype.skipTimers = function(frames) {
var key, timer, val, _i, _len, _ref, _results;
_ref = this.unnamed_timers.concat((function() {
var _ref, _results1;
_ref = this.named_timers;
_results1 = [];
for (key in _ref) {
val = _ref[key];
_results1.push(val);
}
return _results1;
}).call(this));
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
timer = _ref[_i];
_results.push(timer.skip(frames));
}
return _results;
};
Engine.prototype.setInitialScene = function(scene) {
return this.initial_scene = scene;
};
@ -196,19 +283,19 @@
})(this),
_finishPath: (function(_this) {
return function(surface, options) {
var _ref, _ref1, _ref10, _ref11, _ref12, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, _ref8, _ref9;
var _ref, _ref1, _ref10, _ref11, _ref12, _ref13, _ref14, _ref15, _ref16, _ref17, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, _ref8, _ref9;
if ((_ref = options.stroke) != null ? _ref : true) {
surface.lineWidth = (_ref1 = (_ref2 = options.lineWidth) != null ? _ref2 : (_ref3 = options.pen) != null ? _ref3.lineWidth : void 0) != null ? _ref1 : 1;
surface.strokeStyle = (_ref4 = (_ref5 = options.lineColor) != null ? _ref5 : (_ref6 = options.pen) != null ? _ref6.lineColor : void 0) != null ? _ref4 : "black";
if ((_ref7 = options._is_text) != null ? _ref7 : false) {
surface.lineWidth = (_ref1 = (_ref2 = (_ref3 = (_ref4 = (_ref5 = options.lineWidth) != null ? _ref5.value : void 0) != null ? _ref4 : options.lineWidth) != null ? _ref3 : (_ref6 = options.pen) != null ? (_ref7 = _ref6.lineWidth) != null ? _ref7.value : void 0 : void 0) != null ? _ref2 : (_ref8 = options.pen) != null ? _ref8.lineWidth : void 0) != null ? _ref1 : 1;
surface.strokeStyle = (_ref9 = (_ref10 = options.lineColor) != null ? _ref10 : (_ref11 = options.pen) != null ? _ref11.lineColor : void 0) != null ? _ref9 : "black";
if ((_ref12 = options._is_text) != null ? _ref12 : false) {
surface.strokeText(options.text, options.x, options.y);
} else {
surface.stroke();
}
}
if ((_ref8 = options.fill) != null ? _ref8 : false) {
surface.fillStyle = (_ref9 = (_ref10 = options.fillColor) != null ? _ref10 : (_ref11 = options.pen) != null ? _ref11.fillColor : void 0) != null ? _ref9 : "white";
if ((_ref12 = options._is_text) != null ? _ref12 : false) {
if ((_ref13 = options.fill) != null ? _ref13 : false) {
surface.fillStyle = (_ref14 = (_ref15 = options.fillColor) != null ? _ref15 : (_ref16 = options.pen) != null ? _ref16.fillColor : void 0) != null ? _ref14 : "white";
if ((_ref17 = options._is_text) != null ? _ref17 : false) {
return surface.fillText(options.text, options.x, options.y);
} else {
return surface.fill();
@ -227,26 +314,31 @@
})(this),
_applyTextContext: (function(_this) {
return function(surface, options) {
var font_family, font_size, font_style, font_weight, scale, _ref, _ref1, _ref2, _ref3, _ref4, _ref5;
var font_family, font_size, font_style, font_weight, scale, _ref, _ref1, _ref10, _ref11, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, _ref8, _ref9;
font_family = (_ref = options.font) != null ? _ref : "sans-serif";
font_size = (_ref1 = options.size) != null ? _ref1 : 16;
font_weight = (_ref2 = options.weight) != null ? _ref2 : "normal";
font_style = (_ref3 = options.style) != null ? _ref3 : "normal";
scale = (_ref4 = options.scale) != null ? _ref4 : 1;
font_size = (_ref1 = (_ref2 = (_ref3 = options.size) != null ? _ref3.value : void 0) != null ? _ref2 : options.size) != null ? _ref1 : 16;
font_weight = (_ref4 = options.weight) != null ? _ref4 : "normal";
font_style = (_ref5 = options.style) != null ? _ref5 : "normal";
scale = (_ref6 = (_ref7 = (_ref8 = options.scale) != null ? _ref8.value : void 0) != null ? _ref7 : options.scale) != null ? _ref6 : 1;
surface.save();
surface.font = "" + font_weight + " " + font_style + " " + font_size + "px '" + font_family + "'";
surface.globalAlpha = (_ref5 = options.alpha) != null ? _ref5 : 1;
surface.globalAlpha = (_ref9 = (_ref10 = (_ref11 = options.alpha) != null ? _ref11.value : void 0) != null ? _ref10 : options.alpha) != null ? _ref9 : 1;
return surface.scale(scale, scale);
};
})(this),
line: (function(_this) {
return function(x1, y1, x2, y2, options, surface) {
var _ref, _ref1, _ref2, _ref3;
if (options == null) {
options = {};
}
if (surface == null) {
surface = "";
}
x1 = (_ref = x1.value) != null ? _ref : x1;
y1 = (_ref1 = y1.value) != null ? _ref1 : y1;
x2 = (_ref2 = x2.value) != null ? _ref2 : x2;
y2 = (_ref3 = y2.value) != null ? _ref3 : y2;
surface = _this._startPath(surface, options);
surface.moveTo(x1, y1);
surface.lineTo(x2, y2);
@ -255,12 +347,17 @@
})(this),
rectangle: (function(_this) {
return function(x1, y1, x2, y2, options, surface) {
var _ref, _ref1, _ref2, _ref3;
if (options == null) {
options = {};
}
if (surface == null) {
surface = "";
}
x1 = (_ref = x1.value) != null ? _ref : x1;
y1 = (_ref1 = y1.value) != null ? _ref1 : y1;
x2 = (_ref2 = x2.value) != null ? _ref2 : x2;
y2 = (_ref3 = y2.value) != null ? _ref3 : y2;
surface = _this._startPath(surface, options);
surface.rect(x1, y1, x2 - x1, y2 - y1);
return _this._finishPath(surface, options);
@ -268,13 +365,17 @@
})(this),
boxEllipse: (function(_this) {
return function(x1, y1, x2, y2, options, surface) {
var rx, ry, x, y;
var rx, ry, x, y, _ref, _ref1, _ref2, _ref3;
if (options == null) {
options = {};
}
if (surface == null) {
surface = "";
}
x1 = (_ref = x1.value) != null ? _ref : x1;
y1 = (_ref1 = y1.value) != null ? _ref1 : y1;
x2 = (_ref2 = x2.value) != null ? _ref2 : x2;
y2 = (_ref3 = y2.value) != null ? _ref3 : y2;
x = (x1 + x2) / 2;
y = (y1 + y2) / 2;
rx = (x2 - x1) / 2;
@ -284,20 +385,24 @@
})(this),
radiusEllipse: (function(_this) {
return function(x, y, rx, ry, options, surface) {
var i, step, _i, _ref, _ref1;
var i, step, _i, _ref, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7;
if (options == null) {
options = {};
}
if (surface == null) {
surface = "";
}
x = (_ref = x.value) != null ? _ref : x;
y = (_ref1 = y.value) != null ? _ref1 : y;
rx = (_ref2 = rx.value) != null ? _ref2 : rx;
ry = (_ref3 = ry.value) != null ? _ref3 : ry;
surface = _this._startPath(surface, options);
step = (_ref = options.step) != null ? _ref : 0.1;
step = (_ref4 = (_ref5 = (_ref6 = options.step) != null ? _ref6.value : void 0) != null ? _ref5 : options.step) != null ? _ref4 : 0.1;
if (rx === ry) {
surface.arc(x, y, rx, 0, 2 * Math.PI, false);
} else {
surface.moveTo(x + rx, y);
for (i = _i = 0, _ref1 = Math.PI * 2 + step; 0 <= _ref1 ? _i <= _ref1 : _i >= _ref1; i = 0 <= _ref1 ? ++_i : --_i) {
for (i = _i = 0, _ref7 = Math.PI * 2 + step; 0 <= _ref7 ? _i <= _ref7 : _i >= _ref7; i = 0 <= _ref7 ? ++_i : --_i) {
surface.lineTo(x + (Math.cos(i) * rx), y + (Math.sin(i) * ry));
}
}
@ -328,19 +433,19 @@
})(this),
text: (function(_this) {
return function(x, y, text, options, surface) {
var text_width;
var text_width, _ref, _ref1, _ref2, _ref3, _ref4;
if (options == null) {
options = {};
}
if (surface == null) {
surface = "";
}
x = (_ref = x.value) != null ? _ref : x;
y = (_ref1 = y.value) != null ? _ref1 : y;
if (options.alignment == null) {
options.alignment = "left";
}
if (options.scale == null) {
options.scale = 1;
}
options.scale = (_ref2 = (_ref3 = (_ref4 = options.scale) != null ? _ref4.value : void 0) != null ? _ref3 : options.scale) != null ? _ref2 : 1;
options._is_text = true;
options.text = text;
options.y = y;

@ -0,0 +1,14 @@
<!doctype html>
<html>
<head>
<title>Easing Demo</title>
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<script src="compiled/radium.js"></script>
<script src="easing/easing.js"></script>
<link rel="stylesheet" href="easing/easing.css">
</head>
<body>
<canvas id="gamecanvas"></canvas>
<div id="debug"></div>
</body>
</html>

@ -7,12 +7,16 @@ class Engine
@last_frameskip_collection = Math.floor(Date.now())
@frameskip = 0
@current_frameskip = 0
@current_frame = 0
@scenes = {}
@objects = {}
@sounds = {}
@sprites = {}
@tilesets = {}
@easings = []
@named_timers = {}
@unnamed_timers = []
addCanvas: (canvas, label = "") =>
@canvases[label] = util.unpackElement(canvas)
@ -48,12 +52,19 @@ class Engine
current_frame = Date.now()
next_frame = current_frame + frame_interval
@current_frame += 1
if Math.floor(current_frame) > @last_frameskip_collection
@frameskip = @current_frameskip
@current_frameskip = 0
@last_frameskip_collection = Math.floor(current_frame)
# Actual iteration code
# Actual iteration code...
# First update the registered easings.
@updateEasings()
# Then process registered timers.
@updateTimers()
# Now we run the scene-specific code.
scene.iteration() for name, scene of @scenes when scene.active
# Frameskip check and triggering next iteration
@ -62,10 +73,43 @@ class Engine
else
# Frameskip!
overtime = Date.now() - next_frame
@current_frameskip += Math.floor(overtime / frame_interval)
skipped_frames = Math.floor(overtime / frame_interval)
@current_frameskip += skipped_frames
@current_frame += skipped_frames
@skipTimers(skipped_frames)
belated_timeout = overtime % frame_interval
setTimeout(@iteration, belated_timeout)
updateEasings: =>
for easing in @easings
if @current_frame >= (easing.start_frame + easing.duration)
if easing.infinite
easing.start_frame = @current_frame
easing.updateValue(@current_frame)
else
easing.finished = true
easing.value = easing.end
else
easing.updateValue(@current_frame)
# Clean up finished easings
@easings = @easings.filter (obj) -> not obj.finished
updateTimers: =>
for timer in @unnamed_timers.concat (val for key, val of @named_timers)
timer.step()
# Clean up finished timers
@unnamed_timers = @unnamed_timers.filter (obj) -> not obj.finished
for timer_name, timer of @named_timers
if timer.finished
delete @named_timers[timer_name]
skipTimers: (frames) =>
for timer in @unnamed_timers.concat (val for key, val of @named_timers)
timer.skip(frames)
setInitialScene: (scene) =>
@initial_scene = scene

@ -9,7 +9,7 @@ Engine::draw =
_finishPath: (surface, options) =>
if options.stroke ? true
surface.lineWidth = options.lineWidth ? options.pen?.lineWidth ? 1
surface.lineWidth = options.lineWidth?.value ? options.lineWidth ? options.pen?.lineWidth?.value ? options.pen?.lineWidth ? 1
surface.strokeStyle = options.lineColor ? options.pen?.lineColor ? "black"
if options._is_text ? false
@ -33,28 +33,46 @@ Engine::draw =
_applyTextContext: (surface, options) =>
font_family = options.font ? "sans-serif"
font_size = options.size ? 16
font_size = options.size?.value ? options.size ? 16
font_weight = options.weight ? "normal"
font_style = options.style ? "normal"
scale = options.scale ? 1
scale = options.scale?.value ? options.scale ? 1
surface.save()
surface.font = "#{font_weight} #{font_style} #{font_size}px '#{font_family}'"
surface.globalAlpha = options.alpha ? 1
surface.globalAlpha = options.alpha?.value ? options.alpha ? 1
surface.scale(scale, scale)
line: (x1, y1, x2, y2, options = {}, surface = "") =>
# Ease-able properties
x1 = x1.value ? x1
y1 = y1.value ? y1
x2 = x2.value ? x2
y2 = y2.value ? y2
surface = @_startPath(surface, options)
surface.moveTo(x1, y1)
surface.lineTo(x2, y2)
@_finishPath(surface, options)
rectangle: (x1, y1, x2, y2, options = {}, surface = "") =>
# Ease-able properties
x1 = x1.value ? x1
y1 = y1.value ? y1
x2 = x2.value ? x2
y2 = y2.value ? y2
surface = @_startPath(surface, options)
surface.rect(x1, y1, x2 - x1, y2 - y1)
@_finishPath(surface, options)
boxEllipse: (x1, y1, x2, y2, options = {}, surface = "") =>
# Ease-able properties
x1 = x1.value ? x1
y1 = y1.value ? y1
x2 = x2.value ? x2
y2 = y2.value ? y2
x = (x1 + x2) / 2;
y = (y1 + y2) / 2;
rx = (x2 - x1) / 2;
@ -62,9 +80,15 @@ Engine::draw =
@radiusEllipse(x, y, rx, ry, options, surface)
radiusEllipse: (x, y, rx, ry, options = {}, surface = "") =>
# Ease-able properties
x = x.value ? x
y = y.value ? y
rx = rx.value ? rx
ry = ry.value ? ry
surface = @_startPath(surface, options)
step = options.step ? 0.1
step = options.step?.value ? options.step ? 0.1
if rx == ry
surface.arc(x, y, rx, 0, 2 * Math.PI, false)
@ -83,9 +107,13 @@ Engine::draw =
pass # TODO
text: (x, y, text, options = {}, surface = "") =>
# Ease-able properties
x = x.value ? x
y = y.value ? y
# Defaults
options.alignment ?= "left"
options.scale ?= 1
options.scale = options.scale?.value ? options.scale ? 1
options._is_text = true
options.text = text
options.y = y

@ -0,0 +1,165 @@
Engine::ease =
_calculateElasticValues: (amplitude, period, change, inout = false) =>
if !period?
if inout
period = duration * (0.3 * 1.5)
else
period = duration * 0.3
if !amplitude? or amplitude < Math.abs(change)
amplitude = change
overshoot = period / 4
else
overshoot = period / (2 * Math.PI) * Math.asin(change / amplitude)
return [amplitude, period, change]
backIn: (start, end, duration, infinite = false, overshoot = 1.70158) =>
return new Ease("backIn", infinite, start, end, @current_frame, duration, overshoot)
backOut: (start, end, duration, infinite = false, overshoot = 1.70158) =>
return new Ease("backOut", infinite, start, end, @current_frame, duration, overshoot)
backInOut: (start, end, duration, infinite = false, overshoot = 1.70158) =>
return new Ease("backInOut", infinite, start, end, @current_frame, duration, overshoot)
bounceOut: (start, end, duration, infinite = false) =>
return new Ease("bounceOut", infinite, start, end, @current_frame, duration)
bounceIn: (start, end, duration, infinite = false) =>
return new Ease("bounceIn", infinite, start, end, @current_frame, duration)
bounceInOut: (start, end, duration, infinite = false) =>
return new Ease("bounceInOut", infinite, start, end, @current_frame, duration)
circOut: (start, end, duration, infinite = false) =>
return new Ease("circOut", infinite, start, end, @current_frame, duration)
circIn: (start, end, duration, infinite = false) =>
return new Ease("circIn", infinite, start, end, @current_frame, duration)
circInOut: (start, end, duration, infinite = false) =>
return new Ease("circInOut", infinite, start, end, @current_frame, duration)
cubicOut: (start, end, duration, infinite = false) =>
return new Ease("cubicOut", infinite, start, end, @current_frame, duration)
cubicIn: (start, end, duration, infinite = false) =>
return new Ease("cubicIn", infinite, start, end, @current_frame, duration)
cubicInOut: (start, end, duration, infinite = false) =>
return new Ease("cubicInOut", infinite, start, end, @current_frame, duration)
elasticOut: (start, end, duration, infinite = false, amplitude = null, period = null) =>
[amplitude, period, change] = @_calculateElasticValues(amplitude, period, end - start)
end = start + change
return new Ease("elasticOut", infinite, start, end, @current_frame, duration)
elasticIn: (start, end, duration, infinite = false, amplitude = null, period = null) =>
[amplitude, period, change] = @_calculateElasticValues(amplitude, period, end - start)
end = start + change
return new Ease("elasticIn", infinite, start, end, @current_frame, duration)
elasticInOut: (start, end, duration, infinite = false, amplitude = null, period = null) =>
[amplitude, period, change] = @_calculateElasticValues(amplitude, period, end - start, true)
end = start + change
return new Ease("elasticInOut", infinite, start, end, @current_frame, duration)
expoOut: (start, end, duration, infinite = false) =>
return new Ease("expoOut", infinite, start, end, @current_frame, duration)
expoIn: (start, end, duration, infinite = false) =>
return new Ease("expoIn", infinite, start, end, @current_frame, duration)
expoInOut: (start, end, duration, infinite = false) =>
return new Ease("expoInOut", infinite, start, end, @current_frame, duration)
linearNone: (start, end, duration, infinite = false) =>
return new Ease("linearNone", infinite, start, end, @current_frame, duration)
linearOut: (start, end, duration, infinite = false) =>
return new Ease("linearNone", infinite, start, end, @current_frame, duration)
linearIn: (start, end, duration, infinite = false) =>
return new Ease("linearNone", infinite, start, end, @current_frame, duration)
linearInOut: (start, end, duration, infinite = false) =>
return new Ease("linearNone", infinite, start, end, @current_frame, duration)
quadOut: (start, end, duration, infinite = false) =>
return new Ease("quadOut", infinite, start, end, @current_frame, duration)
quadIn: (start, end, duration, infinite = false) =>
return new Ease("quadIn", infinite, start, end, @current_frame, duration)
quadInOut: (start, end, duration, infinite = false) =>
return new Ease("quadInOut", infinite, start, end, @current_frame, duration)
quartOut: (start, end, duration, infinite = false) =>
return new Ease("quartOut", infinite, start, end, @current_frame, duration)
quartIn: (start, end, duration, infinite = false) =>
return new Ease("quartIn", infinite, start, end, @current_frame, duration)
quartInOut: (start, end, duration, infinite = false) =>
return new Ease("quartInOut", infinite, start, end, @current_frame, duration)
sineOut: (start, end, duration, infinite = false) =>
return new Ease("sineOut", infinite, start, end, @current_frame, duration)
sineIn: (start, end, duration, infinite = false) =>
return new Ease("sineIn", infinite, start, end, @current_frame, duration)
sineInOut: (start, end, duration, infinite = false) =>
return new Ease("sineInOut", infinite, start, end, @current_frame, duration)
class Ease
# Port based on https://github.com/jimjeffers/Easie. I don't think this qualifies as a "bad thing" :)
constructor: (type, @infinite, @start, end, @start_frame, @duration, @params...) ->
@func = this[type]
@change = end - @start
@value = @start
@finished = false
# TODO: Investigate whether JS engines cache deterministic outcomes by themselves. If not,
# the below could provide some performance gain.
#@bounce_constant_1 = 1 / 2.75
#@bounce_constant_2 = 2 / 2.75
#@bounce_constant_3 = 2.5 / 2.75
updateValue: (current_frame) =>
@value = @func(current_frame - @start_frame)
backIn: (time) =>
time = time / @duration
overshoot = @params[0]
return @change * time * time * ((overshoot + 1) * time - overshoot) + @start
backOut: (time) =>
time = time / @duration - 1
overshoot = @params[0]
return @change * (time * time * ((overshoot + 1) * time + overshoot) + 1) + @start
backInOut: (time) =>
time = time / (@duration / 2)
overshoot = @params[0] * 1.525
if time < 1
return @change / 2 * (time * time * ((overshoot + 1) * time - overshoot)) + @start
else
time -= 2
return @change / 2 * (time * time * ((overshoot + 1) * time + overshoot) + 2) + @start
bounceOut: (time, start = null) =>
time = time / @duration
start = start ? @start
if time < 1 / 2.75
return @change * (7.5625 * time * time) + start
else if time < 2 / 2.75
time = time - (1.5 / 2.75)
return @change * (7.5625 * time * time + 0.75) + start
else if time < 2.5 / 2.75
time = time - (2.25 / 2.75)
return @change * (7.5625 * time * time + 0.9375) + start
else
time = time - (2.625 / 2.75)
return @change * (7.5625 * time * time + 0.984375) + start
bounceIn: (time, start = null) =>
start = start ? @start
return @change - @bounceOut(@duration - time, 0) + start
bounceInOut: (time) =>
if time < @duration / 2
return @bounceIn(time * 2, 0) + @start
else
return @bounceOut(time * 2 - @duration, 0) + @start
circIn: (time) =>
time = time / @duration
return -@change * (Math.sqrt(1 - time * time) - 1) + @start
circOut: (time) =>
time = time / @duration - 1
return @change * Math.sqrt(1 - time * time) + @start
circInOut: (time) =>
time = time / (@duration / 2)
if time < 1
return -@change / 2 * (Math.sqrt(1 - time * time) - 1) + @start
else
time = time - 2
return @change / 2 * (Math.sqrt(1 - time * time) + 1) + @begin

@ -0,0 +1,30 @@
Engine::timing =
startTimer: (frames, callback, name = null, repeat = false) =>
timer = new Timer(frames, callback, repeat)
if name?
@named_timers[name] = timer
else
@unnamed_timers.push(timer)
stopTimer: (name)
@timers[name].stop()
class Timer
constructor: (@frames, @callback, @repeat) =>
@current_frame = 0
@finished = false
step: =>
if @current_frame >= @frames
@callback()
if repeat
@current_frame = 0
else
@finished = true
skip: (frames) =>
@current_frame += frames
stop: =>
@finished = true
Loading…
Cancel
Save