@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
153 lines (128 loc) • 3.52 kB
JavaScript
import { assert } from "../../../core/assert.js";
import { computeHashFloat } from "../../../core/primitives/numbers/computeHashFloat.js";
/**
* Single keyframe of {@link AnimationCurve}.
* Note that {@link AnimationCurve} relies on {@link Keyframe}s to be static, so treat them as immutable.
* Do not change keyframe values unless you understand the implications of doing so.
*
* @author Alex Goldring
* @copyright Company Named Limited (c) 2025
*/
export class Keyframe {
/**
*
* @type {number}
*/
value = 0;
/**
* Timestamp/position for the value
* @type {number}
*/
time = 0;
/**
* Incoming tangent, affects the slope of the curve from previous key
* @type {number}
*/
inTangent = 0;
/**
* Outgoing tangent, affect the slope of the curve from this key to the next key
* @type {number}
*/
outTangent = 0;
/**
*
* @param {number} time
* @param {number} value
* @param {number} inTangent
* @param {number} outTangent
* @return {Keyframe}
*/
static from(time, value, inTangent = 0, outTangent = 0) {
const r = new Keyframe();
r.set(time, value, inTangent, outTangent);
return r;
}
/**
*
* @param {number} time
* @param {number} value
* @param {number} inTangent
* @param {number} outTangent
*/
set(time, value, inTangent, outTangent) {
assert.isNumber(time, 'time');
assert.notNaN(time, 'time');
assert.isNumber(value, 'value');
assert.notNaN(value, 'value');
assert.isNumber(inTangent, 'inTangent');
assert.notNaN(inTangent, 'inTangent');
assert.isFinite(inTangent, 'inTangent');
assert.isNumber(outTangent, 'outTangent');
assert.notNaN(outTangent, 'outTangent');
assert.isFinite(outTangent, 'outTangent');
this.time = time;
this.value = value;
this.inTangent = inTangent;
this.outTangent = outTangent;
}
/**
*
* @param {Keyframe} other
*/
copy(other) {
this.time = other.time;
this.value = other.value;
this.inTangent = other.inTangent;
this.outTangent = other.outTangent;
}
/**
*
* @return {Keyframe}
*/
clone() {
const r = new Keyframe();
r.copy(this);
return r;
}
/**
*
* @param {Keyframe} other
* @returns {boolean}
*/
equals(other) {
return this.time === other.time
&& this.value === other.value
&& this.inTangent === other.inTangent
&& this.outTangent === other.outTangent;
}
/**
*
* @return {number}
*/
hash() {
return computeHashFloat(this.time)
^ (computeHashFloat(this.value) * 31);
}
toJSON() {
return {
value: this.value,
time: this.time,
inTangent: this.inTangent,
outTangent: this.outTangent
}
};
fromJSON({
value,
time,
inTangent,
outTangent
}) {
this.set(time, value, inTangent, outTangent);
}
}
/**
* Useful for type checks
* @readonly
* @type {boolean}
*/
Keyframe.prototype.isKeyframe = true;