循环引用


问题背景

编辑器的错误反馈机制是在引用计数的基础上建立起来的。

假设 A 引用了 B ,如果 B 发生了错误, A 也会因此发生错误。

编辑器的引用链条可以抽象为下面这样:

ABC ➠ ・・・

而与之对应的错误反馈链条则是这样的:

・・・ CBA

这样一个错误反馈机制可以给我们带来开发上的便利,但同时他也引入了一个问题,那就是 循环引用

当出现下面这种情况时,

ABCA

A 最终间接引用了他自己,

错误反馈也将由此陷入调用地狱。

避免循环引用

目前编辑器层面上并不能解决此问题,开发者应该尽量避免出现循环引用的情况。

使用引用计数的对象

目前编辑器(非运行时)维护引用计数的对象有,

  • 行为树组件
  • 行为树任务
  • 共享变量

也就是说,应该避免在使用这几个对象时出现循环引用。

控制台警告

当编辑器检测到循环引用时,会在 CocosCreator 的控制台打印一条警告:

circular reference detected [ 一个表示引用链条的数组 ]

开发者在看到这条警告时,应该根据提示在编辑器上取消引用相关对象,打断引用链。

通过脚本引用

如果需要引用相关对象,可以在运行时通过脚本动态引用,避免使用编辑器。

引用一个行为树组件

当前行为树

当你需要引用当前行为树时,可以不用通过行为树选择器,因为 任务基类 本身有提供相关接口来获取当前行为树实例。

外部行为树

当你需要引用一个外部行为树时,可以通过 cc.Node 节点的 getComponent 方法来获取到。因为每个行为树实例都是某个 cc.Node 节点上的一个组件。

看下面这个引用外部行为树的例子,

// ExampleAction.ts
import { btclass, btprop, ActionTask, BehaviorTree } from 'bt.ALL';

@btclass('ExampleAction')
export class ExampleAction extends ActionTask {

    @btprop({ type: cc.Node })
    public target: cc.Node;

    /**
     * 缓存外部行为树。
     */
    private _externalTree: BehaviorTree;

    /**
     * 行为树加载完毕。
     */
    protected onReady(): void {

        if (this.target) {
            //
            // 获取行为树组件
            //
            this._externalTree = this.target.getComponent(BehaviorTree);
        }
    }
};

引用一个行为树任务

通过行为树组件提供的 getTask接口 可以获取到任务实例。

看下面这个引用 Switch 任务的例子,

// ExampleAction.ts
import { btclass, ActionTask, Switch } from 'bt.ALL';

@btclass('ExampleAction')
export class ExmapleAction extends ActionTask {

    /**
     * 缓存 Switch 任务实例。
     */
    private _switch: Switch;

    /**
     * 行为树加载完毕。
     */
    protected onReady(): void {

        //
        // 在当前行为树搜索,并返回找到的第一个 Switch 任务。
        //
        this._switch = this.tree.getTask(Switch);
    }
};

如果是分支作务,还可以通过自己本身继承的 getTask接口 获取到分支上的任务实例。

看下面这个引用 Switch 任务的例子,

// ExampleComposite.ts
import { btclass, CompositeTask, Switch } from 'bt.ALL';

@btclass('ExampleComposite')
export class ExampleComposite extends CompositeTask {

    /**
     * 缓存 Switch 任务实例。
     */
    private _switches: Switch[];

    /**
     * 行为树加载完毕。
     */
    protected onReady(): void {

        //
        // 在当前分支上搜索,并返回找到的所有 Switch 任务。
        //
        this._switches = this.getTasks(Switch);
    }
};

引用一个共享变量

目前不支持通过脚本引用共享变量。

results matching ""

    No results matching ""