CCClass

When the decorator ccclass is applied to a class, the class is called ccclass. The ccclass injects additional information to control Cocos Creator 3.0‘s serialization of this kind of object along with the editor’s display for these types of objects.

ccclass

Various characteristics of the ccclass are specified by the ccclass option parameter of ccclass(name).

ccclass name

The option name specifies the name of the ccclass. The ccclass name should be unique.

When you need the corresponding ccclass, you can find it by its ccclass name, for example:

  • Serialization. If the object is a cc object, the ccclass name of the object will be recorded during serialization. During deserialization, the corresponding ccclass will be found for serialization based on this name.

  • When the ccclass is a component class, Node can find the component by its ccclass name.

ccattributes

When the decorator property is applied to a property or accessor of the ccclass, this property is called a ccproperty.

Similar to the ccclass, the ccattribute injects additional information to control the serialization of the attribute in Cocos Creator 3.0 and the display of the attribute in the editor.

Property

Various characteristics of the ccattribute are specified by the ccattribute option parameter of property().

cctype

The option type specifies the cctype of the attribute. The type can be specified by the following parameters:

  • Constructor

    The type specified by the constructor is directly used as the cctype of the attribute.

    Note: when Javascript built-in constructors Number, String, Boolean A warning will be given when used as a cctype, and they are regarded as cctype‘s CCFloat, CCString, and CCBoolean respectively.

  • Cocos Creator 3.0 built-in attribute type identification.

    CCInteger, CCFloat, CCBoolean, and CCString are built-in attribute type identifiers.

    • CCInteger declares the type as integer.
    • CCFloat declares the type as floating point number.
    • CCString declares the type as string.
    • CCBoolean declares the type as Boolean.
  • Array

    When using the constructor, built-in property type identification or array as the array element, the properties are specified as Cocos Creator 3.0 array. For example, [CCInteger] declares the type as a array whose elements are integers.

If the attribute does not specify the cctype, Cocos Creator 3.0 will derive its cctype from the default value of the attribute or the evaluation result of the initialization formula:

  • If the value type is Javascript primitive type number, string, boolean, the cctypes are Creator floating point, string, and boolean values, respectively.
  • Otherwise, if the value is an object type, it is equivalent to using the object’s constructor to specify the cctype.
  • Otherwise, the cctype of the attribute is undefined.

Generally, you only need to explicitly declare the cctype in the following situations:

  • When the attribute needs to be displayed as an integer.
  • When the actual value of the attribute may be of multiple types.

For how the cctype affects the cc attribute and the treatment of attributes that do not define the cctype, see:

For convenience, the following decorators are additionally provided to quickly declare the cctype:

TypeEquivalent to
@type(t)@property(t)
@integer@property(CCInteger)
@float@property(CCFloat)
@string@property(CCString)
@boolean@property(CCBoolean)

The following code demonstrates the declaration of ccattributes of different cctypes:

  1. import { _decorator, CCInteger, Node } from 'cc';
  2. const { ccclass, property, integer, float, boolean, string, type } = _decorator;
  3. @ccclass
  4. class MyClass {
  5. @integer // Declare that the cc type of the attribute _id is a Cocos integer
  6. private _id = 0;
  7. @type(Node) // Declare that the cc type of the attribute _targetNode is Node
  8. private _targetNode: Node | null = null;
  9. @type([Node]) // declare the cc type of the attribute _children as a Node array
  10. private _children: Node[] = [];
  11. @property
  12. private _count = 0; // the cc type is not declared, and it is inferred from the evaluation result of the initializer as a Cocos floating point number
  13. @type(String) // Warning: Constructor should not be used String
  14. // equivalent to CCString
  15. private _name: string = '';
  16. @property
  17. private _children2 = []; // The cc type is not declared, inferred from the evaluation result of the initializer: the element is an undefined Cocos array
  18. }

Defaults

The option default specifies the default value of the cc attribute.

Constructor

Defined By Constructor

The constructor of CCClass is defined by constructor. To ensure that deserialization can always run correctly, constructor is not allowed to define constructor parameters.

Note: if developers really need to use construction parameters, they can get them through arguments, but remember that if this class will be serialized, you must ensure that the object can still be new when the construction parameters are all default.

Judging The Type

Judgment Example

When making type judgments, use TypeScript native 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

Members

Instance Variables

The instance variables defined in the constructor cannot be serialized, nor can they be viewed in the Inspector panel.

  1. class Sprite {
  2. // Declare variables
  3. url: string;
  4. id: number;
  5. constructor() {
  6. // assignment
  7. this.url = "";
  8. this.id = 0;
  9. }
  10. }

Note: if it is a private variable, it is recommended to add an underscore _ in front of the variable name to distinguish it.

Example Method

Please declare the instance method in the prototype object:

  1. class Sprite {
  2. text: string;
  3. constructor() {
  4. this.text = "this is sprite"
  5. }
  6. // Declare an instance method named "print"
  7. print() {
  8. console.log(this.text);
  9. }
  10. }
  11. let obj = new Sprite();
  12. // call instance method
  13. obj.print();

Static Variables and Static Methods

Static variables or static methods can be declared with static:

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

Static members will be inherited by subclasses. When inheriting, the static variables of the parent class will be shallowly copied to the subclass. Therefore:

  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); // The result is 11 because count inherits from the Object class
  8. Sprite.range.w = 200;
  9. console.log(Object.range.w); // The result is 200, because Sprite.range and Object.range point to the same object

If you don’t need to consider inheritance, private static members can also be defined directly outside the class:

  1. // local method
  2. doLoad(sprite) {
  3. // ...
  4. };
  5. // local variables
  6. let url = "foo.png";
  7. class Sprite {
  8. load() {
  9. this.url = url;
  10. doLoad(this);
  11. };
  12. };

Inheritance

Parent Constructor

Please note that regardless of whether the subclass has a constructor defined, the constructor of the parent class will be automatically called before the subclass is instantiated.

  1. class Node {
  2. name: string;
  3. constructor() {
  4. this.name = "node";
  5. }
  6. }
  7. class Sprite extends Node {
  8. constructor() {
  9. super();
  10. // Before the child constructor is called, the parent constructor has been called, so this.name has been initialized
  11. console.log(this.name); // "node"
  12. // Reset "this.name"
  13. this.name = "sprite";
  14. }
  15. }
  16. let obj = new Sprite();
  17. console.log(obj.name); // "sprite"

Rewrite

All member methods are virtual methods, and child methods can directly override parent methods:

  1. class Shape {
  2. getName() {
  3. return "shape";
  4. }
  5. };
  6. class Rect extends Shape {
  7. getName () {
  8. return "rect";
  9. }
  10. };
  11. let obj = new Rect();
  12. console.log(obj.getName()); // "rect"

Attributes

Attributes are special instance variables that can be displayed in the Inspector panel and can also be serialized.

Properties and Constructors

The attribute not required is defined in the constructor. Before the constructor is called, the attribute has been assigned a default value and can be accessed in the constructor. If the default value of the attribute cannot be provided when defining the ccclass and needs to be obtained at runtime, you can also re-assign the default value to the attribute in the constructor.

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

However, it should be noted that the process of property deserialization occurs immediately after the execution of the constructor, so the default value of the property can only be obtained and modified in the constructor, and it cannot be obtained and saved before the modification (serialization ) value.

Attribute Parameters

Default Parameter

default is used to declare the default value of the attribute. The attribute with the default value will be implemented as a member variable by ccclass. The default value is only used when the object is created for the first time, which means that when the default value is modified, the current value of the component that has been added to the scene will not be changed.

Note: after you add a component to the editor, go back to the script to modify a default value, there is no change in the Inspector panel. Because the current value of the property has been serialized into the scene, it is no longer the default value used when it was first created. If you want to force all properties to be reset to default values, you can select Reset in the component menu of the Inspector panel.

default can be set to the following value types:

  1. Any number, string or boolean type value
  2. null or undefined
  3. Subclasses inherited from ValueType, such as instantiated objects of Vec3, Color or Rect:

    1. @property({ type: Vec3 })
    2. private pos = null;
  4. Empty array [] or empty object {}

visible

By default, whether it is displayed in the Inspector panel depends on whether the attribute name starts with an underscore _. If it starts with an underscore, it will not be displayed in the Inspector panel by default, otherwise it will be displayed by default.

If you want to force it to be displayed in the Inspector panel, you can set the visible parameter to true:

  1. @property({ visible: true })
  2. private _num = 0;

If you want to force hiding, you can set the visible parameter to false:

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

serializable

Attributes with a default value of default will be serialized by default. After serialization, the values set in the editor will be saved to resource files such as scenes, and the previously set values will be automatically restored when the scene is loaded. If you don’t want to serialize, you can set serializable: false.

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

type

When default cannot provide enough detailed type information, in order to display the correct input control in the Inspector panel, you must use type to explicitly declare the specific type:

  • When the default value is null, set type to the constructor of the specified type, so that the Inspector panel knows that a Node control should be displayed.

    1. @property({ type: Node })
    2. private enemy = null;
  • When the default value is a number type, set the type to cc.Integer to indicate that this is an integer, so that the attribute cannot be entered in the decimal point in the Inspector panel.

    1. @property({ type: CCInteger })
    2. private num = 0;
  • When the default value is an enumeration (Enum), since the enumeration value itself is actually a number, the type must be set to the enumeration type to be displayed in the Inspector panel enumerate the drop-down box.

    1. enum A {
    2. c,
    3. d
    4. }
    5. Enum(A);
    6. @ccclass("test")
    7. export class test extends Component {
    8. @property({ type: A })
    9. accx:A=A.c;
    10. }

override

All properties will be inherited by the subclass. If the subclass wants to override the property with the same name of the parent class, you need to explicitly set the override parameter, otherwise there will be a duplicate name warning:

  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. }

group

If there are many properties or mixed properties defined in the script, the properties can be grouped and sorted by group for easy management. It also supports sorting properties within a group.

  • @property({ group: { name } })

  • @property({ group: { id, name, displayOrder, style } })

PropertyDescription
idGroup ID, string type, is a unique identifier for the property group, and defaults to default.
nameThe name to classify the properties in the group, string type.
displayOrderSort the groups, number type. The smaller the number, the higher the sorting. The default is Infinity, which means the group is sorted last.
If there are multiple groups without displayOrder set, they will be sorted in the order declared in the script.
styleGrouping styles, currently only tab styles are supported.

Example script is as follows:

  1. import { _decorator, Component, Label, Sprite } from 'cc';
  2. const { ccclass, property } = _decorator;
  3. @ccclass('SayHello')
  4. export class SayHello extends Component {
  5. // Group 1
  6. // The property category named "bar" within the group, which contains a Label property named "label".
  7. @property({ group: { name: 'bar' }, type: Label })
  8. label: Label = null!;
  9. // The property category named "foo" within the group, which contains a Sprite property named "sprite".
  10. @property({ group: { name: 'foo' }, type: Sprite })
  11. sprite: Sprite = null!;
  12. // Group 2
  13. // The property category named "bar2" within the group, which contains a Label property named "label2" and a Sprite property named "sprite2".
  14. @property({ group: { name: 'bar2', id: '2', displayOrder: 1 }, type: Label })
  15. label2: Label = null!;
  16. @property({ group: { name: 'bar2', id: '2' }, type: Sprite })
  17. sprite2: Sprite = null!;
  18. }

Mounting the script to the node displays the following image in the Inspector panel:

decorator-group

Because group 1 does not specify displayOrder and group 2 specifies displayOrder as 1, group 2 will be ranked ahead of group 1.

Sorting the properties within a group can also be done via displayOrder. Taking group 2 as an example, it is currently sorted in the order defined in the script, with label2 in front of sprite2. Let’s adjust it to:

  1. // Group 2
  2. @property({ group: { name: 'bar2', id: '2', displayOrder: 1 }, displayOrder: 2, type: Label })
  3. label2: Label = null!;
  4. @property({ group: { name: 'bar2', id: '2' }, displayOrder: 1, type: Sprite })
  5. sprite2: Sprite = null!;

Back to the editor, the sprite2 is now in front of label2 in the Inspector panel:

decorator-group

For additional information about the properties, please refer to the Properties documentation.

get/set methods

After the get or set is set in the property, when the property is accessed, the predefined get or set method can be triggered.

get

Set the get method in the properties:

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

The get method can return any type of value.

This property can also be displayed in the Inspector panel and can be directly accessed in all codes including the constructor.

  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. };

As get accessor is used, this property cannot be serialized, nor can it be assigned a default value, but most parameters except default and serializable can still be attached.

  1. @property({ type: CCInteger, tooltip: "The width of sprite" })
  2. private _width = 0;
  3. private get width() {
  4. return this._width;
  5. }

The get accessor is read-only, but the returned object is not read-only. Users can still modify the internal properties of the object using code, for example:

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

set

Set the set method in the properties:

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

The set method receives an incoming parameter, which can be of any type.

set is generally used with get:

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

Notes:

  1. If it is not defined together with get, the set itself cannot be accompanied by any parameters.
  2. Like get, after set is set, this property cannot be serialized, nor can it be assigned a default value.