组件和组件执行顺序

所有继承自 Component 的类都称为组件类,其对象称为组件,实现了 Cocos Creator 3.0 EC 系统中的组件概念。

组件类必须是 cc 类

  1. import { Component } from "cc";
  2. @ccclass("MyComponent")
  3. class MyComponent extends Component {
  4. }

组件的创建和销毁

组件的生命周期完全由节点操控。与普通类对象不同,组件不能由构造函数创建:

  1. const component = new MyComponent(); // 错误:组件无法由构造函数创建

相反地,组件必须由节点来创建,通过如下方法将组件添加到节点上:

  1. const myComponent = node.addComponent(MyComponent);

当组件不再被需要的时候,可以调用 node.removeComponent(myComponent) 移除指定的组件并将其销毁。

  1. import { Component } from "cc";
  2. @ccclass("MyComponent")
  3. class MyComponent extends Component {
  4. constructor () {
  5. console.log(this.node.name); // 错误:组件并未附加到节点上
  6. }
  7. public printNodeName () {
  8. console.log(this.node.name);
  9. }
  10. }
  1. const myComponent = node.addComponent(MyComponent);
  2. myComponent.printNodeName(); // 正确
  3. node.removeComponent(myComponent);
  4. myComponent.printNodeName(); // 错误:组件已被该节点移除

组件执行顺序

使用统一的控制脚本来初始化其他脚本

项目中一般会有一个像 Game.ts 这样的脚本作为总的控制脚本,而其余脚本,像 Configuration.tsGameData.tsMenu.ts 三个组件,如果要在 Game.ts 里初始化,那么它们的初始化过程是这样的:

  1. // Game.ts
  2. import { _decorator, Component, Node } from "cc";
  3. const { ccclass, property } = _decorator;
  4. import { Configuration } from './Configuration';
  5. import { GameData } from './GameData';
  6. import { Menu }from './Menu';
  7. @ccclass("Game")
  8. export class Game extends Component {
  9. private configuration = Configuration;
  10. private gameData = GameData;
  11. private menu = Menu;
  12. onLoad () {
  13. this.configuration.init();
  14. this.gameData.init();
  15. this.menu.init();
  16. }
  17. }

其中在 Configuration.tsGameData.tsMenu.ts 中需要实现 init 方法,并将初始化逻辑放进去。这样就可以保证 Configuration、GameData 和 Menu 的初始化顺序。

在 update 中用自定义方法控制更新顺序

同理如果要保证以上三个脚本的每帧更新顺序,也可以将分散在每个脚本里的 update 替换成自己定义的方法:

  1. //Configuration.ts
  2. static updateConfig (deltaTime: number) {
  3. }

然后在 Game.ts 脚本的 update 里调用这些方法:

  1. // Game.ts
  2. update (deltaTime: number) {
  3. this.configuration.updateConfig(deltaTime);
  4. this.gameData.updateData(deltaTime);
  5. this.menu.updateMenu(deltaTime);
  6. }

控制同一个节点上的组件执行顺序

在同一个节点上的组件执行顺序,可以通过组件在 属性检查器 里的排列顺序来控制,排列在上的组件会先于排列在下的组件执行。可以通过组件右上角的齿轮按钮里的 Move UpMove Down 菜单来调整组件的排列顺序,即执行顺序。

假如有两个组件 CompA 和 CompB,它们的内容分别是:

  1. // CompA.ts
  2. import { _decorator, Component, Node } from "cc";
  3. const { ccclass, property } = _decorator;
  4. @ccclass("CompA")
  5. export class CompA extends Component {
  6. onLoad () {
  7. console.log('CompA onLoad!');
  8. }
  9. start () {
  10. console.log('CompA start!');
  11. }
  12. update (deltaTime: number) {
  13. console.log('CompA update!');
  14. }
  15. }
  16. // CompB.ts
  17. import { _decorator, Component, Node } from "cc";
  18. const { ccclass, property } = _decorator;
  19. @ccclass("CompB")
  20. export class CompB extends Component {
  21. onLoad () {
  22. console.log('CompB onLoad!');
  23. }
  24. start () {
  25. console.log('CompB start!');
  26. }
  27. update (deltaTime: number) {
  28. console.log('CompB update!');
  29. }
  30. }

组件顺序 CompA 在 CompB 上面时,输出:

  1. CompA onLoad!
  2. CompB onLoad!
  3. CompA start!
  4. CompB start!
  5. CompA update!
  6. CompB update!

属性检查器 里通过 CompA 组件右上角设置菜单里的 Move Down 将 CompA 移到 CompB 下面后,输出:

  1. CompB onLoad!
  2. CompA onLoad!
  3. CompB start!
  4. CompA start!
  5. CompB update!
  6. CompA update!

设置组件执行优先级

如果以上方法还是不能提供所需的控制粒度,还可以直接设置组件的 executionOrder。executionOrder 会影响组件生命周期回调执行的优先级。executionOrder 越小,该组件相对其它组件就会越先执行。executionOrder 默认为 0,因此设置为负数的话,就会在其它默认的组件之前执行。设置方法如下:

  1. //Configuration.ts
  2. import { _decorator, Component, Node } from "cc";
  3. const { ccclass, executionOrder } = _decorator;
  4. @ccclass("Configuration")
  5. @executionOrder(-1)
  6. export class Configuration extends Component {
  7. onLoad () {
  8. console.log('Configuration onLoad!');
  9. }
  10. }
  1. // Menu.ts
  2. import { _decorator, Component, Node } from "cc";
  3. const { ccclass, executionOrder } = _decorator;
  4. @ccclass("Menu")
  5. @executionOrder(1)
  6. export class Menu extends Component {
  7. onLoad () {
  8. console.log('Menu onLoad!');
  9. }
  10. }

通过如上方法设置,Configuration.ts 的 onLoad 会在 Menu.ts 的 onLoad 方法之前执行。

注意:executionOrder 只对 onLoadonEnablestartupdatelateUpdate 有效,对 onDisableonDestroy 无效。