Contents

Cocos Creator

参考资料

核心概述

Cocos Creator 是一款轻量级、跨平台的 2D/3D 游戏开发引擎,其核心设计理念是 数据驱动 + 组件化 + 场景化
引擎全面拥抱 TypeScript 作为主要脚本语言,通过静态类型检查和丰富的语法特性,帮助开发者编写更健壮、可维护的代码

可以自定义脚本编辑器、预览浏览器

节点与组件系统

节点(Node) 是 Cocos Creator 中的基本单位,可以是角色、道具、背景等各种游戏元素。节点通过父子关系构建复杂的场景结构,子节点的位置、旋转等属性是相对于父节点的。 组件(Component) 是附加在节点上的模块化代码片段,用于赋予节点特定的功能和行为。一个节点可以包含多个组件,组件之间可以相互配合。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
flowchart LR
    A[场景 Scene] --> B[根节点 Canvas]
    B --> C[节点 Node 1]
    B --> D[节点 Node 2]
    C --> E[组件 Component A]
    C --> F[组件 Component B]
    D --> G[组件 Component C]

    style A fill:#e3f2fd
    style B fill:#bbdefb
    style C fill:#90caf9
    style D fill:#90caf9
    style E fill:#64b5f6
    style F fill:#64b5f6
    style G fill:#64b5f6

生命周期回调详解

组件脚本继承自Component,引擎提供了完整的生命周期回调函数:

  • onLoad

    会在脚本组件的 初始化阶段 被调用
    总会在调用 start 方法前被执行,可以用于设置脚本的初始化顺序,或者做一些初始化相关的操作

  • onEnable

    当组件的 enabled 属性从 false 变为 true
    或者所在节点的 active 属性从 false 变为 true 时
    都会激活 onEnable 回调函数
    如果节点第一次被创建且 enabled 属性为 true,则调用顺序为:onLoad–onEnable–start

  • start

    通常用于初始化一些 中间状态的数据
    这些数据可能会在 update 时发生改变,并且被频繁地进行 enable 和 disable 操作

  • update

    会在游戏 每一帧渲染之前 被触发
    游戏开发的一个关键点是在每一帧渲染前更新物体的行为、状态和方位
    这些更新操作通常都被放在 update 回调函数中

  • lateUpdate

    会在游戏 每一帧渲染之后 被触发
    用于在动效(如动画、粒子、物理等)更新之后进行 额外的操作
    或者希望在执行完成所有组件的 update 之后进行其他操作

  • onDisable

    当组件的 enabled 属性从 true 变为 false 时
    或者所在节点的 active 属性从 true 变为 false 时
    会激活 onDisable 回调函数

  • onDestroy

    当组件或者所在节点调用了 destroy 函数时
    回调函数 onDestroy 也会被调用
    并在当前帧结束时统一 回收组件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import { _decorator, Component } from "cc";
const { ccclass, property } = _decorator;
@ccclass("GameController")
export class GameController extends Component {
  // 1. onLoad: 组件初始化阶段
  onLoad() {
    console.log("组件加载完成");
    // 初始化游戏设置、加载资源等
  }

  // 2. onEnable: 组件启用时
  onEnable() {
    console.log("组件已启用");
    // 注册事件监听器等
  }

  // 3. start: 首次update前
  start() {
    console.log("游戏开始");
    // 初始化游戏状态
  }

  // 4. update: 每帧更新
  update(deltaTime: number) {
    // 更新游戏逻辑、状态、方位
    // deltaTime: 与上一帧的时间间隔(秒)
  }

  // 5. lateUpdate: 每帧更新后
  lateUpdate() {
    // 处理动画、物理等更新后的操作
  }

  // 6. onDisable: 组件禁用时
  onDisable() {
    console.log("组件已禁用");
    // 注销事件监听器等
  }

  // 7. onDestroy: 组件销毁时
  onDestroy() {
    console.log("组件即将销毁");
    // 清理资源、释放引用等
  }
}

执行顺序

  1. 节点创建并激活时:onLoadonEnablestartupdatelateUpdate
  2. 组件禁用时:onDisable
  3. 节点销毁时:onDestroy

常用 API 与操作

节点操作

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
// 创建节点
let newNode = new cc.Node("NewNode");
// 或者实例化预制体
let prefabNode = cc.instantiate(prefab);
// 添加子节点
this.node.addChild(newNode);
// 设置父节点
newNode.parent = this.node;
// 获取节点
let targetNode = cc.find("Canvas/TargetNode");
// 或者通过路径查找
let child = this.node.getChildByName("ChildName");
// 节点属性操作
newNode.setPosition(cc.v2(100, 100)); // 设置位置
newNode.setRotation(45); // 设置旋转角度
newNode.setScale(2); // 设置缩放比例
// 节点显隐控制
newNode.active = true; // 显示
newNode.active = false; // 隐藏
// 销毁节点
this.node.destroy();

场景与资源管理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 场景切换
cc.director.loadScene("GameScene");
// 资源加载
// 加载单个资源
cc.resources.load("textures/player", cc.SpriteFrame, (err, spriteFrame) => {
  if (err) {
    console.error(err);
    return;
  }
  // 使用资源
});
// 加载图集资源
cc.resources.load("atlas/game-atlas", cc.SpriteAtlas, (err, atlas) => {
  if (err) {
    console.error(err);
    return;
  }
  const frame = atlas.getSpriteFrame("enemy-1");
});
// 资源释放
// 当不再使用资源时,应该释放以避免内存泄漏
this.spriteFrame.decRef();

UI 组件与交互

Cocos Creator 提供了丰富的 UI 组件,用于构建游戏界面:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// 按钮交互
const { property, ccclass } = cc._decorator;
import { Button, Node } from "cc";
@ccclass("UIController")
export class UIController extends Component {
  @property(Button)
  private startButton: Button = null;

  @property(Node)
  private panelNode: Node = null;

  onLoad() {
    // 添加按钮点击事件
    this.startButton.node.on(Button.EventType.CLICK, this.onStartGame, this);

    // 添加触摸事件
    this.panelNode.on(Node.EventType.TOUCH_START, this.onTouchStart, this);
  }

  onStartGame() {
    console.log("游戏开始!");
    // 切换场景、开始游戏逻辑等
  }

  onTouchStart(event: cc.Event.EventTouch) {
    const touchPos = event.getLocation();
    console.log(`触摸位置: (${touchPos.x}, ${touchPos.y})`);
  }

  onDestroy() {
    // 记得注销事件监听
    this.startButton.node.off(Button.EventType.CLICK, this.onStartGame, this);
    this.panelNode.off(Node.EventType.TOUCH_START, this.onTouchStart, this);
  }
}

实战技巧与最佳实践

建议的项目结构

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
assets/
├── scenes/          # 场景文件
├── scripts/         # TypeScript脚本
│   ├── controllers/ # 游戏控制器
│   ├── components/  # 可复用组件
│   ├── data/        # 数据模型
│   └── utils/       # 工具函数
├── resources/       # 需要动态加载的资源
├── textures/        # 图片资源
├── audio/           # 音频资源
└── prefabs/         # 预制体

TypeScript 工程化实践

  1. 使用严格模式:在tsconfig.json中启用"strict": true,有助于捕获潜在错误
  2. 充分利用类型推断:减少冗余的类型注解,让代码更简洁
  3. 接口优先:使用接口定义数据结构,增强类型安全性
  4. 模块化设计:避免全局污染,使用命名空间和模块系统

性能优化建议

高级优化技巧

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// 1. 对象池模式(避免频繁创建销毁)
class GameObjectPool {
    private pool: cc.Node[] = [];
    private prefab: cc.Prefab;

    constructor(prefab: cc.Prefab) {
        this.prefab = prefab;
    }

    public get(): cc.Node {
        let node: cc.Node;
        if (this.pool.length > 0) {
            node = this.pool.pop()!;
        } else {
            node = cc.instantiate(this.prefab);
        }
        node.active = true;
        return node;
    }

    public put(node: cc.Node): void {
        node.active = false;
        this.pool.push(node);
    }
}
// 2. 批量更新(减少频繁的节点操作)
update(dt: number) {
    // 收集所有需要更新的节点
    const nodesToUpdate: cc.Node[] = [];

    // 一次性处理
    nodesToUpdate.forEach(node => {
        node.setPosition(node.position.x + speed * dt, node.position.y);
    });
}
// 3. 使用cc.SpriteFrame的缓存
const spriteFrameCache = new Map<string, cc.SpriteFrame>();
async function loadSpriteFrame(path: string): Promise<cc.SpriteFrame> {
    if (spriteFrameCache.has(path)) {
        return spriteFrameCache.get(path)!;
    }

    return new Promise((resolve) => {
        cc.resources.load(path, cc.SpriteFrame, (err, spriteFrame) => {
            if (!err) {
                spriteFrameCache.set(path, spriteFrame);
                resolve(spriteFrame);
            }
        });
    });
}

学习路径与资源推荐

阶段性学习目标

阶段 目标 关键技术点
入门阶段 基础概念掌握 TypeScript 基础、节点操作、生命周期、简单 UI
进阶阶段 游戏开发能力 组件通信、资源管理、动画系统、场景管理
实战阶段 完整项目开发 性能优化、发布打包、热更新、团队协作

实用开发技巧

  • 编辑器快捷操作

    • 使用Ctrl+D复制节点
    • 使用Ctrl+Shift+F全局搜索
    • 使用F键聚焦选中节点
  • 调试技巧

    • 使用console.log进行简单调试
    • 使用 Chrome 开发者工具进行深度调试
    • 使用cc.debug进行性能监控
  • 常见陷阱规避

    • 避免在update中频繁创建对象
    • 及时释放不再使用的资源
    • 正确处理节点销毁时的清理工作