mcpField
T
theone-cocos-standards

theone-cocos-standards

github.com/the1studio开发195 次安装
代码仓库

关于 theone-cocos-standards

面向 Cocos Creator 3.x 和 TypeScript 4.1+ 开发者的编码技能,提供代码质量、组件架构及性能优化规范。适用于可玩广告开发、代码审查与重构。

主要功能

  1. 01TypeScript 严格模式与类型安全
  2. 02组件生命周期与事件管理
  3. 03资源加载与对象池建议
  4. 04可玩广告性能优化
  5. 05代码审查检查清单

适用场景

  1. 01编写或重构 Cocos Creator 代码
  2. 02检查 TypeScript 代码质量
  3. 03优化可玩广告性能

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/the1studio/theone-training-skills --skill theone-cocos-standards

安装后在 Claude Code 中输入/theone-cocos-standards确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/framework/
component-system.md
event-patterns.md
playable-optimization.md
size-optimization.md
references/language/
modern-typescript.md
performance.md
quality-hygiene.md
references/review/
architecture-review.md
performance-review.md
quality-review.md

详细介绍

TheOne Studio Cocos Creator 开发规范

⚠️ Cocos Creator 3.x(TypeScript 4.1+): 所有模式和示例均适用于 Cocos Creator 3.x 可玩广告开发。

技能用途

此技能通过以下标准落实 TheOne Studio 全面的 Cocos Creator 开发规范,并将代码质量放在首位:

优先级 1:代码质量与规范(最重要)

  • TypeScript 严格模式、ESLint 配置、访问修饰符(public/private/protected)
  • 抛出异常(绝不静默处理错误)
  • 开发期间使用 console.log,在生产构建中移除
  • 不可变字段使用 readonly,常量使用 const
  • 不写行内注释(使用描述性名称)
  • 妥善处理错误并确保类型安全

优先级 2:现代 TypeScript 模式

  • 优先使用数组方法(map/filter/reduce),而非循环
  • 箭头函数、解构、展开运算符
  • 可选链、空值合并
  • 类型守卫、工具类型(Partial、Required、Readonly)
  • 现代 TypeScript 特性

优先级 3:Cocos Creator 架构

  • 基于组件的实体-组件(EC)系统
  • 生命周期方法:onLoad→start→onEnable→update→onDisable→onDestroy
  • 自定义事件采用 EventDispatcher 模式
  • 节点事件系统(EventTouch、键盘事件)
  • 可玩广告的资源管理与对象池

优先级 4:可玩广告性能

  • DrawCall 批处理(目标:<10 个 DrawCall)
  • Sprite 图集配置(启用自动图集)
  • 骨骼动画使用 GPU 蒙皮
  • update() 循环中零内存分配
  • Bundle 大小 <5MB(纹理压缩、代码压缩)

此技能的触发场景

  • 编写或重构 Cocos Creator TypeScript 代码
  • 实现可玩广告功能
  • 使用组件生命周期和事件
  • 优化可玩广告性能
  • 审查代码变更或拉取请求
  • 搭建可玩项目架构
  • 减小 Bundle 大小或 DrawCall 数量

快速参考指南

需要什么帮助?
优先级任务参考资料
🔴 优先级 1:代码质量(首先检查)
1TypeScript 严格模式、ESLint、访问修饰符质量与规范 ⭐
1抛出异常,正确处理错误质量与规范 ⭐
1console.log(仅用于开发),生产环境中移除质量与规范 ⭐
1readonly/const、无内联注释、使用描述性名称质量与规范 ⭐
🟡 优先级 2:现代 TypeScript 模式
2数组方法、箭头函数、解构现代 TypeScript
2可选链、空值合并现代 TypeScript
2类型守卫、工具类型现代 TypeScript
🟢 优先级 3:Cocos 架构
3组件系统、@property 装饰器组件系统
3生命周期方法(onLoad→start→update→onDestroy)组件系统
3EventDispatcher、节点事件、清理事件模式
3资源加载、对象池、内存管理可玩广告优化
🔵 优先级 4:性能与审查
4DrawCall 批处理、精灵图集、GPU 蒙皮可玩广告优化
4更新循环优化、零分配性能
4缩减包体积(目标 <5MB)体积优化
4架构审查(组件、生命周期、事件)架构审查
4TypeScript 质量审查质量审查
4性能审查(DrawCalls、分配)性能审查

🔴 关键:代码质量规则(首先检查!)

⚠️ 强制质量标准

编写任何代码之前,务必先落实以下要求:

  1. 启用 TypeScript 严格模式——在 tsconfig.json 中设置 "strict": true
  2. 使用 ESLint 配置——启用 @typescript-eslint 规则
  3. 使用访问修饰符——为所有成员指定 public/private/protected
  4. 遇到错误时抛出异常——绝不静默失败或返回 undefined
  5. console.log 仅用于开发——在生产构建中移除所有 console 语句
  6. 不可变字段使用 readonly——为不会重新赋值的字段标记 readonly
  7. 常量使用 const——常量应使用 const,而不是 let
  8. 不写内联注释——使用描述性名称,让代码能够自解释
  9. 妥善处理 null/undefined——使用可选链和空值合并
  10. 确保类型安全——避免使用 any 类型,使用恰当的类型和接口

示例:优先落实代码质量要求

// ✅ EXCELLENT: All quality rules enforced
import { _decorator, Component, Node, EventTouch } from 'cc';
const { ccclass, property } = _decorator;

@ccclass('PlayerController')
export class PlayerController extends Component {
    // 3. Access modifier, 6. readonly for immutable
    @property(Node)
    private readonly targetNode: Node | null = null;

    // 7. const for constants
    private static readonly MAX_HEALTH: number = 100;
    private currentHealth: number = 100;

    // Lifecycle: onLoad → start → onEnable
    protected onLoad(): void {
        // 4. Throw exception for errors
        if (!this.targetNode) {
            throw new Error('PlayerController: targetNode is not assigned');
        }

        // 9. Proper event listener setup
        this.node.on(Node.EventType.TOUCH_START, this.onTouchStart, this);
    }

    protected onDestroy(): void {
        // 9. Always cleanup event listeners
        this.node.off(Node.EventType.TOUCH_START, this.onTouchStart, this);
    }

    private onTouchStart(event: EventTouch): void {
        // 5. console.log only for development (remove in production)
        if (CC_DEBUG) {
            console.log('Touch detected');
        }

        this.takeDamage(10);
    }

    // 8. Descriptive method names (no inline comments needed)
    private takeDamage(amount: number): void {
        this.currentHealth -= amount;

        if (this.currentHealth <= 0) {
            this.handlePlayerDeath();
        }
    }

    private handlePlayerDeath(): void {
        // Death logic
    }
}

⚠️ Cocos Creator 架构规则(质量要求之后)

组件系统基础

实体-组件(EC)系统:

  • 组件继承 Component 类
  • 使用 @ccclass 和 @property 装饰器
  • 生命周期:onLoad → start → onEnable → update → lateUpdate → onDisable → onDestroy

执行顺序:

  1. onLoad() - 组件初始化,一次性设置
  2. start() - 所有组件加载完毕后调用,此时可以引用其他组件
  3. onEnable() - 组件/节点启用时调用(可以多次调用)
  4. update(dt) - 每帧调用(在可玩广告中谨慎使用)
  5. lateUpdate(dt) - 所有 update() 调用完成后调用
  6. onDisable() - 组件/节点禁用时调用
  7. onDestroy() - 清理、移除监听器、释放资源

通用规则:

  • ✅ 在 onLoad() 中初始化,在 start() 中引用其他组件
  • ✅ 在 onEnable() 中注册事件,在 onDisable() 中取消注册
  • ✅ 始终在 onDestroy() 中清理监听器
  • ✅ 避免在 update() 中执行繁重逻辑(这对可玩广告的性能至关重要)
  • ✅ 对不应重新赋值的 @property 字段使用 readonly
  • ✅ 缺少必需引用时抛出异常

简要示例

🔴 优先保证代码质量
// ✅ EXCELLENT: Quality rules enforced
import { _decorator, Component, Node } from 'cc';
const { ccclass, property } = _decorator;

@ccclass('GameManager')
export class GameManager extends Component {
    @property(Node)
    private readonly playerNode: Node | null = null;

    private static readonly MAX_SCORE: number = 1000;
    private currentScore: number = 0;

    protected onLoad(): void {
        // Throw exception for missing required references
        if (!this.playerNode) {
            throw new Error('GameManager: playerNode is required');
        }

        if (CC_DEBUG) {
            console.log('GameManager initialized'); // Development only
        }
    }

    public addScore(points: number): void {
        if (points <= 0) {
            throw new Error('GameManager.addScore: points must be positive');
        }

        this.currentScore = Math.min(
            this.currentScore + points,
            GameManager.MAX_SCORE
        );
    }
}
🟡 现代 TypeScript 模式
// ✅ GOOD: Array methods instead of loops
const activeEnemies = allEnemies.filter(e => e.isActive);
const enemyPositions = activeEnemies.map(e => e.node.position);

// ✅ GOOD: Optional chaining and nullish coalescing
const playerName = player?.name ?? 'Unknown';

// ✅ GOOD: Destructuring
const { x, y } = this.node.position;

// ✅ GOOD: Arrow functions
this.enemies.forEach(enemy => enemy.takeDamage(10));

// ✅ GOOD: Type guards
function isPlayer(node: Node): node is PlayerNode {
    return node.getComponent(PlayerController) !== null;
}
🟢 Cocos Creator 组件模式
import { _decorator, Component, Node, EventTouch, Vec3 } from 'cc';
const { ccclass, property } = _decorator;

@ccclass('TouchHandler')
export class TouchHandler extends Component {
    @property(Node)
    private readonly targetNode: Node | null = null;

    private readonly tempVec3: Vec3 = new Vec3(); // Reusable vector

    // 1. onLoad: Initialize component
    protected onLoad(): void {
        if (!this.targetNode) {
            throw new Error('TouchHandler: targetNode is required');
        }
    }

    // 2. start: Reference other components (if needed)
    protected start(): void {
        // Can safely access other components here
    }

    // 3. onEnable: Register event listeners
    protected onEnable(): void {
        this.node.on(Node.EventType.TOUCH_START, this.onTouchStart, this);
        this.node.on(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
    }

    // 4. onDisable: Unregister event listeners
    protected onDisable(): void {
        this.node.off(Node.EventType.TOUCH_START, this.onTouchStart, this);
        this.node.off(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
    }

    // 5. onDestroy: Final cleanup
    protected onDestroy(): void {
        // Release any additional resources
    }

    private onTouchStart(event: EventTouch): void {
        // Handle touch
    }

    private onTouchMove(event: EventTouch): void {
        // Reuse vector to avoid allocations
        this.targetNode!.getPosition(this.tempVec3);
        this.tempVec3.y += 10;
        this.targetNode!.setPosition(this.tempVec3);
    }
}
🟢 事件分发器模式
import { _decorator, Component, EventTarget } from 'cc';
const { ccclass } = _decorator;

// Custom event types
export enum GameEvent {
    SCORE_CHANGED = 'score_changed',
    LEVEL_COMPLETE = 'level_complete',
    PLAYER_DIED = 'player_died',
}

export interface ScoreChangedEvent {
    oldScore: number;
    newScore: number;
}

@ccclass('EventManager')
export class EventManager extends Component {
    private static instance: EventManager | null = null;
    private readonly eventTarget: EventTarget = new EventTarget();

    protected onLoad(): void {
        if (EventManager.instance) {
            throw new Error('EventManager: instance already exists');
        }
        EventManager.instance = this;
    }

    public static emit(event: GameEvent, data?: any): void {
        if (!EventManager.instance) {
            throw new Error('EventManager: instance not initialized');
        }
        EventManager.instance.eventTarget.emit(event, data);
    }

    public static on(event: GameEvent, callback: Function, target?: any): void {
        if (!EventManager.instance) {
            throw new Error('EventManager: instance not initialized');
        }
        EventManager.instance.eventTarget.on(event, callback, target);
    }

    public static off(event: GameEvent, callback: Function, target?: any): void {
        if (!EventManager.instance) {
            throw new Error('EventManager: instance not initialized');
        }
        EventManager.instance.eventTarget.off(event, callback, target);
    }
}

// Usage in component
@ccclass('ScoreDisplay')
export class ScoreDisplay extends Component {
    protected onEnable(): void {
        EventManager.on(GameEvent.SCORE_CHANGED, this.onScoreChanged, this);
    }

    protected onDisable(): void {
        EventManager.off(GameEvent.SCORE_CHANGED, this.onScoreChanged, this);
    }

    private onScoreChanged(data: ScoreChangedEvent): void {
        console.log(`Score: ${data.oldScore} → ${data.newScore}`);
    }
}
🔵 可玩广告性能优化
import { _decorator, Component, Node, Sprite, SpriteAtlas } from 'cc';
const { ccclass, property } = _decorator;

@ccclass('OptimizedSpriteManager')
export class OptimizedSpriteManager extends Component {
    // Use sprite atlas for DrawCall batching
    @property(SpriteAtlas)
    private readonly characterAtlas: SpriteAtlas | null = null;

    // Preallocate arrays to avoid allocations in update()
    private readonly tempNodes: Node[] = [];
    private frameCount: number = 0;

    protected onLoad(): void {
        if (!this.characterAtlas) {
            throw new Error('OptimizedSpriteManager: characterAtlas is required');
        }

        // Prewarm sprite frames from atlas
        this.prewarmSpriteFrames();
    }

    private prewarmSpriteFrames(): void {
        // Load all sprites from atlas (batched in single DrawCall)
        const spriteFrame = this.characterAtlas!.getSpriteFrame('character_idle');
        if (!spriteFrame) {
            throw new Error('Sprite frame not found in atlas');
        }
    }

    // Optimize update: avoid allocations, use object pooling
    protected update(dt: number): void {
        // Run expensive operations every N frames instead of every frame
        this.frameCount++;
        if (this.frameCount % 10 === 0) {
            this.updateExpensiveOperation();
        }
    }

    private updateExpensiveOperation(): void {
        // Reuse array instead of creating new one
        this.tempNodes.length = 0;

        // Batch operations to reduce DrawCalls
    }
}

代码审查清单

快速验证(提交前)

🔴 代码质量(优先检查):

  • 在 tsconfig.json 中启用 TypeScript 严格模式
  • ESLint 规则检查通过(无错误)
  • 所有访问修饰符正确(public/private/protected)
  • 出错时抛出异常(不静默失败)
  • 移除 console.log 或将其封装在 CC_DEBUG 中
  • 对不会重新赋值的字段使用 readonly
  • 对常量使用 const
  • 不写行内注释(代码应自明)
  • 正确处理 null/undefined
  • 不使用 any 类型(使用适当的类型)

🟡 现代 TypeScript 模式:

  • 使用数组方法代替手动循环
  • 回调使用箭头函数
  • 使用可选链 (?.) 安全访问属性
  • 使用空值合并运算符 (??) 设置默认值
  • 使用解构让代码更简洁
  • 使用类型守卫缩小类型范围

🟢 Cocos Creator 架构:

  • 组件生命周期方法的顺序正确
  • 使用 onLoad() 初始化,使用 start() 引用其他组件
  • 在 onEnable() 中注册事件监听器
  • 在 onDisable() 中取消注册事件监听器
  • 在 onDestroy() 中释放资源
  • 正确使用 @property 装饰器
  • 验证必需引用(如果为 null 则抛出异常)

🔵 可玩广告性能:

  • update() 循环中不进行内存分配
  • 使用精灵图集进行 DrawCall 批处理
  • 为骨骼动画启用 GPU 蒙皮
  • 限制高开销操作的频率(不要每帧执行)
  • 对频繁创建的对象使用对象池
  • 启用纹理压缩
  • Bundle 大小目标 <5MB
  • DrawCall 数量目标 <10

应避免的常见错误

❌ 不要:
  1. 忽略 TypeScript 严格模式 → 启用 "strict": true
  2. 静默处理错误 → 出错时抛出异常
  3. 在生产环境中保留 console.log → 移除或将其封装在 CC_DEBUG 中
  4. 省略访问修饰符 → 使用 public/private/protected
  5. 使用 any 类型 → 定义适当的类型和接口
  6. 添加行内注释 → 改用描述性名称
  7. 跳过事件清理 → 始终在 onDisable/onDestroy 中取消注册
  8. 在 update() 中分配内存 → 预先分配并复用对象
  9. 忘记精灵图集 → 使用图集进行 DrawCall 批处理
  10. 在 update() 中执行繁重逻辑 → 限制高开销操作的频率
  11. 跳过 null 检查 → 在 onLoad 中验证必需引用
  12. 使用可变的 @property 字段 → 适当时使用 readonly
  13. 手动遍历数组 → 使用 map/filter/reduce
  14. 忽略 Bundle 大小 → 监控并优化(目标 <5MB)
✅ 应做:
  1. 启用 TypeScript 严格模式("strict": true)
  2. 遇到错误时抛出异常(绝不静默失败)
  3. 仅在开发期间使用 console.log(生产环境中移除)
  4. 使用访问修饰符(public/private/protected)
  5. 定义恰当的类型(避免使用 any)
  6. 使用描述性名称(不要添加行内注释)
  7. 始终清理事件(onDisable/onDestroy)
  8. 预分配对象(在 update() 中重复使用)
  9. 使用精灵图集(批处理 DrawCall)
  10. 对开销大的操作进行限流(不要每帧执行)
  11. 验证必需的引用(如果为 null,则在 onLoad 中抛出异常)
  12. 在适当情况下为 @property 使用 readonly
  13. 使用数组方法(map/filter/reduce)
  14. 监控包体积(可玩广告的目标为 <5MB)

审查严重级别

🔴 严重(必须修复)
  • 禁用了 TypeScript 严格模式 - 必须启用 "strict": true
  • 静默处理错误 - 遇到错误时必须抛出异常
  • 生产代码中存在 console.log - 移除或用 CC_DEBUG 包裹
  • 缺少访问修饰符 - 所有成员都必须有修饰符
  • 无正当理由使用 any 类型 - 定义恰当的类型
  • 使用行内注释而非描述性名称 - 重命名并移除注释
  • 未清理事件监听器 - 会造成内存泄漏,必须取消注册
  • 缺少必需引用验证 - 如果为 null,必须在 onLoad 中抛出异常
  • 在 update() 循环中分配对象 - 这是关键性能问题,必须预分配
  • 多个精灵未使用精灵图集 - 会导致 DrawCall 激增,必须使用图集
  • 包体积 >5MB - 超出可玩广告限制,必须优化
🟡 重要(应该修复)
  • @property 字段缺少 readonly - 如果不会重新赋值,应该使用 readonly
  • 常量缺少 const - 应使用 const 而不是 let
  • 使用手动循环而非数组方法 - 应使用 map/filter/reduce
  • 缺少可选链 - 应使用 ?. 进行安全访问
  • 缺少空值合并运算符 - 应使用 ?? 设置默认值
  • update() 中包含繁重逻辑 - 应对开销大的操作进行限流
  • 频繁分配对象但未使用对象池 - 应实现对象池
  • 未启用纹理压缩 - 应启用以缩小包体积
  • DrawCall 数量 >10 - 应优化批处理
🟢 可选(建议)
  • 可以在回调中使用箭头函数
  • 可以使用解构让代码更简洁
  • 可以使用类型守卫提高类型安全性
  • 可以改进命名以提高清晰度
  • 可以添加接口以获得更好的类型定义
  • 可以优化算法以提升性能

详细参考

TypeScript 语言标准
  • 质量与规范 - 严格模式、ESLint、访问修饰符、错误处理
  • 现代 TypeScript - 数组方法、可选链、类型守卫、工具类型
  • 性能 - 更新循环优化、零分配、缓存
Cocos Creator 框架
  • 组件系统 - EC 系统、生命周期方法、@property 装饰器
  • 事件模式 - EventDispatcher、节点事件、订阅清理
  • 可玩广告优化 - DrawCall 批处理、精灵图集、GPU 蒙皮、资源池化
  • 体积优化 - 包体积缩减、纹理压缩、构建优化
代码审查
  • 架构审查 - 组件违规、生命周期错误、事件泄漏
  • 质量审查 - TypeScript 质量问题、访问修饰符、错误处理
  • 性能审查 - 可玩广告特有的性能问题、DrawCall、对象分配

摘要

此技能为 TheOne Studio 的可玩广告团队提供全面的 Cocos Creator 开发规范:

  • TypeScript 卓越实践:严格模式、现代模式和类型安全
  • Cocos 架构:组件生命周期、事件模式和资源管理
  • 可玩广告性能:DrawCall 批处理、GPU 蒙皮、<5MB 的包体
  • 代码质量:落实质量、规范和性能规则

使用上方的快速参考指南,查找所需的具体模式。

评论

支持 Markdown