我正在开发一款游戏。因为我不想与框架结合,所以我为图形引擎编写了一个抽象,现在正尝试将 Three.js 塞入其中。
我正在使用 gl-matrix 进行向量数学(使用
vec3
,类型化数组), Three.js 有自己的向量类(使用 {x:number, y:number, z:number}
)。我的 3D 对象界面如下所示:
interface Thing{
...
position:vec3
}
我的实现如下所示:
class ThreeJsThing implements Thing{
...
set position(p:vec3){
this.mesh.position.set(p[0], p[1], p[2]) // [,,] -> {xyz}
}
get position(){
let p = this.mesh.position
return vec3.fromValues(p.x, p.y, p.z) // {xyz} -> [,,]
}
}
现在一切都很有趣和游戏,直到有人尝试这样做:
let myThing = new ThreeJsThing()
myThing.position[1] = 5 // only changes a temporary copy that is returned by the getter
对于 gl-matrix 这尤其是一个问题,因为它出于性能原因使用输出参数,在内部执行上面的数组分配:
vec3.add(myThing.position, a, b)
我知道如何解决这个问题,因为我(现在)意识到了它,但其他贡献者可能也会对此感到窒息,特别是因为它默默地失败了。仅从干净的代码角度来看,我无法真正确定我在哪里使用了反模式或糟糕的设计或其他东西。我发现
ThreeJsThing
尽可能忠实于界面。我有一些怀疑:
myThing.position[1] = 5
仍然是一个问题)任何建议表示赞赏。
我建议返回一个抽象而不是
vec3.fromValues
...
除非你真的需要它作为 vec3...
喜欢:
class ThreeJsThing implements Thing
{
// ...
set position ( p: vec3 )
{
this.mesh.position.set(p[0], p[1], p[2]) // [,,] -> {xyz}
}
get position ()
{
const p = this.mesh.position;
const o =
{
length: 3,
get 0 () { return p.x }
set 0 (n) { p.set(n, p.y, p.z) }
get 1 () { return p.y }
set 1 (n) { p.set(p.x, n, p.z) }
get 2 () { return p.z }
set 2 (n) { p.set(p.x, p.y, n) }
};
Object.setPrototypeOf(o, Array.prototype);
return o // {xyz} -> [,,]
}
}
PS.:我不是 TS 方面的专家,所以也许有问题......但我希望你明白。