真的是应用AI去落地解决游戏问题了,而不是虚有其表的去讲AI
老板看到了会怎么想
鸿蒙的DevEco 可以直接ai测试ccc吗还是说要生成指定包来测试
用AI也是需要技术的
666


只是测试下发热和耗电
插眼 66666
niubi

666


666666 
邪修之为什么大量node.active 性能差, 比如数千个node 再update里 active = true/false
我们先看下node内部发生了什么
大量调用 node.active 会触发节点及其子孙的生命周期回调(preload/onEnable/onDisable)、组件启用、变换和渲染数据重建,导致大量 CPU 开销和可能的内存分配/GC。一次性激活或频繁切换很多节点还会打乱渲染批次
public activateNode (node: Node, active: boolean): void {
if (active) {
const task = activateTasksPool.get();
if (task) {
this._activatingStack.push(task);
this._activateNodeRecursively(node, task.preload, task.onLoad, task.onEnable);
task.preload.invoke();
task.onLoad.invoke();
task.onEnable.invoke();
this._activatingStack.pop();
activateTasksPool.put(task);
}
} else {
this._deactivateNodeRecursively(node);
// remove children of this node from previous activating tasks to debounce
// (this is an inefficient operation but it ensures general case could be implemented in a efficient way)
const stack = this._activatingStack;
for (const lastTask of stack) {
lastTask.preload.cancelInactive(IsPreloadStarted);
lastTask.onLoad.cancelInactive(IsOnLoadStarted);
lastTask.onEnable.cancelInactive(IsOnEnableCalled);
}
}
node.emit(NodeEventType.ACTIVE_IN_HIERARCHY_CHANGED, node);
}
怎么优化?
这里有2个思路
普通版
- 手动管理Node的Visible, 不渲染或者超出屏幕边界时候 我们设置成null, 同时使用init 作为激活函数名, 不实用默认的onEnable, 这个方案对于3D是比较友好了
function enqueueRenderObject (model: Model): void {
// filter model by view visibility
if (model.enabled) {
if (scene.isCulledByLod(camera, model)) {
return;
}
if (model.castShadow) {
castShadowObjects.push(getRenderObject(model, camera));
csmLayerObjects.push(getRenderObject(model, camera));
}
if (model.node && ((visibility & model.node.layer) === model.node.layer)
|| (visibility & model.visFlags)) {
// frustum culling
if (model.worldBounds && !geometry.intersect.aabbFrustum(model.worldBounds, camera.frustum)) {
return;
}
renderObjects.push(getRenderObject(model, camera));
}
}
}
for (let i = 0; i < models.length; i++) {
enqueueRenderObject(models[i]);
}
邪修版
但对于2D 3D 大量伤害文字和特效, 设置成null, 会影响batcher2D 的排序;
2D文字/3D特效/拖尾混排

优化重构assembler, 上万文字,脱尾,特效, 2个assembler 搞定, 同时保证三角面的有序culling
我们在assembler里面也做了3个优化
- 预创建 预先创建好极限大小的buffer, 如果超过, 会把有限时间的移除
- 位置分配 针对光污染特效, 单独一个assembler不去做特定排序(不过先来后到 数量大的时候, 不会很明显) 通过slot 预先分配, 先不用删除, 把能用的slot 给后续节点, 比如有1000个再跑的特效, 有500个要删除, 先添加了300个, 这时候我们通过 vbF32.fill/iBuffer.fill 更新到指定长度就可以了, 前面的数据
private _createBuffers(maxVertCount: number, maxIndexCount: number): EffectBuffer {
const device = director.root!.device;
const vbByteLength = maxVertCount * MultiEffect.VERTEX_SIZE;
const ibByteLength = maxIndexCount * 2;
const vbF32 = new Float32Array(maxVertCount * MultiEffect.FLOATS_PER_VERT);
const iBuffer = new Uint16Array(maxIndexCount);
const vertexBuffer = device.createBuffer(new gfx.BufferInfo(
gfx.BufferUsageBit.VERTEX | gfx.BufferUsageBit.TRANSFER_DST,
gfx.MemoryUsageBit.HOST | gfx.MemoryUsageBit.DEVICE,
vbByteLength,
MultiEffect.VERTEX_SIZE
));
const indexBuffer = device.createBuffer(new gfx.BufferInfo(
gfx.BufferUsageBit.INDEX | gfx.BufferUsageBit.TRANSFER_DST,
gfx.MemoryUsageBit.HOST | gfx.MemoryUsageBit.DEVICE,
ibByteLength,
2
));
return { vertexBuffer, indexBuffer, vbF32, iBuffer };
}
private _processRemovals(config: MatConfig) {
if (!config.hasRemovals) return;
const effs = config.effList!;
let i = 0;
while (i < effs.length) {
const eff = effs[i];
if (eff.remove) {
config.freeSlots!.push(eff.slotIndex);
this._clearEffectBuffer(eff);
// 使用 splice 保持数组连续性
effs.splice(i, 1);
} else {
i++;
}
}
config.hasRemovals = false;
}
private _clearEffectBuffer(eff: EffectConfig) {
const buffers = eff.matConfig!.buffers!;
const mat = eff.matConfig!;
const length = mat.maxLength!;
const shapeCount = 2;
const vertexCount = length * shapeCount * MultiEffect.FLOATS_PER_VERT;
const vbStart = eff.offset;
const indexCount = (length - 1) * (eff.shapeCount - 1) * 2 * 3;
const ibStart = eff.indexOffset;
buffers.vbF32.fill(0, vbStart, vbStart + vertexCount);
buffers.iBuffer.fill(0, ibStart, ibStart + indexCount);
EffectPool.put(eff);
}
牛逼呀大佬
鬼才啊 二喵酱
有这种小型优化的demo就好了,开箱即用,放store里卖也好
特定领域ai大显神通
Agent工作流优化/Debug能帮助熟练工提升效率, 对于基础薄弱/0基础的可能就像天阶功法了;
举个例子
- 优化convertToUINode 和 2D 节点跟随3D 坐标有延迟
AI会让你放在lateUpdate 或者做预判
但是我们去看源码和前置管线渲染 会发现是, 3D相机projection matrix 还没有更新
public extractRenderCameras (cameras: Camera[]): void {
for (let j = 0; j < this._cameras.length; j++) {
const camera = this._cameras[j];
if (camera.enabled) {
camera.update();
cameras.push(camera);
}
}
}
-
再比如如何把 convertToUINode的性能优化80%
-
初阶
展开 worldToScreen,convertToNodeSpaceAR 一层层优化, 优化个10-20%
、、、
public convertToUINode (wpos: Vec3 | Readonly, uiNode: Node, out?: Vec3): Vec3 {this._camera.worldToScreen(_temp_vec3_1, worldPos); const cmp = uiNode.getComponent('cc.UITransform') as UITransform; const view = cclegacy.view; const designSize = view._visibleRect; const xoffset = _temp_vec3_1.x - this._camera.width * 0.5; const yoffset = _temp_vec3_1.y - this._camera.height * 0.5; _temp_vec3_1.x = xoffset / view._scaleX + designSize.width * 0.5; _temp_vec3_1.y = yoffset / view._scaleY + designSize.height * 0.5; cmp.convertToNodeSpaceAR(_temp_vec3_1, out); return out;}
-
中阶
分析函数消耗的根本问题, convertToNodeSpaceAR 每次会获取节点矩阵, 并逆矩阵
this.node.getWorldMatrix(_worldMatrix);
Mat4.invert(_mat4_temp, _worldMatrix);
我们提前每帧, 计算节点的逆矩阵一次, 1000点节点, 可以减少 999 次逆矩阵运算, 优化 30-40%
-
高阶
为什么要逆矩阵完, 再把节点的世界坐标从逆矩阵转换呢? Vec3.transformMat4(out, worldPoint, _mat4_temp), 展开+优化 再可以提升 -
邪修
假如我的节点就是Canvas, Canvas的尺寸就是designSize, 那么Canvas逆矩阵 就是完全不想要了!
优化完, 开销可以忽略了
AI Agent 优化要结合自己的项目需要
- 每个项目一个自定义引擎/通用引擎优化+Git记录
- 引擎的功能可以应对绝大多数项目, 优化/邪修一定是有代价的, 大多时候会牺牲普适性
- AI Agent 时代强者更强, 代码和大佬们的框架/案例还是要看的
神了,猫哥
小母牛坐飞机,牛B上天了
猫神,还有没有ai规则分享一下呀.


