注意:Node 的一些 set 接口行为的修正

有具体的 issue 吗?我看接口是没有设置 z 的话,会用引擎内部的值。

能把你报错的详细信息贴一下吗?我看下哪里阻止了,再看是否有什么办法。

比如我这么写
image
运行报错
image
重定义x,y,z,scaleX,scaleY,scaleZ控制台红字,但是运行没问题
image

我是想一个tween处理node所有属性,跟2.x完全一致,又保留3.x的架构

就为了设置一个属性 写这么长的代码 也不知道谁设计的。。

类似的:https://forum.cocos.org/t/topic/157884

代码里单独设置分量确实是使用内部值,可能是我在做 tween 的时候直接传入了 v3(1, 1) 吧。

这个问题如果要解决的话,应该把这些接口都支持下 Vec2,这样人们就会使用 v2(1, 1) 了。

当然,知道不是不想做,做了的话会导致多个判断多态,again,performance first。

不过,像上面的 x、y、z 等修改原型以方便开发的我反正是每个项目都弄,毕竟我遇到的项目都是开发效率比性能重要。
之前 panda 说原型太多属性在某些设备会导致性能陡降,但是好像我记得没有弄清楚具体原因,我看了很多分析都是表明原型对象永远不会退化到字典模式,所以我觉得可能是 BUG,是否可以通过升级 v8 版本解决。

1赞

哦哦,我还真找到了这个 deprecated 属性。这些属性是 4 年前 deprecated 的,我们评估下看是否可以去掉了。

可以看看代码,y 和 z 的参数是可选的。我这里写的代码只是为了说明问题,不是 node 的使用教程。

@1107984843 我们讨论下,为了保持兼容,还是没法剔除。不过你可以在编辑器勾选剔除接口去删除废弃的接口

image

推荐的写法

1、申请一个Vec3 复用 const tmpV3 = new Vec3();

2、在需要使用的地方做如下操作

//获取
let worldPos = tmpV3.set(this.node.worldPosition);

//做相关操作

//设置回去
this.node.worldPosition = worldPos;

请注意,不要在 update 中使用 new, clone 等操作,否则会有性能和内存问题

3赞

因为要触发 position 的 setter,才能触发内部的矩阵更新

嗯嗯,期待

你这个大概是 Object.defineProperties 的时候
没有给 configurable:true
然后又重新执行了 defineProperty的时候的异常

试试

Object.defineProperties( cc.Node.prototype,
{
    width:
    {
        configurable:true,
        get(){}, set(v){}
    }
})

不然就是在Object.defineProperty之前
先检查一下

if( Node.prototype.hasOwnProperty( 'width' ) ) console.error( `属性width已存在?` )

试过了,没用,应该是引擎底层做了限制

1赞

水平有限,没看懂具体是可能会出现什么问题,是如果我没clone()的话,两个节点都用了同样的世界坐标,如果我只修改一个节点的坐标会影响到另外一个么

// cc.Vec3
class Vec3 {
    protected _x = 0;
    set x(v: number) {
        this._x = v;
    }
    get x() {
        return this._x;
    }

    protected _y = 0;
    set y(v: number) {
        this._y = v;
    }
    get y() {
        return this._y;
    }

    protected _z = 0;
    set z(v: number) {
        this._z = v;
    }
    get z() {
        return this._z;
    }

    constructor(x: number, y: number, z: number) {

    }
}

// 给position、scale等用的Vec3
class MyVec3 extends Vec3 {
    set x(v: number) {
        this._x = v;
        this.onChange?.call(this.target);
    }

    set y(v: number) {
        this._y = v;
        this.onChange?.call(this.target);
    }

    set z(v: number) {
        this._z = v;
        this.onChange?.call(this.target);
    }

    set(other: Vec3) {
        this._x = other.x;
        this._y = other.y;
        this._z = other.z;
        this.onChange?.call(this.target);
    }

    constructor(x: number, y: number, z: number, private onChange?: Function, private target?: unknown) {
        super(x, y, z);
    }
}

class Node {
    private _position = new MyVec3(0, 0, 0, this.onPositionChange, this);
    // 返回值类型还是Vec3,外部感受不到变化
    get position(): Vec3 {
        return this._position
    }
    set position(v: Vec3) {
        this._position.set(v);
    }

    setPosition(position: Vec3) {
        this._position.set(position);
    }

    private onPositionChange() {
        // position改变
    }
}

为什么不这样设计 或 类似的设计?

区别就在于,调用 set 接口时发现值一样就返回了,那么后续的逻辑就不会走。

这里的 set 不只是回调,还有别的一些逻辑。另外,如果对具体的接口设计有建议,建议可以开个新贴讨论。

明白了,感谢解答

这个问题很严重啊,还好逛论坛看到了。我很多项目的更新位置用getWorldPosition都不会再clone一次,一般都是node.getWorldPosition() 或者 node.worldPosition.clone()。

1赞