{"id":18275508,"url":"https://github.com/leeyip/cocos-framework","last_synced_at":"2025-04-05T03:31:00.499Z","repository":{"id":44388213,"uuid":"400530402","full_name":"LeeYip/cocos-framework","owner":"LeeYip","description":"一个基于Cocos Creator的框架","archived":false,"fork":false,"pushed_at":"2024-05-14T12:55:52.000Z","size":16434,"stargazers_count":139,"open_issues_count":1,"forks_count":57,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-03T22:02:17.742Z","etag":null,"topics":["cocos","cocos-creator","framework"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LeeYip.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-08-27T14:10:15.000Z","updated_at":"2025-02-24T02:30:27.000Z","dependencies_parsed_at":"2023-01-23T02:16:05.856Z","dependency_job_id":null,"html_url":"https://github.com/LeeYip/cocos-framework","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LeeYip%2Fcocos-framework","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LeeYip%2Fcocos-framework/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LeeYip%2Fcocos-framework/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LeeYip%2Fcocos-framework/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LeeYip","download_url":"https://codeload.github.com/LeeYip/cocos-framework/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247284911,"owners_count":20913691,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cocos","cocos-creator","framework"],"created_at":"2024-11-05T12:13:08.578Z","updated_at":"2025-04-05T03:30:55.466Z","avatar_url":"https://github.com/LeeYip.png","language":"TypeScript","readme":"# Cocos Framework\r\n一个基于Cocos Creator2.4.11的框架\r\n\r\n## 目录\r\n- [前言](#preface)\r\n- [演示](#showcase)\r\n- [框架结构](#framework)\r\n    - [动画状态机](#framework-animator)\r\n    - [全局时间管理器](#framework-timer)\r\n    - [全局弹窗管理器](#framework-layer)\r\n    - [全局事件管理器](#framework-events)\r\n    - [资源管理器](#framework-res)\r\n    - [音频管理器](#framework-audio)\r\n    - [多语言](#framework-i18n)\r\n    - [常用ui组件](#framework-ui)\r\n    - [常用工具类](#framework-tool)\r\n    - [引擎源码hack](#framework-hack)\r\n    - [几个shader](#framework-shader)\r\n- [命名规范](#name)\r\n- [参考资料](#reference)\r\n\r\n## \u003ca id=\"preface\"\u003e\u003c/a\u003e前言\r\n这套框架是我个人开发过程中的积累，已应用于我个人的几个小项目中。单scene多prefab形式，轻量，各个功能基本都可单独拆解开使用。\r\n\r\n## \u003ca id=\"showcase\"\u003e\u003c/a\u003e演示\r\n部分功能演示地址 https://leeyip.github.io/cocos-framework/\r\n\r\n\r\n\r\n## \u003ca id=\"framework\"\u003e\u003c/a\u003e框架结构\r\n\r\n#### \u003ca id=\"framework-animator\"\u003e\u003c/a\u003e动画状态机\r\n\u003e文件路径(scripts/animator/)\r\n\r\n详见 https://github.com/LeeYip/cocos-animator\r\n\r\n#### \u003ca id=\"framework-timer\"\u003e\u003c/a\u003e全局时间管理器\r\n\u003e文件路径(scripts/common/cmpt/base/Timer.ts)\r\n\r\n组件在场景加载后会自动绑定常驻节点，由timeScale控制每帧间隔时间的缩放。引入并修改了开源库tween.js，在Timer组件中更新和控制，使用方式请参考 https://github.com/tweenjs/tween.js\r\n\r\n关于我对tween.js的修改\r\n1. 设置了新的Group，用以执行受timeScale影响的tween动画\r\n```typescript\r\n// 执行tween，让node用1000毫秒x坐标移动到100处\r\nnew Tween(node)\r\n    .to({x: 100}, 1000)\r\n    .start();\r\n\r\n// 执行tween，让node用1000毫秒x坐标移动到100处，实际动画运行时间受timeScale影响\r\nnew Tween(node, SCALE_TWEEN)\r\n    .to({x: 100}, 1000)\r\n    .start();\r\n```\r\n\r\n2. 加入了新的接口`bindCCObject(obj: cc.Object)`，可以将tween与cc.Node或cc.Component等类型为cc.Object的对象进行绑定。当Node或Component被销毁时，与之绑定的tween也会自动销毁。\r\n```typescript\r\n// 比如构造参数使用cc.Node\r\nlet node: cc.Node;\r\nlet tween = new Tween(node)\r\n    .to({x: 100}, 1000)\r\n    .start();\r\n// node销毁后，不需要手动销毁tween，框架内部会自动销毁\r\nnode.destory();\r\n\r\n\r\n// 或者主动绑定一个cc.Object类型的对象\r\nlet comp: cc.Component;\r\nlet tween = new Tween({a: 1})\r\n    .to({a: 10}, 1000)\r\n    .start()\r\n    .bindCCObject(comp);\r\n// 当comp销毁后，同样tween也会自动销毁\r\ncomp.destory();\r\n```\r\n\r\n- **属性**\r\n    - **`timeScale: number`**  dt缩放倍数，1为正常速度，0为暂停。修改时触发时间缩放值修改事件\r\n    - **`realDt: number`**  距上一帧间隔的真实时间\r\n    - **`scaleDt: number`**  距上一帧间隔经过timeScale缩放的时间\r\n- **方法**\r\n    - **`reset()`**  重置timeScale，触发timeScale事件\r\n    - **`gamePause()`**  暂停游戏 timeScale设置为0，触发暂停事件\r\n    - **`gameResume()`**  恢复游戏 timeScale恢复为暂停前的值，触发恢复事件\r\n\r\n#### \u003ca id=\"framework-layer\"\u003e\u003c/a\u003e全局弹窗管理器\r\n\r\n\u003e文件路径(scripts/common/cmpt/base/Layer.ts)\r\n\r\n组件需要绑在场景的根节点或者常驻节点上，所需的节点层级结构参照项目工程内的Main场景\r\n\r\n```typescript\r\n// 弹窗组件需要继承DialogBase，并重写onOpen方法和onClose方法，用来处理弹窗打开和关闭时的逻辑\r\nexport default class DlgExample extends DialogBase {\r\n    public static pUrl: string = \"example/DlgExample\";\r\n\r\n    /**\r\n     * @override\r\n     */\r\n    public onOpen(num1: number, num2: number) {\r\n        // do something...\r\n    }\r\n\r\n    /**\r\n     * @override\r\n     */\r\n    public onClose() {\r\n        // do something...\r\n    }\r\n}\r\n```\r\n\r\n打开一个弹窗，并传递onOpen方法的参数，弹窗prefab路径规则与[资源管理器](#framework-res)加载路径规则相同\r\n```typescript\r\n// 建议在弹窗组件类上加一个静态属性pUrl用以标明路径，这样在代码里便于查找和跳转引用\r\nLayer.inst.openUniDialog(DlgExample.pUrl, 1, 2);\r\n// 如果不喜欢上面的方式，也可直接填写路径\r\nLayer.inst.openUniDialog(\"example/DlgExample\", 1, 2);\r\n```\r\n\r\n可异步等待某个弹窗关闭\r\n```typescript\r\nawait Layer.inst.waitCloseDialog(DlgExample.pUrl);\r\n// 当在某处关闭了DlgExample这个弹窗或当前不存在此弹窗时，才会往下执行\r\n// do something...\r\n```\r\n\r\n- **方法**\r\n    - **`enterMain(): Promise\u003ccc.Node | null\u003e`**  进入常驻界面，并清空dialog与tip（不同于dialog，常驻界面始终显示在最底层，且同时只会存在一个）\r\n    - **`getDialog(url: string): DialogBase`**  获取弹窗组件（返回遍历到的第一个）\r\n    - **`openDialog(url: string, ...args: any[])`**  （同步方法，需确保事先已加载预制资源）打开弹窗\r\n    - **`openUniDialog(url: string, ...args: any[])`**  （同步方法，需确保事先已加载预制资源）打开唯一弹窗，同一弹窗只能同时存在一个\r\n    - **`openDialogAsync(url: string, ...args: any[]): Promise\u003cvoid\u003e`**  （异步方法）打开弹窗\r\n    - **`openUniDialogAsync(url: string, ...args: any[]): Promise\u003cvoid\u003e`**  （异步方法）打开唯一弹窗，同一弹窗节点只能同时存在一个\r\n    - **`closeDialog(url: string, play: boolean = false)`**  关闭遍历到的第一个弹窗\r\n    - **`closeDialogs(url: string = \"\", play: boolean = false)`**  关闭所有同路径弹窗，不传参则关闭所有弹窗\r\n    - **`waitCloseDialog(url: string): Promise\u003cvoid\u003e`**  异步等待弹窗关闭（只等待遍历到的第一个）\r\n    - **`waitCloseDialogs(url: string): Promise\u003cvoid\u003e`**  异步等待所有同路径弹窗关闭\r\n    - **`showTip(data: TipData | string)`**  弹出一条文字提示\r\n    - **`clearTips()`**  清空所有提示\r\n    - **`showLoading()`**  打开全局loading遮罩（打开与关闭的调用必须一一对应）\r\n    - **`hideLoading()`**  关闭全局loading遮罩\r\n\r\n#### \u003ca id=\"framework-events\"\u003e\u003c/a\u003e全局事件管理器\r\n\u003e文件路径(scripts/common/util/Events.ts)\r\n\r\n全局事件管理，装饰器风格简化事件注册注销，支持异步等待事件监听函数的结束\r\n\r\n```typescript\r\nexport default class Test extends cc.Component {\r\n    protected onLoad() {\r\n        // 注册当前类使用preloadEvent装饰器绑定的所有事件\r\n        Events.targetOn(this);\r\n    }\r\n\r\n    protected onDestroy() {\r\n        // 注销此对象上绑定的所有事件\r\n        Events.targetOff(this);\r\n    }\r\n\r\n    // 使用装饰器绑定对应事件监听的函数\r\n    @preloadEvent(EventName.GAME_PAUSE)\r\n    private eventGamePause() {\r\n        \r\n    }\r\n\r\n    @preloadEvent(EventName.GAME_RESUME)\r\n    private eventGameResume() {\r\n        \r\n    }\r\n\r\n    // 若装饰器第二个参数传true，则触发一次监听函数后会自动注销事件\r\n    @preloadEvent(EventName.TIME_SCALE, true)\r\n    private eventTimeScale() {\r\n        \r\n    }\r\n}\r\n```\r\n\r\n或者也可使用类装饰器覆盖onLoad和onDestroy方法，并分别在其中调用targetOn与targetOff\r\n```typescript\r\n// 参数为false则只注册当前类用preloadEvent绑定的事件\r\n// 参数为true则会注册当前类以及父类用preloadEvent绑定的事件\r\n@eventsOnLoad(true) // 也可使用@eventsOnEnable，对应于onEnable和onDisable\r\nexport default class Test extends cc.Component {\r\n    // 使用装饰器绑定对应事件监听的函数\r\n    @preloadEvent(EventName.GAME_PAUSE)\r\n    private eventGamePause() {\r\n        \r\n    }\r\n\r\n    @preloadEvent(EventName.GAME_RESUME)\r\n    private eventGameResume() {\r\n        \r\n    }\r\n\r\n    // 若装饰器第二个参数传true，则触发一次监听函数后会自动注销事件\r\n    @preloadEvent(EventName.TIME_SCALE, true)\r\n    private eventTimeScale() {\r\n        \r\n    }\r\n}\r\n```\r\n\r\n当在某处触发事件，对应的监听函数便会被调用，可以给监听函数传参。如果是异步监听函数，也可用await等待所有监听函数执行完毕\r\n```typescript\r\n    // 发送EventName.GAME_PAUSE事件，并传参\r\n    Events.emit(EventName.GAME_PAUSE, 1, [\"2\"]);\r\n    // 也可以await等待所有监听函数执行完毕\r\n    await Events.emitAsync(EventName.GAME_PAUSE);\r\n```\r\n\r\n- **装饰器**\r\n    - **`eventsOnLoad(onSuper: boolean = true)`** 类装饰器。用于覆盖onLoad和onDestroy方法，在onLoad中注册preloadEvent绑定的所有事件，在onDestroy注销绑定的所有事件\r\n    - **`eventsOnEnable(onSuper: boolean = true)`** 类装饰器。用于覆盖onEnable和onDisable方法，在onEnable中注册preloadEvent绑定的所有事件，在onDisable注销绑定的所有事件\r\n    - **`preloadEvent(event: EventName, once: boolean = false)`**  非静态成员函数装饰器。用于预先载入待注册的事件，配合eventsOnLoad、eventsOnEnable、targetOn使用\r\n    \r\n- **方法**\r\n    - **`targetOn(target: Object, onSuper: boolean = true)`**  注册与target构造函数预先绑定的所有事件，配合装饰器preloadEvent使用\r\n    - **`on(event: EventName, cb: (...args: any[]) =\u003e void, target: Object, once: boolean = false)`**  注册事件\r\n    - **`once(event: EventName, cb: (...args: any[]) =\u003e void, target: Object)`**  注册事件，触发一次后自动注销\r\n    - **`off(event: EventName, cb: (...args: any[]) =\u003e void, target: Object)`**  移除事件\r\n    - **`targetOff(target: Object)`**  移除target上注册的所有事件\r\n    - **`emit(event: EventName, ...args: any[])`**  派发事件\r\n    - **`emitAsync(event: EventName, ...args: any[]): Promise\u003cvoid\u003e`**  派发事件--异步\r\n\r\n#### \u003ca id=\"framework-res\"\u003e\u003c/a\u003e资源管理器\r\n\u003e文件路径(scripts/common/util/Res.ts)\r\n\r\n主要是对prefab、图片等进行资源管理，内部自动进行引用计数的加减，可保证资源的安全释放。\r\n\r\n资源加载：\r\n1. 如果加载resources内的资源，直接写明resources内的路径即可\r\n2. 如果加载路径以ab:开头，则会加载对应bundle内的资源。例：ab:bundleA/xxx/a表示bundle名为bundleA，资源路径为xxx/a\r\n```typescript\r\n// 加载resources内的资源（项目下完整路径为assets/resources/xxx/a.png）\r\nlet sf = await Res.load\u003ccc.SpriteFrame\u003e(\"xxx/a\", cc.SpriteFrame);\r\n\r\n// 加载bundle内的资源（项目下完整路径为assets/bundleA/xxx/a.png，其中bundleA为包名）\r\nlet sf = await Res.load\u003ccc.SpriteFrame\u003e(\"ab:bundleA/xxx/a\", cc.SpriteFrame);\r\n```\r\n\r\n引用计数管理：\r\n1. 尽量使用此类的接口加载所有资源、instantiate节点实例，否则需要自行管理引用计数\r\n2. Res.instantiate不要对动态生成的节点使用，尽量只instantiate prefab上预设好的节点，否则有可能会导致引用计数的管理出错\r\n3. 调用load接口时如需传入release参数，则同一资源在全局调用load时release参数尽量保持一致，否则可能不符合预期\r\n4. 请使用ResSpine、ResSprite组件去动态加载spine、图片资源，否则需要自行管理这些资源的引用计数\r\n```typescript\r\n// 请使用Res.instantiate代替cc.instantiate去获取节点实例\r\nlet node: cc.Node = Res.instantiate(prefab);\r\n\r\n// ResSpine、ResSprite组件负责自动管理引用计数\r\n// 请使用ResSprite去动态加载或者动态设置spriteFrame\r\nresSpr.setSpriteFrame(\"xxx/a\");\r\nresSpr.spriteFrame = sf;\r\n```\r\n\r\n资源释放：\r\n```typescript\r\n// 设置资源可被释放的间隔时间，资源超过此间隔未被再次load才可释放\r\nRes.releaseSec = 60;\r\n\r\n// 尝试进行缓存资源的释放\r\n// 只要遵守上述规则，此接口不会导致正在被使用的资源被引擎释放，可放心使用\r\nRes.releaseAll();\r\n```\r\n\r\n- **属性**\r\n    - **`releaseSec: number`**  资源释放的间隔时间（秒），资源超过此间隔未被load才可释放\r\n\r\n- **方法**\r\n    - **`get\u003cT extends cc.Asset\u003e(url: string, type: typeof cc.Asset): T`**  获取缓存资源。通常不应直接调用此接口，除非调用前能确保资源已加载并且能自行管理引用计数\r\n    - **`loadBundle(nameOrUrl: string): Promise\u003ccc.AssetManager.Bundle\u003e`** 加载bundle\r\n    - **`load\u003cT extends cc.Asset\u003e(url: string, type: typeof cc.Asset, release: boolean = true): Promise\u003cT | null\u003e`**  加载单个资源\r\n    - **`loadDir\u003cT extends cc.Asset\u003e(url: string, type: typeof cc.Asset, release: boolean = true): Promise\u003cT[]\u003e`**  加载某个文件夹内的某类资源\r\n    - **`instantiate(original: cc.Node | cc.Prefab, related?: cc.Node | cc.Prefab): cc.Node`**  获取节点实例，并建立新节点与prefab资源的联系\r\n    - **`releaseAll()`**  尝试释放所有缓存资源\r\n\r\n#### \u003ca id=\"framework-audio\"\u003e\u003c/a\u003e音频管理器\r\n\u003e文件路径(scripts/common/util/AudioManager.ts)\r\n\r\n统一控制bgm和音效的暂停恢复和开关，支持音量渐变播放和渐变停止，支持控制同一音效同时播放的最大数量\r\n\r\n- **属性**\r\n    - **`bgmVolume: number`**  全局bgm音量\r\n    - **`sfxVolume: number`**  全局sfx音量\r\n    - **`bgmOff: boolean`**  bgm是否关闭\r\n    - **`sfxOff: boolean`**  sfx是否关闭\r\n    - **`bgmPause: boolean`**  bgm是否暂停\r\n    - **`sfxPause: boolean`**  sfx是否暂停，暂停时不暂停ui音效\r\n\r\n- **方法**\r\n    - **`playBgm(args: cc.AudioClip | AudioPlayArgs)`**  播放bgm\r\n    - **`playSfx(args: cc.AudioClip | AudioPlayArgs, type: SfxType = SfxType.NORMAL)`**  播放sfx\r\n    - **`setSfxData(clip: cc.AudioClip, type: SfxType = SfxType.NORMAL, maxNum: number = 8, overStop: boolean = false): SfxData`**  设置音效数据（用于限制某些短时间内同时大量播放的音效）\r\n    - **`stopBgm(clip: cc.AudioClip = null, fadeDuration: number = 0)`**  停止bgm\r\n    - **`stopSfx(clip: cc.AudioClip = null, type: SfxType = SfxType.NORMAL)`**  停止sfx\r\n    - **`stopAll()`**  停止所有音频\r\n    - **`pauseAll()`**  暂停所有音频\r\n    - **`resumeAll()`**  恢复所有音频\r\n    - **`uncacheAll()`**  停止所有音频，清除所有音频缓存\r\n\r\n#### \u003ca id=\"framework-i18n\"\u003e\u003c/a\u003e多语言\r\n\u003e文件路径(scripts/common/util/I18n.ts)\r\n\r\n支持文字以及图片的多语言切换，不同语言的同一图片需命名一致，配置路径如下，如需更改配置路径请自行更换。详见工程示例\r\n\r\n\u003eUI组件路径: scripts/common/cmpt/ui/i18n/\r\n\r\n\u003e语言表路径：scripts/common/config/En.ts和scripts/common/config/Zh.ts\r\n\r\n\u003e图片路径：resources/textures/localizedImage/en/和resources/textures/localizedImage/zh/\r\n\r\n\r\n如果需要替换字符串中的占位符（形如\"**%{xxx}**\"的字符串为占位符），支持以下两种不同的传参形式来获取替换后的字符串\r\n```typescript\r\n// 语言表 {\"test\": \"test %{arg1} %{arg2} !!!\"}\r\nI18n.getText(\"test\", {arg1: \"somthing\", arg2: 2}); // =\u003e \"test somthing 2 !!!\"\r\nI18n.getText(\"test\", \"somthing\", 2); // =\u003e \"test somthing 2 !!!\"\r\n```\r\n\r\n- **属性**\r\n    - **`curLang: LangType`**  当前语言类型\r\n\r\n- **方法**\r\n    - **`init(language: LangType = LangType.NONE)`**  初始化语言\r\n    - **`switch(language: LangType)`**  切换语言\r\n    - **`updateLocalizedCmpt()`**  更新所有多语言组件\r\n    - **`getKeyByValue(value: string): string`**  通过语言表value获取对应的key\r\n    - **`getText(key: string, ...option: [{ [k: string]: string | number }] | Array\u003cstring | number\u003e): string`**  通过key获取语言表中的字符串\r\n\r\n\r\n#### \u003ca id=\"framework-ui\"\u003e\u003c/a\u003e常用ui组件\r\n\u003e文件路径(scripts/common/cmpt/)\r\n- **VirtualList** 虚拟列表，仅生成视图区域内所需的最少节点，且支持节点分层\r\n\r\n- **LoopList** 无限循环列表/轮播图\r\n\r\n- **CircleList** 环形列表，将节点以椭圆排列\r\n\r\n- **AnimValue** 渐变动画组件基类，可基于此组件实现各种数值渐变动画\r\n    - **AnimValueLabel** 数字渐变动画组件\r\n    - **AnimValueProgress** 进度条渐变动画组件\r\n    - **AnimValueProgressHP** 游戏血条组件\r\n\r\n- 按钮组件\r\n    - **ButtonSingle** 按钮分组，阻止同一分组内的多个按钮同时点击\r\n    - **ButtonChildPos** 根据按钮状态改变子节点的坐标\r\n    - **ButtonChildGray** 根据按钮状态将子节点置灰\r\n\r\n- 资源管理组件，结合[资源管理器](#framework-res)，自动管理动态加载的资源引用计数\r\n    - **ResSpine**\r\n    - **ResSprite**\r\n\r\n- **MultiSprite** 基于Multi-Texture\u003csup\u003e[[1]](#reference1)\u003c/sup\u003e实现的渲染组件，支持多图集合批，需通过**MultiTextureManager**管理合批的纹理\r\n    - 兼容web与native\r\n    - 支持Sprite的simple、sliced、tiled、filled渲染类型\r\n    - 支持Cocos自动图集与动态合图的纹理\r\n    - 支持动态修改合批的纹理--**MultiTextureManager.setTexture(idx: number, tex: cc.Texture2D)**\r\n\r\n- ......\r\n\r\n#### \u003ca id=\"framework-tool\"\u003e\u003c/a\u003e常用工具类\r\n\u003e文件路径(scripts/common/util/)\r\n- **Tool** 常用工具方法\r\n- **Decorator** 装饰器\r\n\r\n#### \u003ca id=\"framework-hack\"\u003e\u003c/a\u003e引擎源码hack\r\n\u003e文件路径(scripts/common/hack/)\r\n\r\n#### \u003ca id=\"framework-shader\"\u003e\u003c/a\u003e几个shader\r\n\u003e文件路径(res/shader/)\r\n\r\n## \u003ca id=\"name\"\u003e\u003c/a\u003e命名规范\r\n- 文件夹使用小驼峰 files\r\n- 文件名使用大驼峰 File.ts\r\n- 类名使用大驼峰 FileClass\r\n- 属性名、函数名使用小驼峰 func\r\n- 枚举\r\n```\r\nenum LangType {\r\n    NONE = \"\",\r\n    ZH = \"zh\",\r\n    EN = \"en\"\r\n}\r\n```\r\n- 字符串尽量使用双引号\r\n\r\n## \u003ca id=\"reference\"\u003e\u003c/a\u003e参考资料\r\n1. \u003ca id=\"reference1\"\u003e\u003c/a\u003ehttps://forum.cocos.org/t/topic/121618\r\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleeyip%2Fcocos-framework","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fleeyip%2Fcocos-framework","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleeyip%2Fcocos-framework/lists"}