diff --git a/packages/melonjs/src/camera/camera2d.js b/packages/melonjs/src/camera/camera2d.js
index e4383dc9b9..8284e2e550 100644
--- a/packages/melonjs/src/camera/camera2d.js
+++ b/packages/melonjs/src/camera/camera2d.js
@@ -1,7 +1,5 @@
import Vector2d from "./../math/vector2.js";
import Vector3d from "./../math/vector3.js";
-import ObservableVector2d from "./../math/observable_vector2.js";
-import ObservableVector3d from "./../math/observable_vector3.js";
import Matrix2d from "./../math/matrix2.js";
import Matrix3d from "./../math/matrix3.js";
import Rect from "./../geometries/rectangle.js";
@@ -322,12 +320,7 @@ export default class Camera2d extends Renderable {
follow(target, axis, damping) {
if (target instanceof Renderable) {
this.target = target.pos;
- } else if (
- target instanceof Vector2d ||
- target instanceof Vector3d ||
- target instanceof ObservableVector2d ||
- target instanceof ObservableVector3d
- ) {
+ } else if (target instanceof Vector2d || target instanceof Vector3d) {
this.target = target;
} else {
throw new Error("invalid target for me.Camera2d.follow");
diff --git a/packages/melonjs/src/geometries/ellipse.js b/packages/melonjs/src/geometries/ellipse.js
index 65efa2687b..7a31359533 100644
--- a/packages/melonjs/src/geometries/ellipse.js
+++ b/packages/melonjs/src/geometries/ellipse.js
@@ -2,7 +2,7 @@ import pool from "./../system/pooling.js";
/**
* additional import for TypeScript
- * @import Vector2d from "./../math/vector2.js";
+ * @import Vector3d from "./../math/vector3.js";
* @import Matrix2d from "./../math/matrix2.js";
* @import Bounds from "./../physics/bounds.js";
*/
@@ -21,9 +21,9 @@ export default class Ellipse {
/**
* the center coordinates of the ellipse
* @public
- * @type {Vector2d}
+ * @type {Vector3d}
*/
- this.pos = pool.pull("Vector2d");
+ this.pos = pool.pull("Vector3d");
/**
* The bounding rectangle for this shape
diff --git a/packages/melonjs/src/geometries/poly.js b/packages/melonjs/src/geometries/poly.js
index 6af8fead0e..cdbe7c3749 100644
--- a/packages/melonjs/src/geometries/poly.js
+++ b/packages/melonjs/src/geometries/poly.js
@@ -3,7 +3,7 @@ import { earcut } from "./earcut.js";
/**
* additional import for TypeScript
- * @import Vector2d from "./../math/vector2.js";
+ * @import Vector3d from "./../math/vector3.js";
* @import Matrix2d from "./../math/matrix2.js";
* @import Bounds from "./../physics/bounds.js";
*/
@@ -25,9 +25,27 @@ export default class Polygon {
constructor(x = 0, y = 0, points) {
/**
* origin point of the Polygon
- * @type {Vector2d}
+ * @type {Vector3}
*/
- this.pos = pool.pull("Vector2d");
+ this.pos = pool.pull("Vector3d");
+ /**
+ * Proxy to the pos Vector3d object
+ * @ignore
+ */
+ this.posProxy = new Proxy(this.pos, {
+ set: (obj, prop, value) => {
+ // only update bounds if x or y has changed (ignore z)
+ if (prop !== "z") {
+ const newX = prop === "x" ? value : obj.x;
+ const newY = prop === "y" ? value : obj.y;
+ this.getBounds().translate(newX - obj.x, newY - obj.y);
+ }
+
+ obj[prop] = value;
+
+ return true;
+ },
+ });
/**
* Array of points defining the Polygon
@@ -86,8 +104,8 @@ export default class Polygon {
* @returns {Polygon} this instance for objecf chaining
*/
setShape(x, y, points) {
- this.pos.set(x, y);
this.setVertices(points);
+ this.pos.set(x, y);
return this;
}
@@ -334,7 +352,6 @@ export default class Polygon {
this.pos.x += _x;
this.pos.y += _y;
- this.getBounds().translate(_x, _y);
return this;
}
@@ -362,7 +379,6 @@ export default class Polygon {
}
this.pos.x = _x;
this.pos.y = _y;
- this.updateBounds();
}
/**
diff --git a/packages/melonjs/src/index.js b/packages/melonjs/src/index.js
index ee35bfeac5..ef8e9fb738 100644
--- a/packages/melonjs/src/index.js
+++ b/packages/melonjs/src/index.js
@@ -5,8 +5,6 @@ import "./polyfill/index.ts";
import Color from "./math/color.js";
import Vector2d from "./math/vector2.js";
import Vector3d from "./math/vector3.js";
-import ObservableVector2d from "./math/observable_vector2.js";
-import ObservableVector3d from "./math/observable_vector3.js";
import Matrix2d from "./math/matrix2.js";
import Matrix3d from "./math/matrix3.js";
import Polygon from "./geometries/poly.js";
@@ -101,8 +99,6 @@ export {
Color,
Vector2d,
Vector3d,
- ObservableVector2d,
- ObservableVector3d,
Matrix2d,
Matrix3d,
Polygon,
@@ -228,8 +224,6 @@ export function boot() {
pool.register("me.ColorLayer", ColorLayer, true);
pool.register("me.Vector2d", Vector2d, true);
pool.register("me.Vector3d", Vector3d, true);
- pool.register("me.ObservableVector2d", ObservableVector2d, true);
- pool.register("me.ObservableVector3d", ObservableVector3d, true);
pool.register("me.Matrix2d", Matrix2d, true);
pool.register("me.Matrix3d", Matrix3d, true);
pool.register("me.Rect", Rect, true);
@@ -258,8 +252,6 @@ export function boot() {
pool.register("ColorLayer", ColorLayer, true);
pool.register("Vector2d", Vector2d, true);
pool.register("Vector3d", Vector3d, true);
- pool.register("ObservableVector2d", ObservableVector2d, true);
- pool.register("ObservableVector3d", ObservableVector3d, true);
pool.register("Matrix2d", Matrix2d, true);
pool.register("Matrix3d", Matrix3d, true);
pool.register("Rect", Rect, true);
diff --git a/packages/melonjs/src/level/tiled/TMXTileMap.js b/packages/melonjs/src/level/tiled/TMXTileMap.js
index 682d6c0b29..809874450c 100644
--- a/packages/melonjs/src/level/tiled/TMXTileMap.js
+++ b/packages/melonjs/src/level/tiled/TMXTileMap.js
@@ -493,7 +493,7 @@ export default class TMXTileMap {
obj.body = new Body(obj, shape);
obj.body.setStatic(true);
// set the obj z order
- obj.pos.setMuted(settings.x, settings.y, settings.z);
+ obj.pos.set(settings.x, settings.y, settings.z);
} else {
// pull the corresponding object from the object pool
if (typeof settings.name !== "undefined" && settings.name !== "") {
diff --git a/packages/melonjs/src/math/observable_vector2.js b/packages/melonjs/src/math/observable_vector2.js
deleted file mode 100644
index 7e3e6f9926..0000000000
--- a/packages/melonjs/src/math/observable_vector2.js
+++ /dev/null
@@ -1,425 +0,0 @@
-import pool from "./../system/pooling.js";
-import Vector2d from "./vector2.js";
-import { clamp } from "./math.ts";
-
-/**
- * A Vector2d object that provide notification by executing the given callback when the vector is changed.
- */
-export default class ObservableVector2d extends Vector2d {
- /**
- * @param {number} x - x value of the vector
- * @param {number} y - y value of the vector
- * @param {object} settings - additional required parameters
- * @param {Function} settings.onUpdate - the callback to be executed when the vector is changed
- * @param {Function} [settings.scope] - the value to use as this when calling onUpdate
- */
- constructor(x = 0, y = 0, settings) {
- super(x, y);
- if (typeof settings === "undefined") {
- throw new Error("undefined `onUpdate` callback");
- }
- this.setCallback(settings.onUpdate, settings.scope);
- }
-
- /**
- * @ignore
- */
- onResetEvent(x = 0, y = 0, settings) {
- // init is call by the constructor and does not trigger the cb
- this.setMuted(x, y);
- if (typeof settings !== "undefined") {
- this.setCallback(settings.onUpdate, settings.scope);
- }
- }
-
- /**
- * x value of the vector
- * @type {number}
- */
-
- get x() {
- return this._x;
- }
-
- set x(value) {
- const ret = this.onUpdate.call(
- this.scope,
- value,
- this._y,
- this._x,
- this._y,
- );
- if (ret && "x" in ret) {
- this._x = ret.x;
- } else {
- this._x = value;
- }
- }
-
- /**
- * y value of the vector
- * @type {number}
- */
-
- get y() {
- return this._y;
- }
-
- set y(value) {
- const ret = this.onUpdate.call(
- this.scope,
- this._x,
- value,
- this._x,
- this._y,
- );
- if (ret && "y" in ret) {
- this._y = ret.y;
- } else {
- this._y = value;
- }
- }
-
- /** @ignore */
- _set(x, y) {
- const ret = this.onUpdate.call(this.scope, x, y, this._x, this._y);
- if (ret && "x" in ret && "y" in ret) {
- this._x = ret.x;
- this._y = ret.y;
- } else {
- this._x = x;
- this._y = y;
- }
- return this;
- }
-
- /**
- * set the vector value without triggering the callback
- * @param {number} x - x value of the vector
- * @param {number} y - y value of the vector
- * @returns {ObservableVector2d} Reference to this object for method chaining
- */
- setMuted(x, y) {
- this._x = x;
- this._y = y;
- return this;
- }
-
- /**
- * set the callback to be executed when the vector is changed
- * @param {Function} fn - callback
- * @param {Function} [scope=null] - scope
- * @returns {ObservableVector2d} Reference to this object for method chaining
- */
- setCallback(fn, scope = null) {
- if (typeof fn !== "function") {
- throw new Error("invalid `onUpdate` callback");
- }
- this.onUpdate = fn;
- this.scope = scope;
- return this;
- }
-
- /**
- * Add the passed vector to this vector
- * @param {ObservableVector2d} v
- * @returns {ObservableVector2d} Reference to this object for method chaining
- */
- add(v) {
- return this._set(this._x + v.x, this._y + v.y);
- }
-
- /**
- * Substract the passed vector to this vector
- * @param {ObservableVector2d} v
- * @returns {ObservableVector2d} Reference to this object for method chaining
- */
- sub(v) {
- return this._set(this._x - v.x, this._y - v.y);
- }
-
- /**
- * Multiply this vector values by the given scalar
- * @param {number} x
- * @param {number} [y=x]
- * @returns {ObservableVector2d} Reference to this object for method chaining
- */
- scale(x, y = x) {
- return this._set(this._x * x, this._y * y);
- }
-
- /**
- * Multiply this vector values by the passed vector
- * @param {ObservableVector2d} v
- * @returns {ObservableVector2d} Reference to this object for method chaining
- */
- scaleV(v) {
- return this._set(this._x * v.x, this._y * v.y);
- }
-
- /**
- * Divide this vector values by the passed value
- * @param {number} n - the value to divide the vector by
- * @returns {ObservableVector2d} Reference to this object for method chaining
- */
- div(n) {
- return this._set(this._x / n, this._y / n);
- }
-
- /**
- * Update this vector values to absolute values
- * @returns {ObservableVector2d} Reference to this object for method chaining
- */
- abs() {
- return this._set(
- this._x < 0 ? -this._x : this._x,
- this._y < 0 ? -this._y : this._y,
- );
- }
-
- /**
- * Clamp the vector value within the specified value range
- * @param {number} low
- * @param {number} high
- * @returns {ObservableVector2d} new me.ObservableVector2d
- */
- clamp(low, high) {
- return new ObservableVector2d(
- clamp(this.x, low, high),
- clamp(this.y, low, high),
- { onUpdate: this.onUpdate, scope: this.scope },
- );
- }
-
- /**
- * Clamp this vector value within the specified value range
- * @param {number} low
- * @param {number} high
- * @returns {ObservableVector2d} Reference to this object for method chaining
- */
- clampSelf(low, high) {
- return this._set(clamp(this._x, low, high), clamp(this._y, low, high));
- }
-
- /**
- * Update this vector with the minimum value between this and the passed vector
- * @param {ObservableVector2d} v
- * @returns {ObservableVector2d} Reference to this object for method chaining
- */
- minV(v) {
- return this._set(
- this._x < v.x ? this._x : v.x,
- this._y < v.y ? this._y : v.y,
- );
- }
-
- /**
- * Update this vector with the maximum value between this and the passed vector
- * @param {ObservableVector2d} v
- * @returns {ObservableVector2d} Reference to this object for method chaining
- */
- maxV(v) {
- return this._set(
- this._x > v.x ? this._x : v.x,
- this._y > v.y ? this._y : v.y,
- );
- }
-
- /**
- * Floor the vector values
- * @returns {ObservableVector2d} new me.ObservableVector2d
- */
- floor() {
- return new ObservableVector2d(Math.floor(this._x), Math.floor(this._y), {
- onUpdate: this.onUpdate,
- scope: this.scope,
- });
- }
-
- /**
- * Floor this vector values
- * @returns {ObservableVector2d} Reference to this object for method chaining
- */
- floorSelf() {
- return this._set(Math.floor(this._x), Math.floor(this._y));
- }
-
- /**
- * Ceil the vector values
- * @returns {ObservableVector2d} new me.ObservableVector2d
- */
- ceil() {
- return new ObservableVector2d(Math.ceil(this._x), Math.ceil(this._y), {
- onUpdate: this.onUpdate,
- scope: this.scope,
- });
- }
-
- /**
- * Ceil this vector values
- * @returns {ObservableVector2d} Reference to this object for method chaining
- */
- ceilSelf() {
- return this._set(Math.ceil(this._x), Math.ceil(this._y));
- }
-
- /**
- * Negate the vector values
- * @returns {ObservableVector2d} new me.ObservableVector2d
- */
- negate() {
- return new ObservableVector2d(-this._x, -this._y, {
- onUpdate: this.onUpdate,
- scope: this.scope,
- });
- }
-
- /**
- * Negate this vector values
- * @returns {ObservableVector2d} Reference to this object for method chaining
- */
- negateSelf() {
- return this._set(-this._x, -this._y);
- }
-
- /**
- * Copy the x,y values of the passed vector to this one
- * @param {ObservableVector2d} v
- * @returns {ObservableVector2d} Reference to this object for method chaining
- */
- copy(v) {
- return this._set(v.x, v.y);
- }
-
- /**
- * return true if the two vectors are the same
- * @param {ObservableVector2d} v
- * @returns {boolean}
- */
- equals(v) {
- return this._x === v.x && this._y === v.y;
- }
-
- /**
- * change this vector to be perpendicular to what it was before.
- * (Effectively rotates it 90 degrees in a clockwise direction)
- * @returns {ObservableVector2d} Reference to this object for method chaining
- */
- perp() {
- return this._set(this._y, -this._x);
- }
-
- /**
- * Rotate this vector (counter-clockwise) by the specified angle (in radians).
- * @param {number} angle - The angle to rotate (in radians)
- * @param {Vector2d|ObservableVector2d} [v] - an optional point to rotate around
- * @returns {ObservableVector2d} Reference to this object for method chaining
- */
- rotate(angle, v) {
- let cx = 0;
- let cy = 0;
-
- if (typeof v === "object") {
- cx = v.x;
- cy = v.y;
- }
-
- const x = this._x - cx;
- const y = this._y - cy;
-
- const c = Math.cos(angle);
- const s = Math.sin(angle);
-
- return this._set(x * c - y * s + cx, x * s + y * c + cy);
- }
-
- /**
- * return the dot product of this vector and the passed one
- * @param {Vector2d|ObservableVector2d} v
- * @returns {number} The dot product.
- */
- dot(v) {
- return this._x * v.x + this._y * v.y;
- }
-
- /**
- * return the cross product of this vector and the passed one
- * @param {Vector2d|ObservableVector2d} v
- * @returns {number} The cross product.
- */
- cross(v) {
- return this._x * v.y - this._y * v.x;
- }
-
- /**
- * Linearly interpolate between this vector and the given one.
- * @param {Vector2d|ObservableVector2d} v
- * @param {number} alpha - distance along the line (alpha = 0 will be this vector, and alpha = 1 will be the given one).
- * @returns {ObservableVector2d} Reference to this object for method chaining
- */
- lerp(v, alpha) {
- return this._set(
- this._x + (v.x - this._x) * alpha,
- this._y + (v.y - this._y) * alpha,
- );
- }
-
- /**
- * interpolate the position of this vector towards the given one while nsure that the distance never exceeds the given step.
- * @param {Vector2d|ObservableVector2d} target
- * @param {number} step - the maximum step per iteration (Negative values will push the vector away from the target)
- * @returns {ObservableVector2d} Reference to this object for method chaining
- */
- moveTowards(target, step) {
- const angle = Math.atan2(target.y - this._y, target.x - this._x);
-
- const distance = this.distance(target);
-
- if (distance === 0 || (step >= 0 && distance <= step * step)) {
- return target;
- }
-
- this._x += Math.cos(angle) * step;
- this._y += Math.sin(angle) * step;
-
- return this;
- }
-
- /**
- * return the distance between this vector and the passed one
- * @param {ObservableVector2d} v
- * @returns {number}
- */
- distance(v) {
- return Math.sqrt(
- (this._x - v.x) * (this._x - v.x) + (this._y - v.y) * (this._y - v.y),
- );
- }
-
- /**
- * return a clone copy of this vector
- * @returns {ObservableVector2d} new me.ObservableVector2d
- */
- clone() {
- return pool.pull("ObservableVector2d", this._x, this._y, {
- onUpdate: this.onUpdate,
- scope: this.scope,
- });
- }
-
- /**
- * return a `me.Vector2d` copy of this `me.ObservableVector2d` object
- * @returns {Vector2d} new me.Vector2d
- */
- toVector2d() {
- return pool.pull("Vector2d", this._x, this._y);
- }
-
- /**
- * convert the object to a string representation
- * @returns {string}
- */
- toString() {
- return "x:" + this._x + ",y:" + this._y;
- }
-}
diff --git a/packages/melonjs/src/math/observable_vector3.js b/packages/melonjs/src/math/observable_vector3.js
deleted file mode 100644
index 0cccfd7f65..0000000000
--- a/packages/melonjs/src/math/observable_vector3.js
+++ /dev/null
@@ -1,513 +0,0 @@
-import Vector3d from "./vector3.js";
-import { clamp } from "./math.ts";
-import pool from "./../system/pooling.js";
-
-/**
- * additional import for TypeScript
- * @import ObservableVector2d from "./observable_vector2.js";
- * @import Vector2d from "./vector2.js";
- */
-
-/**
- * A Vector3d object that provide notification by executing the given callback when the vector is changed.
- */
-export default class ObservableVector3d extends Vector3d {
- /**
- * @param {number} x - x value of the vector
- * @param {number} y - y value of the vector
- * @param {number} z - z value of the vector
- * @param {object} settings - additional required parameters
- * @param {Function} settings.onUpdate - the callback to be executed when the vector is changed
- * @param {object} [settings.scope] - the value to use as this when calling onUpdate
- */
- constructor(x = 0, y = 0, z = 0, settings) {
- super(x, y, z);
- if (typeof settings === "undefined") {
- throw new Error("undefined `onUpdate` callback");
- }
- this.setCallback(settings.onUpdate, settings.scope);
- }
-
- /**
- * @ignore
- */
- onResetEvent(x = 0, y = 0, z = 0, settings) {
- // init is call by the constructor and does not trigger the cb
- this.setMuted(x, y, z);
- if (typeof settings !== "undefined") {
- this.setCallback(settings.onUpdate, settings.scope);
- }
- return this;
- }
-
- /**
- * x value of the vector
- * @type {number}
- */
-
- get x() {
- return this._x;
- }
-
- set x(value) {
- const ret = this.onUpdate.call(
- this.scope,
- value,
- this._y,
- this._z,
- this._x,
- this._y,
- this._z,
- );
- if (ret && "x" in ret) {
- this._x = ret.x;
- } else {
- this._x = value;
- }
- }
-
- /**
- * y value of the vector
- * @type {number}
- */
-
- get y() {
- return this._y;
- }
-
- set y(value) {
- const ret = this.onUpdate.call(
- this.scope,
- this._x,
- value,
- this._z,
- this._x,
- this._y,
- this._z,
- );
- if (ret && "y" in ret) {
- this._y = ret.y;
- } else {
- this._y = value;
- }
- }
-
- /**
- * z value of the vector
- * @type {number}
- */
-
- get z() {
- return this._z;
- }
-
- set z(value) {
- const ret = this.onUpdate.call(
- this.scope,
- this._x,
- this._y,
- value,
- this._x,
- this._y,
- this._z,
- );
- if (ret && "z" in ret) {
- this._z = ret.z;
- } else {
- this._z = value;
- }
- }
-
- /**
- * @ignore
- */
- _set(x, y, z) {
- const ret = this.onUpdate.call(
- this.scope,
- x,
- y,
- z,
- this._x,
- this._y,
- this._z,
- );
- if (ret && "x" in ret && "y" in ret && "z" in ret) {
- this._x = ret.x;
- this._y = ret.y;
- this._z = ret.z;
- } else {
- this._x = x;
- this._y = y;
- this._z = z || 0;
- }
- return this;
- }
-
- /**
- * set the vector value without triggering the callback
- * @param {number} x - x value of the vector
- * @param {number} y - y value of the vector
- * @param {number} [z=0] - z value of the vector
- * @returns {ObservableVector3d} Reference to this object for method chaining
- */
- setMuted(x, y, z) {
- this._x = x;
- this._y = y;
- this._z = z || 0;
- return this;
- }
-
- /**
- * set the callback to be executed when the vector is changed
- * @param {Function} fn - callback
- * @param {Function} [scope=null] - scope
- * @returns {ObservableVector3d} Reference to this object for method chaining
- */
- setCallback(fn, scope = null) {
- if (typeof fn !== "function") {
- throw new Error("invalid `onUpdate` callback");
- }
- this.onUpdate = fn;
- this.scope = scope;
- return this;
- }
-
- /**
- * Add the passed vector to this vector
- * @param {Vector2d|Vector3d|ObservableVector2d|ObservableVector3d} v
- * @returns {ObservableVector3d} Reference to this object for method chaining
- */
- add(v) {
- return this._set(this._x + v.x, this._y + v.y, this._z + (v.z || 0));
- }
-
- /**
- * Substract the passed vector to this vector
- * @param {Vector2d|Vector3d|ObservableVector2d|ObservableVector3d} v
- * @returns {ObservableVector3d} Reference to this object for method chaining
- */
- sub(v) {
- return this._set(this._x - v.x, this._y - v.y, this._z - (v.z || 0));
- }
-
- /**
- * Multiply this vector values by the given scalar
- * @param {number} x
- * @param {number} [y=x]
- * @param {number} [z=1]
- * @returns {ObservableVector3d} Reference to this object for method chaining
- */
- scale(x, y = x, z = 1) {
- return this._set(this._x * x, this._y * y, this._z * z);
- }
-
- /**
- * Multiply this vector values by the passed vector
- * @param {Vector2d|Vector3d|ObservableVector2d|ObservableVector3d} v
- * @returns {ObservableVector3d} Reference to this object for method chaining
- */
- scaleV(v) {
- return this._set(this._x * v.x, this._y * v.y, this._z * (v.z || 1));
- }
-
- /**
- * Divide this vector values by the passed value
- * @param {number} n - the value to divide the vector by
- * @returns {ObservableVector3d} Reference to this object for method chaining
- */
- div(n) {
- return this._set(this._x / n, this._y / n, this._z / n);
- }
-
- /**
- * Update this vector values to absolute values
- * @returns {ObservableVector3d} Reference to this object for method chaining
- */
- abs() {
- return this._set(
- this._x < 0 ? -this._x : this._x,
- this._y < 0 ? -this._y : this._y,
- this._Z < 0 ? -this._z : this._z,
- );
- }
-
- /**
- * Clamp the vector value within the specified value range
- * @param {number} low
- * @param {number} high
- * @returns {ObservableVector3d} new me.ObservableVector3d
- */
- clamp(low, high) {
- return new ObservableVector3d(
- clamp(this._x, low, high),
- clamp(this._y, low, high),
- clamp(this._z, low, high),
- { onUpdate: this.onUpdate, scope: this.scope },
- );
- }
-
- /**
- * Clamp this vector value within the specified value range
- * @param {number} low
- * @param {number} high
- * @returns {ObservableVector3d} Reference to this object for method chaining
- */
- clampSelf(low, high) {
- return this._set(
- clamp(this._x, low, high),
- clamp(this._y, low, high),
- clamp(this._z, low, high),
- );
- }
-
- /**
- * Update this vector with the minimum value between this and the passed vector
- * @param {Vector2d|Vector3d|ObservableVector2d|ObservableVector3d} v
- * @returns {ObservableVector3d} Reference to this object for method chaining
- */
- minV(v) {
- const _vz = v.z || 0;
- return this._set(
- this._x < v.x ? this._x : v.x,
- this._y < v.y ? this._y : v.y,
- this._z < _vz ? this._z : _vz,
- );
- }
-
- /**
- * Update this vector with the maximum value between this and the passed vector
- * @param {Vector2d|Vector3d|ObservableVector2d|ObservableVector3d} v
- * @returns {ObservableVector3d} Reference to this object for method chaining
- */
- maxV(v) {
- const _vz = v.z || 0;
- return this._set(
- this._x > v.x ? this._x : v.x,
- this._y > v.y ? this._y : v.y,
- this._z > _vz ? this._z : _vz,
- );
- }
-
- /**
- * Floor the vector values
- * @returns {ObservableVector3d} new me.ObservableVector3d
- */
- floor() {
- return new ObservableVector3d(
- Math.floor(this._x),
- Math.floor(this._y),
- Math.floor(this._z),
- { onUpdate: this.onUpdate, scope: this.scope },
- );
- }
-
- /**
- * Floor this vector values
- * @returns {ObservableVector3d} Reference to this object for method chaining
- */
- floorSelf() {
- return this._set(
- Math.floor(this._x),
- Math.floor(this._y),
- Math.floor(this._z),
- );
- }
-
- /**
- * Ceil the vector values
- * @returns {ObservableVector3d} new me.ObservableVector3d
- */
- ceil() {
- return new ObservableVector3d(
- Math.ceil(this._x),
- Math.ceil(this._y),
- Math.ceil(this._z),
- { onUpdate: this.onUpdate, scope: this.scope },
- );
- }
-
- /**
- * Ceil this vector values
- * @returns {ObservableVector3d} Reference to this object for method chaining
- */
- ceilSelf() {
- return this._set(
- Math.ceil(this._x),
- Math.ceil(this._y),
- Math.ceil(this._z),
- );
- }
-
- /**
- * Negate the vector values
- * @returns {ObservableVector3d} new me.ObservableVector3d
- */
- negate() {
- return new ObservableVector3d(-this._x, -this._y, -this._z, {
- onUpdate: this.onUpdate,
- scope: this.scope,
- });
- }
-
- /**
- * Negate this vector values
- * @returns {ObservableVector3d} Reference to this object for method chaining
- */
- negateSelf() {
- return this._set(-this._x, -this._y, -this._z);
- }
-
- /**
- * Copy the components of the given vector into this one
- * @param {Vector2d|Vector3d|ObservableVector2d|ObservableVector3d} v
- * @returns {ObservableVector3d} Reference to this object for method chaining
- */
- copy(v) {
- return this._set(v.x, v.y, v.z || 0);
- }
-
- /**
- * return true if the two vectors are the same
- * @param {Vector2d|Vector3d|ObservableVector2d|ObservableVector3d} v
- * @returns {boolean}
- */
- equals(v) {
- return this._x === v.x && this._y === v.y && this._z === (v.z || this._z);
- }
-
- /**
- * change this vector to be perpendicular to what it was before.
- * (Effectively rotates it 90 degrees in a clockwise direction)
- * @returns {ObservableVector3d} Reference to this object for method chaining
- */
- perp() {
- return this._set(this._y, -this._x, this._z);
- }
-
- /**
- * Rotate this vector (counter-clockwise) by the specified angle (in radians).
- * @param {number} angle - The angle to rotate (in radians)
- * @param {Vector2d|ObservableVector2d} [v] - an optional point to rotate around (on the same z axis)
- * @returns {ObservableVector3d} Reference to this object for method chaining
- */
- rotate(angle, v) {
- let cx = 0;
- let cy = 0;
-
- if (typeof v === "object") {
- cx = v.x;
- cy = v.y;
- }
-
- // TODO also rotate on the z axis if the given vector is a 3d one
- const x = this.x - cx;
- const y = this.y - cy;
-
- const c = Math.cos(angle);
- const s = Math.sin(angle);
-
- return this._set(x * c - y * s + cx, x * s + y * c + cy, this.z);
- }
-
- /**
- * return the dot product of this vector and the passed one
- * @param {Vector2d|Vector3d|ObservableVector2d|ObservableVector3d} v
- * @returns {number} The dot product.
- */
- dot(v) {
- return this._x * v.x + this._y * v.y + this._z * (v.z || 1);
- }
-
- /**
- * calculate the cross product of this vector and the passed one
- * @param {Vector3d|ObservableVector3d} v
- * @returns {ObservableVector3d} Reference to this object for method chaining
- */
- cross(v) {
- const ax = this._x;
- const ay = this._y;
- const az = this._z;
- const bx = v.x;
- const by = v.y;
- const bz = v.z;
-
- return this._set(ay * bz - az * by, az * bx - ax * bz, ax * by - ay * bx);
- }
-
- /**
- * Linearly interpolate between this vector and the given one.
- * @param {Vector3d|ObservableVector3d} v
- * @param {number} alpha - distance along the line (alpha = 0 will be this vector, and alpha = 1 will be the given one).
- * @returns {ObservableVector3d} Reference to this object for method chaining
- */
- lerp(v, alpha) {
- return this._set(
- this._x + (v.x - this._x) * alpha,
- this._y + (v.y - this._y) * alpha,
- this._z + (v.z - this._z) * alpha,
- );
- }
-
- /**
- * interpolate the position of this vector on the x and y axis towards the given one while ensure that the distance never exceeds the given step.
- * @param {Vector2d|ObservableVector2d|Vector3d|ObservableVector3d} target
- * @param {number} step - the maximum step per iteration (Negative values will push the vector away from the target)
- * @returns {ObservableVector3d} Reference to this object for method chaining
- */
- moveTowards(target, step) {
- const angle = Math.atan2(target.y - this._y, target.x - this._x);
-
- const dx = this._x - target.x;
- const dy = this._y - target.y;
-
- const distance = Math.sqrt(dx * dx + dy * dy);
-
- if (distance === 0 || (step >= 0 && distance <= step * step)) {
- return target;
- }
-
- return this._set(
- this._x + Math.cos(angle) * step,
- this._y + Math.sin(angle) * step,
- this._z,
- );
- }
-
- /**
- * return the distance between this vector and the passed one
- * @param {Vector2d|Vector3d|ObservableVector2d|ObservableVector3d} v
- * @returns {number}
- */
- distance(v) {
- const dx = this._x - v.x;
- const dy = this._y - v.y;
- const dz = this._z - (v.z || 0);
- return Math.sqrt(dx * dx + dy * dy + dz * dz);
- }
-
- /**
- * return a clone copy of this vector
- * @returns {ObservableVector3d} new me.ObservableVector3d
- */
- clone() {
- return pool.pull("ObservableVector3d", this._x, this._y, this._z, {
- onUpdate: this.onUpdate,
- });
- }
-
- /**
- * return a `me.Vector3d` copy of this `me.ObservableVector3d` object
- * @returns {Vector3d} new me.Vector3d
- */
- toVector3d() {
- return pool.pull("Vector3d", this._x, this._y, this._z);
- }
-
- /**
- * convert the object to a string representation
- * @returns {string}
- */
- toString() {
- return "x:" + this._x + ",y:" + this._y + ",z:" + this._z;
- }
-}
diff --git a/packages/melonjs/src/renderable/entity/entity.js b/packages/melonjs/src/renderable/entity/entity.js
index cab875396d..51f2adc7e2 100644
--- a/packages/melonjs/src/renderable/entity/entity.js
+++ b/packages/melonjs/src/renderable/entity/entity.js
@@ -53,10 +53,10 @@ export default class Entity extends Renderable {
// Update anchorPoint
if (settings.anchorPoint) {
- this.anchorPoint.setMuted(settings.anchorPoint.x, settings.anchorPoint.y);
+ this.anchorPoint.set(settings.anchorPoint.x, settings.anchorPoint.y);
} else {
// for backward compatibility
- this.anchorPoint.setMuted(0, 0);
+ this.anchorPoint.set(0, 0);
}
// set the sprite name if specified
diff --git a/packages/melonjs/src/renderable/renderable.js b/packages/melonjs/src/renderable/renderable.js
index f4bcca7660..3830074d99 100644
--- a/packages/melonjs/src/renderable/renderable.js
+++ b/packages/melonjs/src/renderable/renderable.js
@@ -1,5 +1,3 @@
-import ObservableVector2d from "./../math/observable_vector2.js";
-import ObservableVector3d from "./../math/observable_vector3.js";
import Rect from "./../geometries/rectangle.js";
import pool from "./../system/pooling.js";
import { releaseAllPointerEvents } from "./../input/input.js";
@@ -40,25 +38,7 @@ export default class Renderable extends Rect {
// parent constructor
super(x, y, width, height);
- if (this.pos instanceof ObservableVector3d) {
- this.pos.setMuted(x, y, 0).setCallback(this.updateBoundsPos, this);
- } else {
- /**
- * Position of the Renderable relative to its parent container
- * @public
- * @type {ObservableVector3d}
- */
- this.pos = pool.pull("ObservableVector3d", x, y, 0, {
- onUpdate: this.updateBoundsPos,
- scope: this,
- });
- }
-
- if (this.anchorPoint instanceof ObservableVector2d) {
- this.anchorPoint
- .setMuted(0.5, 0.5)
- .setCallback(this.onAnchorUpdate, this);
- } else {
+ if (typeof this.anchorPoint === "undefined") {
/**
* The anchor point is used for attachment behavior, and/or when applying transformations.
* The coordinate system places the origin at the top left corner of the frame (0, 0) and (1, 1) means the bottom-right corner
@@ -67,13 +47,25 @@ export default class Renderable extends Rect {
*
* Note: Object created through Tiled will have their anchorPoint set to (0, 0) to match Tiled Level editor implementation.
* To specify a value through Tiled, use a json expression like `json:{"x":0.5,"y":0.5}`.
- * @type {ObservableVector2d}
+ * @type {Vector2d}
* @default <0.5,0.5>
*/
- this.anchorPoint = pool.pull("ObservableVector2d", 0.5, 0.5, {
- onUpdate: this.onAnchorUpdate,
- scope: this,
+ this.anchorPoint = pool.pull("Vector2d", 0.5, 0.5);
+ /**
+ * proxy to the anchorPoint vector
+ * @ignore
+ */
+ this.anchorPointProxy = new Proxy(this.anchorPoint, {
+ set: (obj, prop, value) => {
+ // store the new value
+ obj[prop] = value;
+ this.updateBounds();
+ this.isDirty = true;
+ return true;
+ },
});
+ } else {
+ this.anchorPoint.set(0.5, 0.5);
}
if (typeof this.currentTransform === "undefined") {
@@ -556,7 +548,7 @@ export default class Renderable extends Rect {
/**
* Rotate this renderable by the specified angle (in radians).
* @param {number} angle - The angle to rotate (in radians)
- * @param {Vector2d|ObservableVector2d} [v] - an optional point to rotate around
+ * @param {Vector2d} [v] - an optional point to rotate around
* @returns {Renderable} Reference to this object for method chaining
*/
rotate(angle, v) {
@@ -650,14 +642,6 @@ export default class Renderable extends Rect {
}
}
- /**
- * update the renderable's bounding rect (private)
- * @ignore
- */
- updateBoundsPos(newX = this.pos.x, newY = this.pos.y) {
- this.getBounds().translate(newX - this.pos.x, newY - this.pos.y);
- }
-
/**
* return the renderable absolute position in the game world
* @returns {Vector2d}
@@ -678,21 +662,6 @@ export default class Renderable extends Rect {
return this._absPos;
}
- /**
- * called when the anchor point value is changed
- * @private
- * @param {number} x - the new X value to be set for the anchor
- * @param {number} y - the new Y value to be set for the anchor
- */
- onAnchorUpdate(x, y) {
- // since the callback is called before setting the new value
- // manually update the anchor point (required for updateBoundsPos)
- this.anchorPoint.setMuted(x, y);
- // then call updateBounds
- this.updateBounds();
- this.isDirty = true;
- }
-
/**
* Prepare the rendering context before drawing (automatically called by melonJS).
* This will apply any defined transforms, anchor point, tint or blend mode and translate the context accordingly to this renderable position.
diff --git a/packages/melonjs/src/renderable/sprite.js b/packages/melonjs/src/renderable/sprite.js
index 3562ab291f..f530f10369 100644
--- a/packages/melonjs/src/renderable/sprite.js
+++ b/packages/melonjs/src/renderable/sprite.js
@@ -549,7 +549,7 @@ export default class Sprite extends Renderable {
this.height = this.current.height = region.height;
// set global anchortPoint if defined
if (region.anchorPoint) {
- this.anchorPoint.setMuted(
+ this.anchorPoint.set(
this._flip.x && region.trimmed === true
? 1 - region.anchorPoint.x
: region.anchorPoint.x,
diff --git a/packages/melonjs/tests/observableVect2d.spec.js b/packages/melonjs/tests/observableVect2d.spec.js
deleted file mode 100644
index a0c54ed040..0000000000
--- a/packages/melonjs/tests/observableVect2d.spec.js
+++ /dev/null
@@ -1,227 +0,0 @@
-import { describe, expect, it } from "vitest";
-import { ObservableVector2d, Vector2d, math } from "../src/index.js";
-
-describe("ObservableVector2d", () => {
- const x = 1;
- const y = 2;
-
- let a;
- let b;
- let c;
-
- let _newX;
- let _newY;
- let _oldX;
- let _oldY;
-
- const callback = function (newX, newY, oldX, oldY) {
- // this will also validate the argument list
- _newX = newX;
- _newY = newY;
- _oldX = oldX;
- _oldY = oldY;
- };
-
- const callback_with_ret = function () {
- return {
- x: 10,
- y: 10,
- };
- };
-
- it("should be initialized to a (0, 0) 2d vector", function () {
- a = new ObservableVector2d(0, 0, {
- onUpdate: callback.bind(this),
- });
- b = new ObservableVector2d(0, 0, {
- onUpdate: callback.bind(this),
- });
- c = new ObservableVector2d(0, 0, {
- onUpdate: callback.bind(this),
- });
-
- expect(a.toString()).toEqual("x:0,y:0");
- });
-
- it("setting the vector triggers the callback", () => {
- a.set(10, 100);
- expect(a.x + a.y).toEqual(_newX + _newY);
- });
-
- it("callback returns a vector value", function () {
- const d = new ObservableVector2d(0, 0, {
- onUpdate: callback_with_ret.bind(this),
- });
- d.set(100, 100);
- expect(d.x + d.y).toEqual(20); // 10 + 10
- });
-
- it("add a vector triggers the callback", () => {
- a.add(new Vector2d(10, 10));
- expect(a.y).toEqual(_oldY + 10);
- });
-
- it("sub a vector triggers the callback", () => {
- a.sub(new Vector2d(10, 10));
- expect(a.x).toEqual(_oldX - 10);
- });
-
- it("a(1, 2) should be copied into b", () => {
- a.set(x, y);
- b.copy(a);
-
- expect(b.equals(a)).toEqual(true);
- });
-
- it("scale (1, 2) by (-1, -2)", () => {
- a.set(x, y);
- b.set(-x, -y);
-
- expect(a.scaleV(b).toString()).toEqual("x:" + x * -x + ",y:" + y * -y);
- });
-
- it("negate (1, 2)", () => {
- a.set(x, y);
-
- expect(a.negateSelf().toString()).toEqual("x:" + -x + ",y:" + -y);
- });
-
- it("dot Product (1, 2) and (-1, -2)", () => {
- a.set(x, y);
- b.set(-x, -y);
-
- // calculate the dot product
- expect(a.dot(b)).toEqual(-x * x - y * y);
- });
-
- it("cross Product (2, 3) and (5, 6)", () => {
- a.set(2, 3);
- b.set(5, 6);
-
- // calculate the cross product
- expect(a.cross(b)).toEqual(-3);
- });
-
- it("length/lengthSqrt functions", () => {
- a.set(x, 0);
- b.set(0, -y);
- c.set(0, 0);
-
- expect(a.length()).toEqual(x);
- expect(a.length2()).toEqual(x * x);
- expect(b.length()).toEqual(y);
- expect(b.length2()).toEqual(y * y);
- expect(c.length()).toEqual(0);
- expect(c.length2()).toEqual(0);
-
- a.set(x, y);
- expect(a.length()).toEqual(Math.sqrt(x * x + y * y));
- expect(a.length2()).toEqual(x * x + y * y);
- });
-
- it("lerp functions", () => {
- a.set(x, 0);
- b.set(0, -y);
-
- expect(a.clone().lerp(a, 0).equals(a.lerp(a, 0.5))).toEqual(true);
- expect(a.clone().lerp(a, 0).equals(a.lerp(a, 1))).toEqual(true);
-
- expect(a.clone().lerp(b, 0).equals(a)).toEqual(true);
-
- expect(a.clone().lerp(b, 0.5).x).toEqual(x * 0.5);
- expect(a.clone().lerp(b, 0.5).y).toEqual(-y * 0.5);
-
- expect(a.clone().lerp(b, 1).equals(b)).toEqual(true);
- });
-
- it("normalize function", () => {
- a.set(x, 0);
- b.set(0, -y);
-
- a.normalize();
- expect(a.length()).toEqual(1);
- expect(a.x).toEqual(1);
-
- b.normalize();
- expect(b.length()).toEqual(1);
- expect(b.y).toEqual(-1);
- });
-
- it("distance function", () => {
- a.set(x, 0);
- b.set(0, -y);
- c.set(0, 0);
-
- expect(a.distance(c)).toEqual(x);
- expect(b.distance(c)).toEqual(y);
- });
-
- it("min/max/clamp", () => {
- a.set(x, y);
- b.set(-x, -y);
- c.set(0, 0);
-
- c.copy(a).minV(b);
- expect(c.x).toEqual(-x);
- expect(c.y).toEqual(-y);
-
- c.copy(a).maxV(b);
- expect(c.x).toEqual(x);
- expect(c.y).toEqual(y);
-
- c.set(-2 * x, 2 * x);
- c.clampSelf(-x, x);
- expect(c.x).toEqual(-x);
- expect(c.y).toEqual(x);
- });
-
- it("ceil/floor", () => {
- expect(
- a.setMuted(-0.1, 0.1).floorSelf().equals(new Vector2d(-1, 0)),
- ).toEqual(true);
- expect(
- b.setMuted(-0.5, 0.5).floorSelf().equals(new Vector2d(-1, 0)),
- ).toEqual(true);
- expect(
- c.setMuted(-0.9, 0.9).floorSelf().equals(new Vector2d(-1, 0)),
- ).toEqual(true);
-
- expect(a.setMuted(-0.1, 0.1).ceilSelf().equals(new Vector2d(0, 1))).toEqual(
- true,
- );
- expect(b.setMuted(-0.5, 0.5).ceilSelf().equals(new Vector2d(0, 1))).toEqual(
- true,
- );
- expect(c.setMuted(-0.9, 0.9).ceilSelf().equals(new Vector2d(0, 1))).toEqual(
- true,
- );
- });
-
- it("project a on b", () => {
- a.set(x, y);
- b.set(-x, -y);
-
- // the following only works with (-)1, (-)2style of values
- expect(a.project(b).equals(b)).toEqual(true);
- });
-
- it("angle between a and b", () => {
- a.set(x, y);
- b.set(-x, -y);
-
- // why is this not perfectly 180 degrees ?
- expect(Math.round(math.radToDeg(a.angle(b)))).toEqual(180);
-
- b.set(4 * x, -y);
- expect(a.angle(b)).toEqual(Math.PI / 2);
- });
-
- it("perp and rotate function", () => {
- a.set(x, y);
- b.copy(a).perp();
- // perp rotate the vector by 90 degree clockwise on the z axis
- c.copy(a).rotate(Math.PI / 2);
-
- expect(a.angle(b)).toEqual(a.angle(c));
- });
-});
diff --git a/packages/melonjs/tests/observableVect3d.spec.js b/packages/melonjs/tests/observableVect3d.spec.js
deleted file mode 100644
index 271a29d39f..0000000000
--- a/packages/melonjs/tests/observableVect3d.spec.js
+++ /dev/null
@@ -1,281 +0,0 @@
-import { describe, expect, it } from "vitest";
-import { ObservableVector3d, Vector3d, math } from "../src/index.js";
-
-describe("ObservableVector3d", () => {
- const x = 1;
- const y = 2;
- const z = 3;
-
- let a;
- let b;
- let c;
- let d;
-
- let _newX;
- let _newY;
- let _newZ;
- let _oldX;
- let _oldY;
- let _oldZ;
-
- const callback = function (newX, newY, newZ, oldX, oldY, oldZ) {
- // this will also validate the argument list
- _newX = newX;
- _newY = newY;
- _newZ = newZ;
- _oldX = oldX;
- _oldY = oldY;
- _oldZ = oldZ;
- };
-
- const callback_with_ret = function () {
- return {
- x: 10,
- y: 10,
- z: 10,
- };
- };
-
- it("should be initialized to a (0, 0, 0) 3d vector", function () {
- a = new ObservableVector3d(0, 0, 0, {
- onUpdate: callback.bind(this),
- });
- b = new ObservableVector3d(x, 0, 0, {
- onUpdate: callback.bind(this),
- });
- c = new ObservableVector3d(x, y, 0, {
- onUpdate: callback.bind(this),
- });
-
- d = new ObservableVector3d(x, y, z, {
- onUpdate: callback.bind(this),
- });
-
- expect(a.toString()).toEqual("x:0,y:0,z:0");
- });
-
- it("setting the vector triggers the callback", () => {
- a.set(10, 100, 20);
-
- expect(a.x + a.y + a.z).toEqual(_newX + _newY + _newZ);
- });
-
- it("callback returns a vector value", function () {
- const d = new ObservableVector3d(0, 0, 0, {
- onUpdate: callback_with_ret.bind(this),
- });
- d.set(100, 100, 100);
- expect(d.x + d.y + d.z).toEqual(30); // 10 + 10 + 10
- });
-
- it("add a vector triggers the callback", () => {
- a.add(new Vector3d(10, 10, 10));
-
- expect(a.y).toEqual(_oldY + 10);
- });
-
- it("sub a vector triggers the callback", () => {
- a.sub(new Vector3d(10, 10, 10));
-
- expect(a.x).toEqual(_oldX - 10);
- });
-
- it("scale a vector triggers the callback", () => {
- a.scaleV(new Vector3d(10, 10, 10));
-
- expect(a.x).toEqual(_oldX * 10);
- expect(a.y).toEqual(_oldY * 10);
- expect(a.z).toEqual(_oldZ * 10);
- });
-
- it("negate (1, 2, 3)", () => {
- a.set(x, y, z);
-
- expect(a.negateSelf().toString()).toEqual(
- "x:" + -x + ",y:" + -y + ",z:" + -z,
- );
- });
-
- it("dot Product (1, 2, 3) and (-1, -2, -3)", () => {
- a.set(x, y, z);
- b.set(-x, -y, -z);
-
- // calculate the dot product
- expect(a.dot(b)).toEqual(-x * x - y * y - z * z);
- });
-
- it("cross Product (2, 3, 4) and (5, 6, 7)", () => {
- a.set(2, 3, 4);
- b.set(5, 6, 7);
-
- const crossed = new Vector3d(-3, 6, -3);
-
- // calculate the cross product
- a.cross(b);
- expect(Math.abs(a.x - crossed.x)).toBeCloseTo(0, 4);
- expect(Math.abs(a.y - crossed.y)).toBeCloseTo(0, 4);
- expect(Math.abs(a.z - crossed.z)).toBeCloseTo(0, 4);
- });
-
- it("length/lengthSqrt functions", () => {
- a.set(x, 0, 0);
- b.set(0, -y, 0);
- c.set(0, 0, z);
- d.set(0, 0, 0);
-
- expect(a.length()).toEqual(x);
- expect(a.length2()).toEqual(x * x);
- expect(b.length()).toEqual(y);
- expect(b.length2()).toEqual(y * y);
- expect(c.length()).toEqual(z);
- expect(c.length2()).toEqual(z * z);
- expect(d.length()).toEqual(0);
- expect(d.length2()).toEqual(0);
-
- a.set(x, y, z);
-
- expect(a.length()).toEqual(Math.sqrt(x * x + y * y + z * z));
- expect(a.length2()).toEqual(x * x + y * y + z * z);
- });
-
- it("lerp functions", () => {
- a.set(x, 0, z);
- b.set(0, -y, 0);
-
- expect(a.clone().lerp(a, 0).equals(a.lerp(a, 0.5))).toEqual(true);
- expect(a.clone().lerp(a, 0).equals(a.lerp(a, 1))).toEqual(true);
-
- expect(a.clone().lerp(b, 0).equals(a)).toEqual(true);
-
- expect(a.clone().lerp(b, 0.5).x).toEqual(x * 0.5);
- expect(a.clone().lerp(b, 0.5).y).toEqual(-y * 0.5);
- expect(a.clone().lerp(b, 0.5).z).toEqual(z * 0.5);
-
- expect(a.clone().lerp(b, 1).equals(b)).toEqual(true);
- });
-
- it("normalize function", () => {
- a.set(x, 0, 0);
- b.set(0, -y, 0);
- c.set(0, 0, z);
-
- a.normalize();
- expect(a.length()).toEqual(1);
- expect(a.x).toEqual(1);
-
- b.normalize();
- expect(b.length()).toEqual(1);
- expect(b.y).toEqual(-1);
-
- c.normalize();
- expect(c.length()).toEqual(1);
- expect(c.z).toEqual(1);
- });
-
- it("distance function", () => {
- a.set(x, 0, 0);
- b.set(0, -y, 0);
- c.set(0, 0, z);
- d.set(0, 0, 0);
-
- expect(a.distance(d)).toEqual(x);
- expect(b.distance(d)).toEqual(y);
- expect(c.distance(d)).toEqual(z);
- });
-
- it("min/max/clamp", () => {
- a.set(x, y, z);
- b.set(-x, -y, -z);
- c.set(0, 0, 0);
-
- c.copy(a).minV(b);
- expect(c.x).toEqual(-x);
- expect(c.y).toEqual(-y);
- expect(c.z).toEqual(-z);
-
- c.copy(a).maxV(b);
- expect(c.x).toEqual(x);
- expect(c.y).toEqual(y);
- expect(c.z).toEqual(z);
-
- c.set(-2 * x, 2 * x, 2 * z);
- c.clampSelf(-x, x);
- expect(c.x).toEqual(-x);
- expect(c.y).toEqual(x);
- expect(c.z).toEqual(x);
- });
-
- it("ceil/floor", () => {
- expect(
- a
- .set(-0.1, 0.1, 0.3)
- .floorSelf()
- .equals(new Vector3d(-1, 0, 0)),
- ).toEqual(true);
- expect(
- a
- .set(-0.5, 0.5, 0.6)
- .floorSelf()
- .equals(new Vector3d(-1, 0, 0)),
- ).toEqual(true);
- expect(
- a
- .set(-0.9, 0.9, 0.8)
- .floorSelf()
- .equals(new Vector3d(-1, 0, 0)),
- ).toEqual(true);
-
- expect(
- a
- .set(-0.1, 0.1, 0.3)
- .ceilSelf()
- .equals(new Vector3d(0, 1, 1)),
- ).toEqual(true);
- expect(
- a
- .set(-0.5, 0.5, 0.6)
- .ceilSelf()
- .equals(new Vector3d(0, 1, 1)),
- ).toEqual(true);
- expect(
- a
- .set(-0.9, 0.9, 0.9)
- .ceilSelf()
- .equals(new Vector3d(0, 1, 1)),
- ).toEqual(true);
- });
-
- it("project a on b", () => {
- a.set(x, y, z);
- b.set(-x, -y, -z);
-
- // the following only works with (-)1, (-)2, (-)3 style of values
- expect(a.project(b).equals(b)).toEqual(true);
- });
-
- it("angle between a and b", () => {
- a.set(0, -0.18851655680720186, 0.9820700116639124);
- b.set(0, 0.18851655680720186, -0.9820700116639124);
-
- expect(a.angle(a)).toEqual(0);
- expect(a.angle(b)).toEqual(Math.PI);
-
- a.set(x, y, 0);
- b.set(-x, -y, 0);
-
- // why is this not perfectly 180 degrees ?
- expect(math.round(math.radToDeg(a.angle(b)))).toEqual(180);
-
- b.set(4 * x, -y, 0);
- expect(a.angle(b)).toEqual(Math.PI / 2);
- });
-
- it("perp and rotate function", () => {
- a.set(x, y, z);
- b.copy(a).perp();
- // perp rotate the vector by 90 degree clockwise on the z axis
- c.copy(a).rotate(Math.PI / 2);
-
- expect(a.angle(b)).toEqual(a.angle(c));
- });
-});