You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为PlayCanvas递归clone方法打猴子补丁并在递归结束后执行代码

解决PlayCanvas递归clone时自定义代码重复执行的问题

我太懂这个痛点了——PlayCanvas的clone()方法会递归遍历整个节点层级,直接打猴子补丁的话,自定义代码会跟着递归调用跑N次,完全不是我们想要的「克隆完整个树再统一处理」的效果。下面给你一个靠谱的重写方案,能精准控制自定义代码只在整个递归克隆流程结束后执行一次。

核心思路

我们需要区分「顶层clone调用」和「递归内部的clone调用」:只有当是用户主动发起的顶层调用完成后,才触发自定义逻辑。这里用一个临时标记来追踪当前是否处于递归克隆过程中,避免内部调用误触发。

具体实现代码

// 先保存原始的clone方法,别弄丢了
const originalClone = pc.Entity.prototype.clone;

// 用Symbol做临时属性名,避免和其他代码的属性冲突
const isCloningSymbol = Symbol('isCloning');

// 重写Entity的clone方法
pc.Entity.prototype.clone = function(options) {
    // 判断是否是顶层调用:当前实体没有标记时,就是第一次调用
    const isTopLevelCall = !this[isCloningSymbol];

    // 顶层调用时,打上标记,告诉后续递归调用「别触发自定义逻辑」
    if (isTopLevelCall) {
        this[isCloningSymbol] = true;
    }

    // 执行原始的克隆逻辑,拿到克隆后的实体
    const clonedEntity = originalClone.call(this, options);

    // 只有顶层调用完成后,才执行自定义代码
    if (isTopLevelCall) {
        // 移除临时标记,避免污染实体
        delete this[isCloningSymbol];
        
        // --------------------------
        // 这里写你的自定义代码,只会执行一次!
        console.log("整个层级克隆完成,开始处理:", clonedEntity.name);
        // 示例:遍历克隆后的整个层级做统一处理
        this.handleClonedHierarchy(clonedEntity);
        // --------------------------
    }

    return clonedEntity;
};

// 示例自定义处理函数,你可以改成自己的逻辑
function handleClonedHierarchy(rootEntity) {
    // 比如给所有克隆节点加个标识
    rootEntity.findComponents('script').forEach(script => {
        script.cloned = true;
    });
    // 或者调整层级、修改属性等等
}

为什么这个方案有效?

  • 临时标记isCloningSymbol是唯一的,不会和你的其他代码或PlayCanvas内部属性冲突;
  • 只有第一次调用clone()(也就是你主动发起的顶层调用)会进入自定义代码分支,递归过程中内部的clone()调用会看到标记存在,跳过自定义逻辑;
  • 完全保留了PlayCanvas原始clone()的所有功能和参数,不会影响原有克隆行为。

备选方案:计数器方式

如果你担心临时属性的问题,也可以用计数器追踪递归层级:

const originalClone = pc.Entity.prototype.clone;
let cloneDepth = 0;

pc.Entity.prototype.clone = function(options) {
    cloneDepth++;
    const clonedEntity = originalClone.call(this, options);
    cloneDepth--;

    // 当计数器回到0,说明整个克隆流程结束
    if (cloneDepth === 0) {
        // 执行自定义代码
        console.log("克隆完成,处理:", clonedEntity);
    }

    return clonedEntity;
};

这个方案更简洁,但要注意如果同时有多个并行的克隆操作,计数器会互相干扰,所以第一种标记方式更安全。

内容的提问来源于stack exchange,提问作者mcmorry

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 07:25:23