🎯 Cocos Creator 生命周期详解

2026-07-22
20707 分钟
...

Cocos Creator 生命周期详解

一、前言

Cocos Creator 作为主流的游戏开发引擎,其组件化架构的核心就是生命周期回调函数。理解这些回调的触发时机、执行顺序和使用场景,是写出高质量游戏逻辑的基础。

本文基于 Cocos Creator 3.x,系统梳理从引擎启动到场景切换、从节点创建到销毁的完整生命周期。

二、组件生命周期回调总览

Cocos Creator 的生命周期回调按触发顺序排列如下:

回调函数触发时机说明
onLoad节点加载完成时初始化的起点,只触发一次
start第一次 update 之前用于业务逻辑初始化
update(dt)每帧调用游戏主循环,dt 为上一帧耗时
lateUpdate(dt)每帧在 update 之后调用处理 update 中产生的依赖
onDestroy节点被销毁时资源释放、事件注销
onDisable节点或组件被禁用时组件失活的清理
onEnable节点或组件被启用时组件激活的恢复

注意:constructor(构造函数)不是 Cocos 的生命周期回调,而是 TypeScript/JavaScript 类的构造器。虽然可以在其中写初始化代码,但此时组件尚未被引擎挂载,很多引擎 API 不可用。

三、各回调详解

3.1 onLoad

触发时机:当节点及其所有子节点加载完成后,引擎会按照节点树的顺序依次调用每个组件的 onLoad

import { _decorator, Component, Node } from 'cc';
const { ccclass, property } = _decorator;

@ccclass('Player')
export class Player extends Component {
    onLoad() {
        // 初始化引用、获取其他组件
        const health = this.node.getChildByName('Health');
        console.log('节点加载完成,可以安全访问子节点');
    }
}

关键特性

  • 每个组件只触发一次
  • 所有节点的 onLoad 在第一帧 update 之前全部执行完毕
  • onLoad 中可以安全地访问子节点和组件引用
  • 节点激活状态下,onLoad 在节点激活时触发;禁用的节点,其 onLoad 会延迟到节点激活时才触发

典型用途

  • 获取组件引用和子节点引用
  • 初始化变量
  • 注册事件监听

3.2 start

触发时机:在 onLoad 之后、第一帧 update 之前调用。

@ccclass('Enemy')
export class Enemy extends Component {
    start() {
        // 在这里开始寻路逻辑
        this.scheduleOnce(() => {
            this.findPath();
        }, 0.5);
    }
}

start 与 onLoad 的区别

对比项onLoadstart
调用顺序先于 start后于 onLoad
执行次数每个组件一次每个组件一次
节点禁用时节点激活后触发节点激活后触发
多组件依赖不保证同节点其他组件的 onLoad 已执行保证同节点所有组件的 onLoad 已执行

最佳实践:如果组件 A 需要访问同节点上组件 B 的初始化结果,把 A 的逻辑放在 start 中。

3.3 update(dt)

触发时机:游戏运行期间,每帧都会被调用。

@ccclass('Bullet')
export class Bullet extends Component {
    private speed: number = 500;

    update(dt: number) {
        const pos = this.node.position;
        this.node.setPosition(pos.x, pos.y + this.speed * dt, pos.z);
    }
}

注意事项

  • dt 参数是上一帧到当前帧的时间间隔(秒),不是固定值
  • 不要在 update 中做内存分配(创建对象、拼字符串等),会造成 GC 压力
  • 频繁访问属性(如 this.node.position)会触发组件脏标记更新,能缓存就缓存
  • 禁用的组件不会调用 update

3.4 lateUpdate(dt)

触发时机:在所有组件的 update 之后调用。

@ccclass('CameraFollow')
export class CameraFollow extends Component {
    @property(Node)
    target: Node = null;

    lateUpdate(dt: number) {
        // 跟随玩家移动
        if (this.target) {
            this.node.setPosition(
                this.target.position.x,
                this.target.position.y,
                this.node.position.z
            );
        }
    }
}

典型用途

  • 摄像机跟随(确保玩家位置更新后再移动摄像机)
  • 粒子系统与角色动画的同步
  • 在所有逻辑更新完成后做统一的后处理

3.5 onEnable / onDisable

@ccclass('UIPanel')
export class UIPanel extends Component {
    onEnable() {
        // 面板显示时注册事件
        this.node.on(Node.EventType.TOUCH_START, this.onTouch, this);
    }

    onDisable() {
        // 面板隐藏时注销事件,防止内存泄漏
        this.node.off(Node.EventType.TOUCH_START, this.onTouch, this);
    }
}

触发场景

  • node.active = true/false
  • component.enabled = true/false
  • 节点首次被添加到场景树且处于激活状态时(onEnable
  • 节点被移除前(onDisable

重要onDisableonDestroy 之前调用。这意味着节点销毁时,先执行所有组件的 onDisable,再执行 onDestroy

3.6 onDestroy

触发时机:节点从场景树中移除并被销毁时。

@ccclass('Tower')
export class Tower extends Component {
    onDestroy() {
        // 清理所有定时器
        this.unscheduleAllCallbacks();
        // 清理事件监听
        this.node.off(Node.EventType.TOUCH_START, this.onTouch, this);
        console.log('塔被摧毁');
    }
}

注意事项

  • onDestroy 中不要再访问其他可能已被销毁的节点
  • 不要在 onDestroy 中重新创建节点或启动新的动画
  • 如果在 onDestroy 中通过 director.loadScene 切换场景,需要注意时序

四、场景切换的生命周期

当你调用 director.loadScene() 切换场景时,流程如下:

步骤执行内容
1当前场景所有节点的 onDisable
2当前场景所有节点的 onDestroy
3加载新场景资源
4新场景节点的 onLoad
5新场景节点的 start
6新场景第一帧 update

实际案例

// 玩家死亡后切换到结算场景
@ccclass('GameManager')
export class GameManager extends Component {
    onPlayerDead() {
        // 先执行结算逻辑
        this.showResult();
        // 1 秒后切换场景
        this.scheduleOnce(() => {
            director.loadScene('ResultScene');
        }, 1);
    }
}

五、节点创建与销毁的生命周期

动态创建节点

const node = new Node('NewEnemy');
this.node.addChild(node);
// 此时引擎会:
// 1. 调用 node 上所有组件的 onLoad
// 2. 如果 node 处于激活状态,下一帧调用 start

动态销毁节点

node.destroy();
// 此时引擎会:
// 1. 调用 node 上所有组件的 onDisable
// 2. 调用 node 上所有组件的 onDestroy
// 3. 从场景树中移除

从场景树移除但不销毁

node.removeFromParent();
// 只是从父节点移除,不触发 onDestroy
// 可以之后重新 addChild 到其他节点

六、常用生命周期模式

模式 1:对象池

@ccclass('BulletPool')
export class BulletPool extends Component {
    private pool: Node[] = [];

    getBullet(): Node {
        let bullet: Node;
        if (this.pool.length > 0) {
            bullet = this.pool.pop();
            bullet.active = true;  // 触发 onEnable
        } else {
            bullet = instantiate(this.bulletPrefab);
            this.node.addChild(bullet);  // 触发 onLoad
        }
        return bullet;
    }

    putBullet(bullet: Node) {
        bullet.active = false;  // 触发 onDisable
        // 不调用 destroy(),留着复用
    }
}

模式 2:事件驱动的状态机

@ccclass('StateComponent')
export class StateComponent extends Component {
    private currentState: string = 'idle';

    changeState(newState: string) {
        if (this.currentState === newState) return;
        this.exitState(this.currentState);
        this.currentState = newState;
        this.enterState(newState);
    }

    onEnable() {
        this.enterState(this.currentState);
    }

    onDisable() {
        this.exitState(this.currentState);
    }
}

模式 3:延迟初始化

@ccclass('LazyInit')
export class LazyInit extends Component {
    private initialized = false;

    update(dt: number) {
        if (!this.initialized) {
            // 确保所有依赖都已就绪
            this.doInit();
            this.initialized = true;
        }
        // 正常逻辑
    }
}

七、常见陷阱

陷阱 1:onLoad 中访问未加载的资源

// 错误示例
onLoad() {
    // texture 可能还未加载完成
    this.getComponent(Sprite).spriteFrame = this.texture;
}

// 正确示例:使用资源加载 API
start() {
    resources.load('textures/hero', SpriteFrame, (err, asset) => {
        this.getComponent(Sprite).spriteFrame = asset;
    });
}

陷阱 2:update 中频繁创建对象

// 错误示例
update(dt) {
    const pos = `${this.node.position.x},${this.node.position.y}`;
    this.label.string = pos;
}

// 正确示例
private tempVec = new Vec3();
update(dt) {
    Vec3.copy(this.tempVec, this.node.position);
    this.label.string = `${this.tempVec.x.toFixed(1)},${this.tempVec.y.toFixed(1)}`;
}

陷阱 3:销毁后访问节点

// 错误示例
onDestroy() {
    const parent = this.node.parent;
    parent.removeChild(this.node);  // 节点可能已经不在场景树中
}

// 正确示例:不需要手动移除,destroy() 已经处理
onDestroy() {
    // 只做清理逻辑
    this.unscheduleAllCallbacks();
}

陷阱 4:onDisable 中触发新的生命周期

// 危险操作
onDisable() {
    this.node.active = true;  // 可能导致无限循环
}

八、生命周期执行顺序图

场景加载

  ├─ 所有节点 onLoad从根到叶

  ├─ 所有节点 start从根到叶

  ├─ [游戏循环开始]
  │   │
  │   ├─ update(dt)        ← 每帧执行
  │   ├─ lateUpdate(dt)    ← 每帧执行
  │   │
  │   └─ [下一帧...]

  └─ 场景卸载
      ├─ 所有节点 onDisable
      └─ 所有节点 onDestroy

九、总结

阶段关键回调适合做什么
初始化onLoad获取引用、注册事件
启动start业务逻辑初始化、跨组件依赖
运行update / lateUpdate移动、碰撞检测、摄像机跟随
失活onDisable注销事件、停止定时器
销毁onDestroy释放资源、最终清理

掌握生命周期是 Cocos Creator 开发的基础。建议在实际项目中多观察日志输出,加深对执行顺序的理解。

如果您觉得这篇文章有帮助,请点个赞吧~

分享文章

相关文章

更多文章 →
cocos2026-07-22
🚀 Cocos Creator 新手入门指南
一、Cocos Creator 是什么 Cocos Creator 是一款专注于 2D 和 3D 游戏开发的引擎,由 Cocos 团队开发。它的核心理念是 组件化开发 ——把游戏中的每个功能拆成独立的组件,像搭积木一样组合起来。 主要特点 : 完全免费,支持发布到 Web、iOS、Android、桌面等多平台 使用 TypeScript 编写脚本,对前端开发者非常友好 编辑器可视化操作,所见即所得 内置资源管理、动画系统、UI 系统、物...
学习
cocos2025-10-11
🚀 cocos进阶语法
1\. 组件设计与脚本复用 在 Cocos Creator 中, 一切都是组件 。 你可以把通用逻辑封装成独立组件,实现模块化开发。 ✅ 建议 : 把“功能性逻辑”(移动、旋转、漂浮、点击反应等)做成通用组件,避免在业务逻辑脚本里重复写。 2\. 单例与全局管理器 大型项目通常需要全局控制器,比如音效、玩家数据、网络。 使用: ✅ 建议 : 使用“单例模式”集中管理音效、事件、UI、对象池等,减少节点层级耦合。 3\. 动画系统与状态机...
学习
cocos2025-09-23
📘 Cocos Creator 语法入门文档
📘 Cocos Creator 语法入门文档 1. 基础概念 Cocos Creator 使用 TypeScript/JavaScript 作为主要开发语言,游戏逻辑通常通过脚本来驱动。主要模块: 节点 (Node) :场景中的基本元素,可以理解为游戏对象。 组件 (Component) :附加到节点上的脚本/功能,比如渲染、物理、脚本逻辑。 场景 (Scene) :游戏运行的基本单位,包含多个节点。 资源 (Assets) :图片、...
学习
AI2026-09-01
Deep Agents 01:何为 Agent Harness,以及如何开始
1、本篇任务:完成一份多步骤、带证据的技术调研 普通客服 Agent 的问题短、工具少、输出即时。技术调研或编码任务会持续很久,产生计划、搜索结果、文件和中间结论。Deep Agents 在 LangChain/LangGraph 之上预装规划、虚拟文件系统、上下文压缩和子 Agent,适合这类开放任务。 本课让 Agent 比较两种向量数据库,并交付一份可验证报告。 2、什么时候需要 Deep Agent 满足以下两项以上再考虑:任务...
学习
AI2026-09-01
Deep Agents 02:子 Agent、虚拟文件系统与长期记忆
1、本篇任务:让主管只看结论,让子 Agent 处理细节 技术调研会产生几十次搜索和大量文件。如果全部进入主管上下文,真正的目标会被噪音淹没。本课用两个子 Agent: 收集证据, 检查结论;主管负责计划与最终合成。 2、什么时候委派,什么时候直接调用工具 适合委派:子任务有多步;需要专门提示或工具;会产生大量中间结果;只需返回有限结论。不适合:一步查询;主管需要全部中间上下文;协调成本超过任务本身。 3、配置专门子 Agent Pyt...
学习
AI2026-09-01
Deep Agents 03:生产化、Sandbox、权限与上线验收
1、本篇任务:让 Deep Agent 在隔离环境中分析代码 只读研究 Agent 风险有限;编码 Agent 需要读写文件、安装依赖和执行测试。本课不讲如何让模型写更漂亮的代码,只讲执行环境、权限、恢复和上线验收。 2、先做威胁模型 资产包括源代码、用户文件、云凭证、生产网络和发布权限;攻击入口包括用户消息、仓库内容、网页、依赖包、MCP 返回和命令输出。 Prompt injection 不是靠一句 system prompt 解决...
学习

评论

请登录后发表评论

去登录
加载评论中...

目录