three.js の基本的なクラスであるVector*
, Quaternion
, Matrix*
(*は3とか4とか)にはclone
, copy
, set
, fromArray
という関数が定義されています。これらは
-
clone
: 同一のプロパティをもつインスタンスを複製して返す- 例:
const vec3_ = vec3.clone();
- 例:
-
copy
: ただひとつの引数(同じクラスのインスタンス)のプロパティをそのインスタンスのプロパティにコピーする- 例:
vec3_.copy(vec3);
- 例:
-
set
: 引数ひとつひとつをそのインスタンスのプロパティひとつひとつにセットする- 例:
vec3.set(1, 2, 3);
- 例:
-
fromArray
: ただひとつの引数(配列)の要素をそのインスタンスのプロパティひとつひとつにセットする- 例:
vec3.fromArray([1, 2, 3]);
- 例:
……と覚えるまでが大変です。
この記事では特によく使うcopy
とset
について引数を間違えていると即座にランタイムで警告を出せるようにします。
.copy()
const overrideCopyFunction = function(cl, args) {
// 元のcopy関数
const cp = cl.prototype.copy;
cl.prototype.copy = function(from) {
// fromの「名前がargsに含まれるプロパティ」に数値でないものが含まれる場合に例外を返す
if(args.some(function(x) { return (typeof from[x]) != "number"; }))
throw new Error(); // お好きなメッセージをどうぞ
// 本来のcopy関数を呼ぶ
return (cp.bind(this))(from);
};
};
overrideCopyFunction(THREE.Vector3, ["x", "y", "z"]);
overrideCopyFunction(THREE.Quaternion, ["x", "y", "z", "w"]);
こんな感じにVector3
のcopy
関数を上書きします。
overrideCopyFunction
の引数には対象クラスとプロパティ名の配列を指定します。
copy
関数では他の物理演算エンジンのベクトルなどを使いたい場合もあるため、ここでは「数値型の.x
, .y
, .z
プロパティをもつオブジェクト」が渡された場合以外の際に例外を投げるようにしています。
.set()
const overrideSetFunction = function(cl) {
const st = cl.prototype.set;
cl.prototype.set = function(...from) {
if(from.some(function(x) { return (typeof x) != "number"; }))
throw new Error();
return (st.bind(this))(...from);
};
};
overrideSetFunction(THREE.Vector3);
overrideSetFunction(THREE.Quaternion);
set
についてもcopy
と同様に関数を上書きします。
新しいset
関数では引数のうち数値型でないものが含まれる場合に例外を投げ、そうでない場合にはその引数をオリジナルのset
関数にそのまま引き渡します。
実行例
適用前
> v
< Vector3 {x: 1, y: 2, z: 3, isVector3: true, set: function, ...}
> v2
< Vector3 {x: 4, y: 5, z: 6, isVector3: true, set: function, ...}
> v.set(7, 8, 9)
< Vector3 {x: 7, y: 8, z: 9, isVector3: true, set: function, ...}
> v.set(v2)
< Vector3 {x: Vector3, y: undefined, z: undefined, isVector3: true, set: function, ...}
2つ目のset
でv
が破壊されます。
> v
< Vector3 {x: 1, y: 2, z: 3, isVector3: true, set: function, ...}
> v2
< Vector3 {x: 4, y: 5, z: 6, isVector3: true, set: function, ...}
> v.copy(v2)
< Vector3 {x: 4, y: 5, z: 6, isVector3: true, set: function, ...}
> v.copy(7, 8, 9)
< Vector3 {x: undefined, y: undefined, z: undefined, isVector3: true, set: function, ...}
2つ目のcopy
でv
が破壊されます。
適用後
> v
< Vector3 {x: 1, y: 2, z: 3, isVector3: true, set: function, ...}
> v2
< Vector3 {x: 4, y: 5, z: 6, isVector3: true, set: function, ...}
> v.set(7, 8, 9)
< Vector3 {x: 7, y: 8, z: 9, isVector3: true, set: function, ...}
> v.set(v2)
< Error
> v
< Vector3 {x: 1, y: 2, z: 3, isVector3: true, set: function, ...}
> v2
< Vector3 {x: 4, y: 5, z: 6, isVector3: true, set: function, ...}
> v.copy(v2)
< Vector3 {x: 4, y: 5, z: 6, isVector3: true, set: function, ...}
> v.copy(7, 8, 9)
< Error
ちゃんとエラーが帰ってきます。