cc 类的各种特性是通过 的 cc 类选项参数来指定的。

cc 类名

选项 name 指定了 cc 类的名称。cc 类名应该是独一无二的。

当需要相应的 cc 类时,可以通过其 cc 类名来查找,例如:

  • 序列化。 若对象是 cc 类对象, 则在序列化时将记录该对象的 cc 类名, 反序列化时将根据此名称找到相应的 cc 类进行序列化。

  • 当 cc 类是组件类时,Node 通过可以组件类的 cc 类名查找该组件;

cc 属性

当装饰器 应用在 cc 类的属性或访问器上时,此属性称为 cc 属性。 与 cc 类类似,cc 属性注入了额外的信息以控制 Cocos Creator 3D 对该属性的序列化、编辑器对该属性的展示等。

property

cc 属性的各种特性是通过 property() 的 cc 属性选项参数来指定的。

cc 类型

选项 type 指定了属性的 cc 类型。

可以通过以下几种形式的参数指定类型:

  • 构造函数。 构造函数所指定的类型就直接作为属性的 cc 类型。 注意,当 Javascript 内置构造函数 NumberStringBoolean 用作 cc 类型时将给出警告,并且将 分别视为 cc 类型 CCFloatCCStringCCBoolean

  • Cocos Creator 3D 内置属性类型标识。 CCIntegerCCFloatCCBooleanCCString 是内置属性类型标识。 CCInteger 声明类型为 Cocos Creator 3D 整数CCFloat 声明类型为 Cocos Creator 3D 浮点数CCString 声明类型为 Cocos Creator 3D 字符串CCBoolean 声明类型为 Cocos Creator 3D 布尔值

  • 数组。 通过将构造函数、Cocos Creator 3D 内置属性类型标识或数组作为数组元素时, 属性被指定为 Cocos Creator 3D 数组。 例如 [CCInteger] 就将类型声明为元素为Cocos Creator 3D 整数的 Cocos Creator 3D 数组。

若属性未指定 cc 类型,Cocos Creator 3D 将从属性的默认值或初始化式的求值结果推导其 cc 类型:

  • 若值的类型是 Javascript 原始类型 numberstringboolean, 则其 cc 类型分别为 Cocos Creator 3D 浮点数、Cocos Creator 3D 字符串、Cocos Creator 3D 布尔值。
  • 否则,若值是对象类型,则相当于使用对象的构造函数指定了 cc 类型;
  • 否则,属性的 cc 类型是未定义的。

一般地,仅需要在以下情况中需要显式地声明 cc 类型:

  • 当需要将属性显示为整数时;
  • 当属性的实际值可能是多个类型时。

关于 cc 类型如何影响 cc 属性以及对未定义 cc 类型的属性的处理,见:

为了方便,额外提供了以下装饰器以快速声明 cc 类型:

下列代码演示了不同 cc 类型 的 cc 属性的声明:

默认值

选项 default 指定了 cc 属性的默认值。

构造函数

通过 constructor 定义

判断实例

需要做类型判断时,可以用 TypeScript 原生的 instanceof

  1. class Sub extends Base {
  2. }
  3. let sub = new Sub();
  4. console.log(sub instanceof Sub); //true
  5. console.log(sub instanceof Base); //true
  6. let base = new Base();
  7. console.log(base instanceof Sub); // false

成员

在构造函数中定义的实例变量不能被序列化,也不能在 属性检查器 中查看。

  1. class Sprite{
  2. //声明变量
  3. url: string;
  4. id: number;
  5. constructor() {
  6. //赋值
  7. this.url = "";
  8. this.id = 0;
  9. }
  10. }

实例方法

实例方法请在原型对象中声明:

  1. class Sprite{
  2. text: string;
  3. constructor() {
  4. this.text = "this is sprite"
  5. }
  6. // 声明一个名叫 "print" 的实例方法
  7. print(){
  8. }
  9. }
  10. let obj = new Sprite();
  11. // 调用实例方法
  12. obj.print();

静态变量和静态方法

静态变量或静态方法可以用 statics 声明:

  1. class Sprite{
  2. static count=0;
  3. static getBounds(){
  4. }

静态成员会被子类继承,继承时会将父类的静态变量浅拷贝给子类,因此:

  1. class Object{
  2. static count= 11;
  3. static range: { w: 100, h: 100 }
  4. }
  5. class Sprite extends Object{
  6. }
  7. console.log(Sprite.count); // 结果是 11,因为 count 继承自 Object 类
  8. Sprite.range.w = 200;
  9. console.log(Object.range.w); // 结果是 200,因为 Sprite.range 和 Object.range 指向同一个对象

如果你不需要考虑继承,私有的静态成员也可以直接定义在类的外面:

  1. // 局部方法
  2. doLoad(sprite){
  3. // ...
  4. };
  5. // 局部变量
  6. let url = "foo.png";
  7. class Sprite{
  8. load() {
  9. this.url = url;
  10. doLoad(this);
  11. };
  12. };

父构造函数

请注意,不论子类是否有定义构造函数,子类实例化前父类的构造函数都会被自动调用。

  1. class Node {
  2. name: string;
  3. constructor(){
  4. this.name = "node";
  5. }
  6. }
  7. class Sprite extends Node{
  8. constructor() {
  9. super();
  10. // 子构造函数被调用前,父构造函数已经被调用过,所以 this.name 已经被初始化过了
  11. console.log(this.name); // "node"
  12. // 重新设置 this.name
  13. this.name = "sprite";
  14. }
  15. }
  16. let obj = new Sprite();
  17. console.log(obj.name); // "sprite"

所有成员方法都是虚方法,子类方法可以直接重写父类方法:

属性

属性是特殊的实例变量,能够显示在 属性检查器 中,也能被序列化。

属性和构造函数

属性不用在构造函数里定义,在构造函数被调用前,属性已经被赋为默认值了,可以在构造函数内访问到。如果属性的默认值无法在定义 CCClass 时提供,需要在运行时才能获得,你也可以在构造函数中重新给属性赋默认值。

  1. class Sprite {
  2. constructor() {
  3. this.num = 1;
  4. }
  5. @property({type:CCInteger})
  6. private num = 0;
  7. }

不过要注意的是,属性被反序列化的过程紧接着发生在构造函数执行之后,因此构造函数中只能获得和修改属性的默认值,还无法获得和修改之前保存(序列化)的值。

属性参数

default参数

default 用于声明属性的默认值,声明了默认值的属性会被 CCClass 实现为成员变量。默认值只有在第一次创建对象的时候才会用到,也就是说修改默认值时,并不会改变已添加到场景里的组件的当前值。

default 允许设置为以下几种值类型:

  1. 任意 number, string 或 boolean 类型的值
  2. nullundefined
  3. 继承自 ValueType 的子类,如 Vec3, ColorRect 的实例化对象:

    1. @property({type:Vec3})
    2. private pos = null;
  4. 空数组 [] 或空对象 {}

visible参数

如果要强制显示在 属性检查器,可以设置 visible 参数为 true:

  1. @property({visible:true})

如果要强制隐藏,可以设置 visible 参数为 false:

  1. @property({visible:false})

serializable参数

指定了 default 默认值的属性默认情况下都会被序列化,序列化后就会将编辑器中设置好的值保存到场景等资源文件中,并且在加载场景时自动还原之前设置好的值。如果不想序列化,可以设置serializable: false

  1. @property({serializable:false})
  2. private num = 0;

type参数

default 不能提供足够详细的类型信息时,为了能在 属性检查器 显示正确的输入控件,就要用 type 显式声明具体的类型:

  • 当默认值为 null 时,将 type 设置为指定类型的构造函数,这样 属性检查器 才知道应该显示一个 Node 控件。

    1. @property({type:Node})
    2. private enemy = null;
  • 当默认值为数值(number)类型时,将 type 设置为 cc.Integer,用来表示这是一个整数,这样属性在 属性检查器 里就不能输入小数点。

    1. @property({type:CCInteger})
    2. private num = 0;
  • 当默认值是一个枚举(Enum)时,由于枚举值本身其实也是一个数字(number),所以要将 type 设置为枚举类型,才能在 属性检查器 中显示为枚举下拉框。

override参数

所有属性都将被子类继承,如果子类要覆盖父类同名属性,需要显式设置 override 参数,否则会有重名警告:

  1. @property({type:CCString,tooltip:"my id",override:true})
  2. private _id = "";
  3. @property({displayName:"Name",override:true})
  4. private _name = null;
  5. private get name(){
  6. return this._name;
  7. }

更多参数内容请查阅 属性参数

在属性中设置了 get 或 set 以后,访问属性的时候,就能触发预定义的 get 或 set 方法。

get

在属性中设置 get 方法:

  1. @property({type:CCInteger})
  2. private _num = 0;
  3. private get num(){
  4. return this._num;
  5. }

get 方法可以返回任意类型的值。
这个属性同样能显示在 属性检查器 中,并且可以在包括构造函数内的所有代码里直接访问。

  1. class Sprite{
  2. _width: number;
  3. constructor() {
  4. this._width = 128;
  5. console.log(this.width); // 128
  6. }
  7. @property({type:CCInteger})
  8. private width = 0;
  9. private get width(){
  10. return this._width;
  11. }
  12. };

请注意:

  • 设定了 get 以后,这个属性就不能被序列化,也不能指定默认值,但仍然可附带除了 default, serializable 外的大部分参数。

    1. @property({type:CCInteger,tooltip: "The width of sprite"})
    2. private _width = 0;
    3. private get width(){
    4. return this._width;
    5. }
  • get 属性本身是只读的,但返回的对象并不是只读的。用户使用代码依然可以修改对象内部的属性,例如:

    1. @property
    2. _num=0;
    3. private get num(){
    4. return this._num;
    5. }
    6. start(){
    7. consolo.log(this.num);
    8. }

在属性中设置 set 方法:

  1. @property({type:CCInteger})
  2. private _width = 0;
  3. set(value){
  4. this._width = value
  5. }

set 方法接收一个传入参数,这个参数可以是任意类型。

set 一般和 get 一起使用:

  1. @property
  2. _width=0;
  3. private get width(){
  4. return this._width;
  5. }
  6. set(value){
  7. this._width = value;