|
| 1 | +# 克隆 |
| 2 | + |
| 3 | +# 简介 |
| 4 | +节点克隆是运行时的常用功能,同时节点克隆也会附带克隆其绑定的组件。例如在初始化阶段根据配置动态创建一定数量相同的实体,然后根据逻辑规则摆放到场景不同的位置。这里会对脚本的克隆细节进行详细讲解。 |
| 5 | + |
| 6 | + |
| 7 | +# 使用 |
| 8 | +## 实体的克隆 |
| 9 | +非常简单,直接调用实体的 [clone()]({{book.api}}interfaces/design.iclone.html#clone) 方法即可完成实体以及附属组件的克隆。 |
| 10 | +```typescript |
| 11 | +const cloneEntity = entity.clone(); |
| 12 | +``` |
| 13 | + |
| 14 | + |
| 15 | +## 脚本的克隆 |
| 16 | +脚本的本质也是组件,所以当我们调用实体的 [clone()]({{book.api}}interfaces/design.iclone.html#clone) 函数时,引擎不仅会对引擎内置组件进行克隆,还是对自定义脚本进行克隆。引擎内置组件的克隆规则官方已经完成定制,同样我们也将脚本的克隆能力和规则定制开放给了开发者。脚本字段默认的克隆方式为浅拷贝,例如我们对脚本的字段值进行修改后再克隆,克隆后的脚本将保持修改后的值,无需增加任何额外的编码。以下为自定义脚本的克隆案例: |
| 17 | +```typescript |
| 18 | +// define a custom script |
| 19 | +class CustomScript extends Script{ |
| 20 | + /** boolean type.*/ |
| 21 | + a:boolean = false; |
| 22 | + |
| 23 | + /** number type.*/ |
| 24 | + b:number = 1; |
| 25 | + |
| 26 | + /** class type.*/ |
| 27 | + c:Vector3 = new Vector3(0,0,0); |
| 28 | +} |
| 29 | + |
| 30 | +//init entity and script. |
| 31 | +const entity = engine.createEntity(); |
| 32 | +const script = entity.addComponent(CustomScript); |
| 33 | +script.a = true; |
| 34 | +script.b = 2; |
| 35 | +script.c.setValue(1,1,1); |
| 36 | + |
| 37 | +// clone logic. |
| 38 | +const cloneEntity = entity.clone(); |
| 39 | +const cloneScript = cloneEntity.getComponent(CustomScript); |
| 40 | +console.log(cloneScript.a);// output is true. |
| 41 | +console.log(cloneScript.b);// output is 2. |
| 42 | +console.log(cloneScript.c);// output is (1,1,1). |
| 43 | +``` |
| 44 | +### 克隆装饰器 |
| 45 | +除了默认的克隆方式外,引擎还提供了“克隆装饰器“对脚本字段的克隆方式进行定制。引擎内置四种克隆装饰: |
| 46 | + |
| 47 | +| 装饰器名称 | 装饰器释义 | |
| 48 | +| :--- | :--- | |
| 49 | +| [ignoreClone]({{book.api}}modules/core.html#ignoreclone) | 克隆时对字段进行忽略。 | |
| 50 | +| [assignmentClone]({{book.api}}modules/core.html#assignmentclone) | ( 默认值,和不添加任何克隆装饰器等效) 克隆时对字段进行赋值。如果是基本类型则会拷贝值,如果是引用类型则会拷贝其引用地址。 | |
| 51 | +| [shallowClone]({{book.api}}modules/core.html#shallowclone) | 克隆时对字段进行浅克隆。克隆后会保持自身引用独立,并使用赋值的方式克隆其内部所有字段(如果内部字段是基本类型则会拷贝值,如果内部字段是引用类型则会拷贝其引用地址)。| |
| 52 | +| [deepClone]({{book.api}}modules/core.html#deepClone) | 克隆时对字段进行深克隆。克隆后会保持自身引用独立,并且其内部所有深层字段均保持完全独立。| |
| 53 | + |
| 54 | + 我们将上面的案例稍加修改,分别对 `CustomScript` 中的四个字段添加了不同的“克隆装饰器“,由于 `shallowClone` 和 `deepCone` 较复杂,我们对字段 `c` 和 `d` 增加了额外的打印输出进行进一步讲解。 |
| 55 | +```typescript |
| 56 | +// define a custom script |
| 57 | +class CustomScript extends Script{ |
| 58 | + /** boolean type.*/ |
| 59 | + @ignoreClone |
| 60 | + a:boolean = false; |
| 61 | + |
| 62 | + /** number type.*/ |
| 63 | + @assignmentClone |
| 64 | + b:number = 1; |
| 65 | + |
| 66 | + /** class type.*/ |
| 67 | + @shallowClone |
| 68 | + c:Vector3[] = [new Vector3(0,0,0)]; |
| 69 | + |
| 70 | + /** class type.*/ |
| 71 | + @deepClone |
| 72 | + d:Vector3[] = [new Vector3(0,0,0)]; |
| 73 | +} |
| 74 | + |
| 75 | +//init entity and script. |
| 76 | +const entity = engine.createEntity(); |
| 77 | +const script = entity.addComponent(CustomScript); |
| 78 | +script.a = true; |
| 79 | +script.b = 2; |
| 80 | +script.c[0].setValue(1,1,1); |
| 81 | +script.d[0].setValue(1,1,1); |
| 82 | + |
| 83 | +// clone logic. |
| 84 | +const cloneEntity = entity.clone(); |
| 85 | +const cloneScript = cloneEntity.getComponent(CustomScript); |
| 86 | +console.log(cloneScript.a);// output is false,ignoreClone will ignore the value. |
| 87 | +console.log(cloneScript.b);// output is 2,assignmentClone is just assignment the origin value. |
| 88 | +console.log(cloneScript.c[0]);// output is Vector3(1,1,1),shallowClone clone the array shell,but use the same element. |
| 89 | +console.log(cloneScript.d[0]);// output is Vector3(1,1,1),deepClone clone the array shell and also clone the element. |
| 90 | + |
| 91 | +cloneScript.c[0].setValue(2,2,2);// change the field c[0] value to (2,2,2). |
| 92 | +cloneScript.d[0].setValue(2,2,2);// change the field d[0] value to (2,2,2). |
| 93 | + |
| 94 | +console.log(script.c[0]);// output is (2,2,2). bacause shallowClone let c[0] use the same reference with cloneScript's c[0]. |
| 95 | +console.log(script.d[0]);// output is (1,1,1). bacause deepClone let d[0] use the different reference with cloneScript's d[0]. |
| 96 | +``` |
| 97 | +注意: |
| 98 | + |
| 99 | +- `shallowClone` 和 `deepClone` 适用于 *Obect*、*Array* 和 *Class* 类型。 |
| 100 | +- `shallowClone` 克隆后会保持自身引用独立,并使用赋值的方式克隆其内部所有字段(如果内部字段是基本类型则会拷贝值,如果内部字段是引用类型则会拷贝其引用地址)。 |
| 101 | +- `deepClone` 如果在深克隆过程中遇到 *Class* 则会调用对象的 [cloneTo()]({{book.api}}interfaces/design.iclone.html#cloneTo) 实现克隆,需要对象实现 [IClone]({{bool.api}}interfaces/design.iclone.html) 接口。 |
0 commit comments