等了 5 个月,3.8.4 终于发布了。怀着激动的心情,我把自己的 OpenTGX、TGX-球球大乱斗、TGX-大厅子游戏项目都升级了。
从 Release Notes 来看,3.8.4 新增的东西蛮多的。我挑一些一眼就能看到的:
- Tween 增加了不少函数,更方便使用
- 支持 WebGPU
- 可定制管线(CRP)正式启用
- 插屏预览支持分辨率适配
- 节点属性 setter 机制变更,复用内部对象将不会触发脏标记
1、无感升级
我的 TGX 项目一直保持升级到最新版本,所以升级前是 v3.8.3,直接切换为 3.8.4 打开,没有发现任何问题。
检查 git,发现只改动了引擎版本号。
这说明,3.8.4 没有对资源部分做一丝改动,大家最担心的资源不兼容是完全不存在的。
2、管线兼容
我的 TGX 项目并没有使用自定义管线,升级到 3.8.4 后,在项目设置->图形设置面板可以看到,依然使用的是原渲染管线。
由于原渲染管线没有任何改动,所以可以确保旧项目是完全没有问题的。
官方说,新的内置管线完全兼容原管线,所以,我切换到了新管线,发现一切照旧。
我用 TGX 中的 2D 坦克和 3D 场景试了,都没有任何问题。
3、WebGPU
虽然是实验室功能,但还是忍不住想试试。
直接在项目设置->功能裁剪中勾选 WebGPU 即可。
为了确保是跑在 WebGPU 上的,我去掉了 WebGL 选项
不管是新管线还是原管线,在我的电脑上顺利运行,材质和阴影都 OK。
4、节点属性 setter 变更
早在 5 月,引擎组就在论坛发表了这个变更。
https://forum.cocos.org/t/topic/158404
简单来说就是,为了减少新对象的开销,Node 节点上的返回并没有采用 clone 形式,而是直接返回了引用。
为了防止这个引用的数据被直接修改,导致一些不必要的错乱,所以返回值加上了 readonly
限制。
开发者如果不修改这个值,那么只需要直接持有引用即可,是性能最高的写法。
如果想要修改这个值,最佳写法是。
1、申请一个可复用的临时变量
这个变量可以放在 class 外,也可以在比如像这样
//方法1:放在class外
const tempV3 = v3();
@ccclass('Layout_UIJoystickTank')
export class Layout_UIJoystickTank extends Component {
//方法二:放在 class 内
private _tempV3 = v3();
}
推荐使用 方法1,可以省点内存。
2、将 Node 属性的值复制过来
//方法1:使用 getWorldPosition
this.node.getWorldPosition(tempV3);
//方法2:使用 Vec3.set
this._tempV3.set(this.node.worldPosition);
方法1和方法2是等效的,选择喜欢的方式即可。
3、将值设置回去
//方法1:使用 setWorldPosition
this.node.setWorldPosition(tempV3);
//方法2:使用 setter
this.node.worldPosition = tempV3;
两种方法是等效的,都会触发引擎的脏标记,从而重新计算节点世界矩阵,更新渲染画面。
this.invalidateChildren(TransformBit.POSITION);
if (this._eventMask & TRANSFORM_ON) {
this.emit(NodeEventType.TRANSFORM_CHANGED, TransformBit.POSITION);
}
避免用法1
有很多同学试图直接修改数据更新位置。
this.node.worldPosition.set(0,0,0);
这样是不行的,因为这样操作,虽然改了值,但是引擎感知不到,无法触法世界矩阵重算,从而不会更新画面。 Vec3.set 函数长这样:
public set (x?: number | Vec3, y?: number, z?: number): Vec3 {
if (typeof x === 'object') {
this.x = x.x;
this.y = x.y;
this.z = x.z;
} else {
this.x = x || 0;
this.y = y || 0;
this.z = z || 0;
}
return this;
}
避免用法2
有一些同学,为了避免麻烦,复用了值,会像下面这样写。
注意这个
as Vec3
,如果不这样做其实是会报语法错误的,因为返回的是 readonly。
let pos = this.node.worldPosition as Vec3;
pos.set(5,6,7);
this.node.worldPosition = pos;
这样的写法在3.8.4之前可以,但在3.8.4之后就不行了。因为多加了 equals
判断。 当我们复用引擎内部的属性对象时,这个 eqauls
总是返回 true
,导致无法设置数据变脏的标记,从而无法更新渲染画面。
if (!forceUpdateLocalPosition && worldPosition.equals(val as Vec3)) {
return;
}
项目中有这样使用的朋友,在升级 3.8.4 后,需要清理掉。
麒麟子平时写项目严格遵守推荐写法来写的,所以项目升级很丝滑,并没有这个问题。
写在最后
后面抽时间用 Cyberpunk 这样的大项目再验证一下,看看体验如何。
其余的更新,像 Tween、插屏预览等,麒麟子来不及体验,大家体验后可以多多交流。