Loading...
Loading...
提供 Cocos Creator 3.8 游戏引擎的全面开发指导,包括组件系统(_decorator、Component)、生命周期回调、事件系统(EventTarget、input)、resources 资源管理、tween 缓动系统、对象池、UI 系统、物理碰撞以及可试玩广告优化。在用户编写或重构 Cocos Creator 3.x TypeScript 代码、实现游戏功能、处理资源加载与释放、优化性能/包体大小、审查代码变更、搭建可试玩广告项目架构时触发。也适用于用户提到 import from 'cc'、Component、Node、resources、tween、director 等 3.x API 时使用。
npx skill4agent add zpqq132555/skills cocos-creator-3x-cncocos-creator-3x-cnimport { ... } from 'cc'| 项目 | 2.x 写法 | 3.8 写法 |
|---|---|---|
| 导入 | | |
| 组件基类 | | |
| 节点类 | | |
| 调试宏 | | |
| 全局事件 | | |
| 资源加载 | | |
| 缓动 | | |
| 实例化 | | |
| 场景管理 | | |
| 属性类型 | | |
import { _decorator, Component, Node } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('MyComponent')
export class MyComponent extends Component {
@property(Node)
private readonly targetNode: Node | null = null;
@property
private readonly speed: number = 10;
// 生命周期见 §2
protected onLoad(): void { }
protected start(): void { }
protected update(dt: number): void { }
protected onDestroy(): void { }
}| 装饰器 | 说明 | 示例 |
|---|---|---|
| 注册 cc 类(名称全局唯一) | |
| 序列化属性 | |
| 指定类型 | |
| 数组类型 | |
| 整数类型简写 | |
| 浮点类型简写 | |
| 类型简写 | |
| 编辑器模式执行 | |
| 依赖组件 | |
| 执行优先级 | |
| 禁止重复添加 | |
| 添加到组件菜单 | |
@property({
type: Node,
visible: true,
displayName: '目标节点',
tooltip: '要跟随的目标',
serializable: true,
group: { name: '基础设置' },
})
targetNode: Node | null = null;typevisibledisplayNametooltipserializablereadonlyminmaxsteprangeslidegroupoverrideformerlySerializedAseditorOnlyonLoadonEnablestartupdatelateUpdateonDisableonDestroy ┌─────────┐ ┌──────────┐ ┌───────┐ ┌────────┐
│ onLoad │──▶│ onEnable │──▶│ start │──▶│ update │──┐
└─────────┘ └──────────┘ └───────┘ └────────┘ │
▲ │
└─────────┘
┌────────────┐
│ lateUpdate │
└────────────┘
│
┌───────────┐ ┌─────────────┐
│ onDisable │──▶│ onDestroy │
└───────────┘ └─────────────┘| 回调 | 触发时机 | 典型用途 |
|---|---|---|
| 节点首次激活时(仅一次) | 初始化引用、获取组件 |
| 组件启用时 | 注册事件监听 |
| 第一次 | 需要依赖其他组件 |
| 每帧调用 | 游戏逻辑、移动 |
| 所有 | 跟随相机、后处理 |
| 组件禁用时 | 取消事件监听 |
| 节点销毁时 | 资源释放、清理 |
onLoadonLoadonEnablestart@executionOrderonEnableonDisableonDestroyimport { EventTarget } from 'cc';
// 创建全局事件总线
const eventTarget = new EventTarget();
// 监听
eventTarget.on('game-over', (score: number) => {
console.log('Game Over, score:', score);
});
// 发射(最多 5 个参数)
eventTarget.emit('game-over', 100);
// 取消监听
eventTarget.off('game-over', callback, target);Nodeimport { _decorator, Component, input, Input, EventTouch, EventKeyboard, KeyCode } from 'cc';
@ccclass('InputExample')
export class InputExample extends Component {
protected onEnable(): void {
input.on(Input.EventType.TOUCH_START, this.onTouchStart, this);
input.on(Input.EventType.KEY_DOWN, this.onKeyDown, this);
}
protected onDisable(): void {
input.off(Input.EventType.TOUCH_START, this.onTouchStart, this);
input.off(Input.EventType.KEY_DOWN, this.onKeyDown, this);
}
private onTouchStart(event: EventTouch): void {
console.log(event.getLocation()); // 屏幕坐标
console.log(event.getUILocation()); // UI 坐标
}
private onKeyDown(event: EventKeyboard): void {
if (event.keyCode === KeyCode.SPACE) { /* ... */ }
}
}| 类别 | 事件类型 |
|---|---|
| 触摸 | |
| 鼠标 | |
| 键盘 | |
| 重力 | |
// UI 节点触摸(需要 UITransform 组件)
this.node.on(Node.EventType.TOUCH_START, (event: EventTouch) => {
event.propagationStopped = true; // 阻止冒泡
}, this);
// 使用捕获阶段
this.node.on(Node.EventType.TOUCH_START, callback, this, true);
// 事件穿透(v3.4+)
private onTouchStart(event: EventTouch): void {
event.preventSwallow = true; // 阻止事件被吞噬
}import { Event } from 'cc';
class MyEvent extends Event {
public readonly detail: unknown;
constructor(name: string, bubbles?: boolean, detail?: unknown) {
super(name, bubbles);
this.detail = detail;
}
}
// 派发事件(支持冒泡/捕获)
this.node.dispatchEvent(new MyEvent('custom-event', true, { data: 123 }));import { resources, Prefab, SpriteFrame, Texture2D, instantiate, Sprite } from 'cc';
// 加载 Prefab
resources.load('prefabs/enemy', Prefab, (err, prefab) => {
const node = instantiate(prefab);
this.node.addChild(node);
});
// 加载 SpriteFrame(注意路径到子资源)
resources.load('images/bg/spriteFrame', SpriteFrame, (err, sf) => {
this.getComponent(Sprite)!.spriteFrame = sf;
});
// 批量加载
resources.loadDir('textures', Texture2D, (err, assets) => { /* ... */ });
// 预加载
resources.preload('images/bg/spriteFrame', SpriteFrame);import { assetManager, Prefab } from 'cc';
// 加载 Bundle
assetManager.loadBundle('gameBundle', (err, bundle) => {
// 加载 Bundle 中的资源
bundle.load('prefabs/player', Prefab, (err, prefab) => { /* ... */ });
// 批量加载
bundle.loadDir('textures', (err, assets) => { /* ... */ });
// 加载场景
bundle.loadScene('level1', (err, scene) => {
director.runScene(scene);
});
});
// 获取已加载的 Bundle
const bundle = assetManager.getBundle('gameBundle');import { assetManager, resources, SpriteFrame } from 'cc';
// 方式一:直接释放
assetManager.releaseAsset(asset);
// 方式二:通过 Bundle 释放
bundle.release('image', SpriteFrame);
bundle.releaseAll();
// 方式三:引用计数管理
resources.load('img/spriteFrame', SpriteFrame, (err, sf) => {
sf.addRef(); // 持有时增加引用
// ... 使用中
sf.decRef(); // 不再使用时减少引用
});
// 移除 Bundle
assetManager.removeBundle(bundle);import { assetManager, ImageAsset, Texture2D, SpriteFrame } from 'cc';
assetManager.loadRemote<ImageAsset>('https://example.com/avatar.png', (err, imageAsset) => {
const texture = new Texture2D();
texture.image = imageAsset;
const sf = new SpriteFrame();
sf.texture = texture;
});import { tween, Vec3, Node, UIOpacity } from 'cc';
// 基础缓动
tween(this.node)
.to(1, { position: new Vec3(100, 200, 0) })
.start();
// 链式动画
tween(this.node)
.to(0.5, { scale: new Vec3(1.2, 1.2, 1) })
.to(0.5, { scale: new Vec3(1, 1, 1) })
.union() // 合并为一个动作
.repeatForever() // 无限循环
.start();
// 回调
tween(this.node)
.to(1, { position: new Vec3(0, 100, 0) })
.call(() => { console.log('done'); })
.start();
// 并行 & 延迟
tween(this.node)
.parallel(
tween().to(1, { position: new Vec3(100, 0, 0) }),
tween().to(1, { scale: new Vec3(2, 2, 1) }),
)
.delay(0.5)
.start();
// 透明度缓动(需要 UIOpacity 组件)
const opacity = this.node.getComponent(UIOpacity)!;
tween(opacity).to(0.5, { opacity: 0 }).start();
// 停止缓动
Tween.stopAllByTarget(this.node);// 子节点
const child = this.node.getChildByName('child');
const children = this.node.children;
const childByPath = find('Canvas/UI/Button', this.node); // 路径查找
// 父节点
const parent = this.node.parent;
// 全局查找
import { find } from 'cc';
const canvas = find('Canvas');
// 组件获取
const sprite = this.node.getComponent(Sprite);
const sprites = this.node.getComponentsInChildren(Sprite);import { Vec3, Quat } from 'cc';
// 位置
this.node.setPosition(new Vec3(100, 200, 0));
this.node.position = new Vec3(100, 200, 0);
// 旋转 (3D 使用 Quat)
this.node.setRotationFromEuler(0, 0, 45);
this.node.angle = 45; // 2D 简写
// 缩放
this.node.setScale(new Vec3(2, 2, 1));
// 世界坐标
const worldPos = this.node.worldPosition;
this.node.setWorldPosition(worldPos);import { director } from 'cc';
// 加载并切换场景
director.loadScene('GameScene');
// 带回调
director.loadScene('GameScene', (err, scene) => {
console.log('scene loaded');
});
// 预加载场景
director.preloadScene('GameScene', (err) => {
// 预加载完成
});
// 常驻节点
director.addPersistRootNode(this.node);
director.removePersistRootNode(this.node);import { sys } from 'cc';
import { DEBUG, EDITOR, PREVIEW, BUILD } from 'cc/env';
// 环境宏
if (DEBUG) { /* 调试模式 */ }
if (EDITOR) { /* 编辑器模式 */ }
if (BUILD) { /* 构建后 */ }
// 平台判断
if (sys.isBrowser) { /* 浏览器 */ }
if (sys.isNative) { /* 原生平台 */ }
if (sys.platform === sys.Platform.WECHAT_GAME) { /* 微信小游戏 */ }// ✅ 正确:从 'cc' 模块导入
import { _decorator, Component, Node, Vec3, Color, Sprite, resources } from 'cc';
// ✅ 正确:从 'cc/env' 导入环境宏
import { DEBUG, EDITOR } from 'cc/env';
// ❌ 错误:不要使用 cc. 全局前缀
// cc.Component, cc.Node, cc.find // 3.x 中不存在| 文件 | 说明 |
|---|---|
| component-system.md | 组件系统、装饰器、生命周期详解 |
| event-patterns.md | 事件系统、输入/节点/自定义事件模式 |
| asset-management.md | 资源管理、加载/释放/Bundle |
| playable-optimization.md | 可试玩广告优化、包体/性能策略 |
| 文件 | 说明 |
|---|---|
| quality-hygiene.md | TypeScript 代码质量与卫生规范 |
| performance.md | 性能优化指南、内存/渲染/逻辑 |
| 文件 | 说明 |
|---|---|
| architecture-review.md | 架构审查清单 |
| quality-review.md | 代码质量审查清单 |