diff --git a/README.md b/README.md index aaff06c..c0f3534 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ -# cocos游戏轻量级框架 +# cocos 轻量级游戏框架 [![996.icu](https://img.shields.io/badge/link-996.icu-red.svg)](https://996.icu) [![blog](https://img.shields.io/badge/blog-game--develop--road-yellow.svg)](https://www.yuque.com/fengyong/game-develop-road) -![](https://img.shields.io/badge/Cocos--Creator-2.1.3-blue) +![](https://img.shields.io/badge/Cocos--Creator-2.2.1-blue) +![](https://img.shields.io/badge/框架版本-1.0.0-blue) +![](https://img.shields.io/badge/脚本语言-TypeScript-blue) ## 说明 * 以个人实践为主,有些方案并非是最佳实践。我刚入门游戏开发,还在不断学习中。 @@ -10,64 +12,56 @@ ## 使用方法 * 拷贝整个项目作为基础使用。 -* 单文件直接使用,文件依赖参考文件头部import部分。针对3种特殊的依赖: - 1. G,在 g-global.ts 中找到对应的方法,拷贝。 - 2. FMLog,使用 cc.log 代替,或者使用自定义的 log 方法。 - 3. FMVersion,使用 true/false 代替,或者直接删除,或者使用自定义的版本判定方法。 -* 思路参考,某些处理并非是最优解,但是提供了一个还算不错的思路可以参考。 +* 拷贝框架层所有文件并放入到现有项目中。推荐使用此方式,在框架层升级时可以直接替换。 +* 拷贝单个文件并放入到现有项目中。 +* 参考某些功能的实现方式,在现有项目中自己实现。 ## 文件说明 -- [**`App`**] 游戏启动唯一主入口 -- [**`G`**] 通用方法 -- [**F系列脚本**] 框架层 - - [**`FAnima`**] 动画 - - [**`FColor`**] 颜色数据存储;绑定数据文件 data/color.ts - - [**`FHttp`**] 网络交互 - - [**`FLocal`**] 本地存储;绑定数据文件 data/local.ts - - [**`FLog`**] 日志 - - [**`FPanel`**] 界面 - - [**`FSound`**] 声音;绑定数据文件 data/suond.ts - - [**`FText`**] 文字数据;绑定数据文件 data/text-*.ts - - [**`FVersion`**] 游戏版本 -- [**T系列脚本**] 工具层,一些独立的功能脚本 - - [**`TChild`**] 子节点组合 - - [**`TColor`**] 绑定颜色 - - [**`TSize`**] 修改大小 - - [**`TText`**] 绑定文字 - - [**`TZIndex`**] 修改节点渲染顺序 -- [**data系列脚本**] 数据文件 -- [**C系列脚本**] controller 的缩写,表示控制器脚本 -- [**S系列脚本**] system 的缩写,表示系统脚本 -- [**Panel系列脚本**] 每个界面下挂载的默认脚本 +- **`App`** 游戏启动唯一主入口 +- 框架层 + - **`FColor`** 颜色数据模块 + - **`FHttp`** 网络模块(未完整实现) + - **`FLocal`** 本地存储模块 + - **`FMeta`** 游戏数据表模块 + - **`FNodeStateAnima`** 节点动画状态模块 + - **`FPanel`** 界面模块 + - **`FSound`** 声音模块 + - **`FState`** 状态工具 + - **`FText`** 文字模块(多语言) + - **`FTool`** 封装一些常用的方法 + - **`Fversion`** 版本管理模块 +- 业务层 + - **`T*`** 一些常用的工具脚本 + - **`Data*`** 一些配置数据 + - **`Meta*`** 数据表脚本 + - **`Panel*`** 界面脚本 + - **`C*`** Controller 脚本,一般需要继承 cc.Component,进行游戏逻辑的处理 + - **`S*`** System 脚本,一般不继承 cc.Component,进行游戏数据的处理 -## 规范(仅针对 typescript) +## 规范 ### 命名规范(大驼峰,小驼峰,下划线,连接符) -* 类名/模块名使用大驼峰,文件名与文件中主类(主模块)相同。 -* 常量使用下划线+大写字母 -* 变量/方法使用下划线+小写字母。(本项为了与引擎自带方法区分开,如果引擎使用下划线+小写字母命名,则本项使用小驼峰) -* typescript 中的 enum/interface/type 使用大驼峰,并且利用前缀进行含义说明: - * Type* 表示类型 - * Params* 表示参数(不论入参还是出参) +* 类名、模块名使用大驼峰。文件名需要与文件中的主类、主模块名相同。 +* 常量名使用下划线+大写字母。 +* 变量名、方法名使用下划线+小写字母。本项为了与引擎自带方法区分开,如果引擎使用下划线+小写字母命名,则本项使用小驼峰。 +* enum、interface、type 使用大驼峰,并且利用前缀进行含义说明: + * Type* 表示类型。 + * Params* 表示参数(不论入参还是出参)。 * Data* 表示数据。 -* 最多使用 1 个前缀表示大类别,其余用后缀表示。 - * anima_*,表示动画函数的前缀。 - * *_btn,表示组件类型的后缀,类似的还有 _label/_sp 等。 - * *_list,表示数据结构的后缀。(不要使用复数命名,使用单数对应的数据结构如 array/list/set/map 等) -* 保证命名的统一性:如介词的使用(本项目中使用 to 和 by,其中 to 后面接输出值,by 后面接输入值),前缀,后缀,系统名等。 +* 保证命名的统一性 + * 介词的使用,在本项目中,to 后接输出,by 后接输入。 + * 前缀,后缀,系统名等。 ### 代码规范 -* 代码次序为:import/cc._decorator,C(静态数据),enum/interface/type,main-class/main-namespace -* 使用字符串枚举而不是数字枚举。不要使用 enum/cc.Enum,或者其他数字枚举,数字枚举再描述性上非常差。 -* 使用 export 而不是 export default。 -* 使用 module(export namespace)而不是 namespace。 -* 使用 module(export namespace)而不是 class 中的 static 方法。 -* 在 class 中,对于不需要外部调用的属性和方法,使用 private 而不是 public。 -* 在 module 中,不要轻易使用 export。 +* 代码次序为:import,cc._decorator,C(静态数据),enum,interface,type,main namespace,main class。 +* 使用「字符串字面量类型」或者「常量枚举类型」而不是「枚举类型」。因为前者在编译后会删除,后者则不会。 +* 使用「export」而不是「export default」。 +* 使用「export namespace」而不是「namespace」或者「类的静态方法」。 +* 在类中,优先使用「private」而不是「public」。 * 在函数内部使用箭头函数而不是 function。外部函数定义可以使用 function。 * 使用 forEach 或者其他高阶方法遍历而不是 for 循环。(for 循环的性能最高,在大数组遍历时可以使用)(高阶方法参考:https://www.yuque.com/fengyong/game-develop-road/gwv8xo ) * 避免在遍历时添加 break 和 return 逻辑,这样做会影响循环的语义性。 * 避免对 object 类型的遍历,如果不可避免,则通过 Object.keys 方法转化为数组后遍历。 * 使用双引号,反引号,而不是单引号。 ### 架构规范 -* 极力避免对底层/中台进行修改,使用底层代码 + 数据配置文件的方案进行规避。(参考 FColor/FText/FSound) +* 保证框架层的独立性,避免在框架层中直接写入数据。(参考 FColor 与 DataColor)。 * 数据与显示分离,数据优于显示。(参考:https://www.yuque.com/fengyong/game-develop-road/toqqxe ) * 唯有设计上的统一性才能保证架构上的统一性,切记! diff --git a/assets/resources/panel/PanelExample.prefab b/assets/resources/panel/PanelExample.prefab index 0e63cb7..c800c36 100644 --- a/assets/resources/panel/PanelExample.prefab +++ b/assets/resources/panel/PanelExample.prefab @@ -25,7 +25,6 @@ } ], "_active": true, - "_level": 1, "_components": [ { "__id__": 8 @@ -52,17 +51,6 @@ "x": 0.5, "y": 0.5 }, - "_eulerAngles": { - "__type__": "cc.Vec3", - "x": 0, - "y": 0, - "z": 0 - }, - "_skewX": 0, - "_skewY": 0, - "_is3DNode": false, - "groupIndex": 0, - "_id": "", "_trs": { "__type__": "TypedArray", "ctor": "Float64Array", @@ -78,7 +66,19 @@ 1, 1 ] - } + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "" }, { "__type__": "cc.Node", @@ -89,7 +89,6 @@ }, "_children": [], "_active": true, - "_level": 2, "_components": [ { "__id__": 3 @@ -116,17 +115,6 @@ "x": 0.5, "y": 0.5 }, - "_eulerAngles": { - "__type__": "cc.Vec3", - "x": 0, - "y": 0, - "z": 0 - }, - "_skewX": 0, - "_skewY": 0, - "_is3DNode": false, - "groupIndex": 0, - "_id": "", "_trs": { "__type__": "TypedArray", "ctor": "Float64Array", @@ -142,7 +130,19 @@ 1, 1 ] - } + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "" }, { "__type__": "cc.Sprite", @@ -196,7 +196,6 @@ }, "_children": [], "_active": true, - "_level": 2, "_components": [ { "__id__": 6 @@ -223,17 +222,6 @@ "x": 0.5, "y": 0.5 }, - "_eulerAngles": { - "__type__": "cc.Vec3", - "x": 0, - "y": 0, - "z": 0 - }, - "_skewX": 0, - "_skewY": 0, - "_is3DNode": false, - "groupIndex": 0, - "_id": "", "_trs": { "__type__": "TypedArray", "ctor": "Float64Array", @@ -249,7 +237,19 @@ 1, 1 ] - } + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "" }, { "__type__": "cc.Label", diff --git a/assets/scene/MainScene.fire b/assets/scene/MainScene.fire index 5c2b9ea..0cb479e 100644 --- a/assets/scene/MainScene.fire +++ b/assets/scene/MainScene.fire @@ -18,7 +18,6 @@ } ], "_active": false, - "_level": 0, "_components": [], "_prefab": null, "_opacity": 255, @@ -39,16 +38,6 @@ "x": 0, "y": 0 }, - "_quat": { - "__type__": "cc.Quat", - "x": 0, - "y": 0, - "z": 0, - "w": 1 - }, - "groupIndex": 0, - "autoReleaseAssets": false, - "_id": "2d2f792f-a40c-49bb-a189-ed176a246e49", "_trs": { "__type__": "TypedArray", "ctor": "Float64Array", @@ -60,11 +49,16 @@ 0, 0, 1, - 0.5132042253521127, - 0.5132042253521127, + 1, + 1, 1 ] - } + }, + "_is3DNode": true, + "_groupIndex": 0, + "groupIndex": 0, + "autoReleaseAssets": false, + "_id": "2d2f792f-a40c-49bb-a189-ed176a246e49" }, { "__type__": "cc.Node", @@ -85,7 +79,6 @@ } ], "_active": true, - "_level": 1, "_components": [ { "__id__": 10 @@ -113,17 +106,6 @@ "x": 0.5, "y": 0.5 }, - "_quat": { - "__type__": "cc.Quat", - "x": 0, - "y": 0, - "z": 0, - "w": 1 - }, - "_skewX": 0, - "_skewY": 0, - "groupIndex": 0, - "_id": "a286bbGknJLZpRpxROV6M94", "_trs": { "__type__": "TypedArray", "ctor": "Float64Array", @@ -139,7 +121,19 @@ 1, 1 ] - } + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "a286bbGknJLZpRpxROV6M94" }, { "__type__": "cc.Node", @@ -150,7 +144,6 @@ }, "_children": [], "_active": true, - "_level": 1, "_components": [ { "__id__": 4 @@ -175,24 +168,13 @@ "x": 0.5, "y": 0.5 }, - "_quat": { - "__type__": "cc.Quat", - "x": 0, - "y": 0, - "z": 0, - "w": 1 - }, - "_skewX": 0, - "_skewY": 0, - "groupIndex": 0, - "_id": "d8CA3aalFJ3rgnixzejbpA", "_trs": { "__type__": "TypedArray", "ctor": "Float64Array", "array": [ 0, 0, - 0, + 340.3479836872844, 0, 0, 0, @@ -201,7 +183,19 @@ 1, 1 ] - } + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "d8CA3aalFJ3rgnixzejbpA" }, { "__type__": "cc.Camera", @@ -223,6 +217,20 @@ "_depth": -1, "_zoomRatio": 1, "_targetTexture": null, + "_fov": 60, + "_orthoSize": 10, + "_nearClip": 1, + "_farClip": 4096, + "_ortho": true, + "_rect": { + "__type__": "cc.Rect", + "x": 0, + "y": 0, + "width": 1, + "height": 1 + }, + "_renderStages": 1, + "_alignWithScreen": true, "_id": "90IZrUddZNB7ONSEFu5k7V" }, { @@ -234,7 +242,6 @@ }, "_children": [], "_active": true, - "_level": 0, "_components": [ { "__id__": 6 @@ -265,17 +272,6 @@ "x": 0.5, "y": 0.5 }, - "_quat": { - "__type__": "cc.Quat", - "x": 0, - "y": 0, - "z": 0, - "w": 1 - }, - "_skewX": 0, - "_skewY": 0, - "groupIndex": 0, - "_id": "58fgEQo0FMOZD/jQgbaogA", "_trs": { "__type__": "TypedArray", "ctor": "Float64Array", @@ -291,7 +287,19 @@ 1, 1 ] - } + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "58fgEQo0FMOZD/jQgbaogA" }, { "__type__": "cc.Sprite", @@ -301,6 +309,11 @@ "__id__": 5 }, "_enabled": true, + "_materials": [ + { + "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" + } + ], "_srcBlendFactor": 770, "_dstBlendFactor": 771, "_spriteFrame": { @@ -317,7 +330,6 @@ "_fillStart": 0, "_fillRange": 0, "_isTrimmedMode": true, - "_state": 0, "_atlas": null, "_id": "bdUJAoweBO07hcM1h0huz2" }, @@ -370,7 +382,6 @@ }, "_children": [], "_active": true, - "_level": 0, "_components": [], "_prefab": null, "_opacity": 255, @@ -391,17 +402,6 @@ "x": 0.5, "y": 0.5 }, - "_quat": { - "__type__": "cc.Quat", - "x": 0, - "y": 0, - "z": 0, - "w": 1 - }, - "_skewX": 0, - "_skewY": 0, - "groupIndex": 0, - "_id": "46U33is7JKLL0T893RDKMI", "_trs": { "__type__": "TypedArray", "ctor": "Float64Array", @@ -417,7 +417,19 @@ 1, 1 ] - } + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "46U33is7JKLL0T893RDKMI" }, { "__type__": "cc.Canvas", diff --git a/assets/script/data/DataColor.ts b/assets/script/data/DataColor.ts index e844bda..ad03153 100644 --- a/assets/script/data/DataColor.ts +++ b/assets/script/data/DataColor.ts @@ -2,20 +2,20 @@ export const DataColor = { // 默认颜色 - "none": cc.Color.WHITE, + "none": "#ffffff", // ant-design-cyan-6-10 - "cyan_6": cc.color().fromHEX("#13c2c2"), - "cyan_7": cc.color().fromHEX("#08979c"), - "cyan_8": cc.color().fromHEX("#006d75"), - "cyan_9": cc.color().fromHEX("#00474f"), - "cyan_10": cc.color().fromHEX("#002329"), + "cyan-6": "#13c2c2", + "cyan-7": "#08979c", + "cyan-8": "#006d75", + "cyan-9": "#00474f", + "cyan-10": "#002329", // ant-design-volcano-6-10 - "volcano_6": cc.color().fromHEX("#fa541c"), - "volcano_7": cc.color().fromHEX("#d4380d"), - "volcano_8": cc.color().fromHEX("#ad2102"), - "volcano_9": cc.color().fromHEX("#871400"), - "volcano_10": cc.color().fromHEX("#610b00"), + "volcano-6": "#fa541c", + "volcano-7": "#d4380d", + "volcano-8": "#ad2102", + "volcano-9": "#871400", + "volcano-10": "#610b00", } diff --git a/assets/script/data/DataSound.ts b/assets/script/data/DataSound.ts index a63f54d..b05f0c5 100644 --- a/assets/script/data/DataSound.ts +++ b/assets/script/data/DataSound.ts @@ -4,7 +4,7 @@ */ export const DataSound = { - "bgm": ["test", 1, true], + "bgm": ["sound/test", 1, true], - "btn": ["test"] + "btn": ["sound/test"] } diff --git a/assets/script/data/DataTextEn.ts b/assets/script/data/DataTextEn.ts index 3c4c4c3..484e131 100644 --- a/assets/script/data/DataTextEn.ts +++ b/assets/script/data/DataTextEn.ts @@ -3,9 +3,5 @@ import { DataTextZh } from "./DataTextZh"; /** 文字的数据,英文 */ export const DataTextEn: typeof DataTextZh = { - "panel_loading_game_info": "{0}\nCreated by {1}\nV {2} @{3}", - - "panel_message_title": "Message", - "panel_message_yes": "Yes", - "panel_message_no": "No", + "none": "", } diff --git a/assets/script/data/DataTextZh.ts b/assets/script/data/DataTextZh.ts index a45246c..ea2d8e9 100644 --- a/assets/script/data/DataTextZh.ts +++ b/assets/script/data/DataTextZh.ts @@ -1,9 +1,5 @@ /** 文字的数据,中文 */ export const DataTextZh = { - "panel_loading_game_info": "游戏名称:{0}\n开发者:{1}\n版本号:{2}-{3}", - - "panel_message_title": "消息", - "panel_message_yes": "是", - "panel_message_no": "否", + "none": "", } diff --git a/assets/script/framework/FColor.ts b/assets/script/framework/FColor.ts index be38f26..8d4f055 100644 --- a/assets/script/framework/FColor.ts +++ b/assets/script/framework/FColor.ts @@ -1,25 +1,25 @@ import { DataColor } from "../data/DataColor" -/** 所有颜色的key */ -type TypeColorKey = keyof typeof DataColor - /** - * [framework] 颜色数据管理 - * - [注意] 需要在数据源文件中实现 DataColor 和 DataColorKey。 - * - [参考资料] Ant-design推荐的颜色设计:https://ant.design/docs/spec/colors-cn + * 颜色数据模块 + * - *注意* 需要在数据源文件中实现 DataColor。 + * - *参考资料* Ant-design 推荐的颜色设计:https://ant.design/docs/spec/colors-cn。 */ export namespace FColor { + /** 所有颜色的 key */ + type TypeColorKey = keyof typeof DataColor + /** * 获取颜色 * @param color_key */ export function get_color(color_key: TypeColorKey): cc.Color { - let result = DataColor[color_key] - if (!result) { - cc.warn(`@FColor: color-key不存在, key=${color_key}`) + try { + return cc.color().fromHEX(DataColor[color_key]) + } catch (error) { + cc.warn(`@FColor: 获取color失败,key=${color_key},error=${error}`) } - return result } } diff --git a/assets/script/framework/FHttp.ts b/assets/script/framework/FHttp.ts index 8925380..1665200 100644 --- a/assets/script/framework/FHttp.ts +++ b/assets/script/framework/FHttp.ts @@ -1,10 +1,6 @@ /** - * [framework] 网络连接 - * - [用法] 这里只是给出了一个样例,实际使用中http请求需要更加定制化 - * - [注意] 考虑await无法对reject()进行处理,需要进行try-catch封装,并在catch中返回null - * - [注意] 需要处理浏览器跨域请求;如果是cros方案,需要后端(目标url)进行配合才可以实现 - * - [注意] GET方法不允许包含body,只允许包含query - * - [注意] body的类型建议前后端使用interface进行约束 + * 网络连接模块 + * - 未完整实现,这里只是一个示例。 */ export namespace FHttp { diff --git a/assets/script/framework/FLocal.ts b/assets/script/framework/FLocal.ts index 7f997d2..6e6783e 100644 --- a/assets/script/framework/FLocal.ts +++ b/assets/script/framework/FLocal.ts @@ -1,27 +1,21 @@ import { DataLocal } from "../data/DataLocal"; import { FVersion } from "./FVersion"; -/** 本地数据key */ -type TypeLocalKey = keyof typeof DataLocal - /** - * [framework] 本地数据存储(统一管理) - * - [注意] key不能重复 - * - [注意] 当没有key的对应值时,会返回null - * - [注意] cc.sys.localStorage.getItem返回值为string或者null,在缓存中也是 - * - [特别注意] 考虑cc.sys.localStorage相应方法的的消耗(特别是针对微信小游戏平台的,还需要减少同步次数),新增2种解决方案 - * - 1.建立缓存结构 - * - 2.采用异步Promise封装存储过程(可能存在的问题是:在退出游戏时存储可能会导致游戏存储失败) + * 本地存储模块 + * - *注意* 返回值均为 string 或者 null。 */ export namespace FLocal { - /** 缓存;加快存储的效率,均存储为string格式 */ + /** 本地数据 key */ + type TypeLocalKey = keyof typeof DataLocal + + /** 缓存 */ let cache_map: Map = new Map() + /** 初始化,如果是开发版本则一直初始化 */ export function init_local_data() { - // 预处理 FVersion.get_version().has_state("dev") && set("init", `${false}`) - // 正式处理 if (get("init") === `${true}`) { cc.log("@FLocal: 已获取用户本地数据") } else { @@ -31,17 +25,14 @@ export namespace FLocal { } } - /** 获取:优先从缓存中获取 */ + /** 获取,顺序为:缓存,本地存储,配置的默认值 */ export function get(key: TypeLocalKey): string { - let value = cache_map.get(key) - if (value === undefined) { - value = cc.sys.localStorage.getItem(key) || `${DataLocal[key]}` - cache_map.set(key, value) - } + let value = cache_map.get(key) || cc.sys.localStorage.getItem(key) || `${DataLocal[key]}` + cache_map.set(key, value) return value } - /** 设置 */ + /** 存储 */ export function set(key: TypeLocalKey, value: string) { cache_map.set(key, value) Promise.resolve().then(() => { diff --git a/assets/script/framework/FMeta.ts b/assets/script/framework/FMeta.ts index 7b97a7e..78021ee 100644 --- a/assets/script/framework/FMeta.ts +++ b/assets/script/framework/FMeta.ts @@ -3,25 +3,24 @@ import { FState } from "./FState" /** * 数据配置表模块 - * 1. 使用csv文件作为源文件,1个meta类可以对应多个csv文件,注意处理属性名冲突 - * 2. 使用简化的csv格式: - * - 以#开头的行视为注释行,不解析 - * - 以@开头的行视为属性行,存储属性名称 - * - 只解析到string类型,在on_load方法中进一步处理类型 - * - 使用##代替字符串中的逗号 - * - 空白则表示此值为当前行的id + * 1. 使用 csv 文件作为源文件,1 个 Meta 类可以对应多个 csv 文件,注意处理属性名冲突。 + * 2. 使用简化的 csv 格式: + * - 以 # 开头的行视为注释行,不解析 + * - 以 @ 开头的行视为属性行,存储属性名称 + * - 使用 ## 代替字符串中的逗号 + * - 空白则表示此值为当前行的 id * 3. 一些命名 - * - file_source 1张数据表的源内容 - * - metas 1张数据表上的全部内容(使用Meta类封装) - * - meta 1张数据表上单行的内容(使用Meta类封装) + * - file_source:1 张数据表的源内容 + * - metas:1 张数据表上的全部内容,使用 Meta 类封装 + * - meta:1 张数据表上单行的内容,使用 Meta 类封装 */ export namespace FMeta { - /** 完整的csv文件 */ - interface Csv { [K: string]: CsvLine } + /** 完整的 csv 文件 */ + type Csv = Map - /** 单行csv */ - export interface CsvLine { [K: string]: string } + /** 单行 csv */ + export type CsvLine = Map /** * meta类的状态 @@ -31,9 +30,9 @@ export namespace FMeta { */ type MetaState = "prepare" | "ok" | "error" - /** meta的基础抽象类 */ + /** meta 的基础抽象类 */ export class MetaBase { - /** meta类的上下文信息 */ + /** meta 类的上下文信息 */ static context: { // 源文件路径表 file_path_list: string[] @@ -42,12 +41,14 @@ export namespace FMeta { // 状态 state: FState.StateJumpTable } = null - /** 创建meta类实例时,对传入的单行源数据进行处理 */ + /** 创建 meta 类实例时,对传入的单行源数据进行处理 */ on_load(source: CsvLine): void { } } - /** 设置MetaContext的装饰器函数 */ - export function SetMetaContext(config: { file_path_list: string[] }) { + /** 设置 meta 类上下文的装饰器函数 */ + export function SetMetaContext(config: { + file_path_list: string[] + }) { return (constructor: typeof MetaBase) => { constructor.context = { file_path_list: config.file_path_list, @@ -56,31 +57,34 @@ export namespace FMeta { "ok": [], "error": [], }, "prepare"), - file_source: null, + file_source: new Map(), } // 非编辑器模式下,载入资源 !CC_EDITOR && Promise.all(config.file_path_list.map(v => load_csv(v))) .then(csv_list => { constructor.context.file_source = merge_csv(...csv_list) constructor.context.state.try_change_state("ok") - cc.log(`@FMeta: load meta ok, class=${constructor.name}`) + cc.log(`@FMeta: 载入meta数据成功, class=${constructor.name}, data=`, constructor.context.file_source) }) .catch(error => { constructor.context.state.try_change_state("error") - cc.error(`@FMeta: load meta error, class=${constructor.name}, error=${error}`) + cc.error(`@FMeta: 载入meta数据失败, class= ${constructor.name}, error = ${error} `) }) } } /** 一些判定正则 */ const REGEX = { - COMMENT_LINE: /^#/, // 注释行 - PROPERTY_LINE: /^@/, // 属性行 - COMMA: /##/g, // 逗号 + // 注释行 + COMMENT_LINE: /^#/, + // 属性行 + PROPERTY_LINE: /^@/, + // 逗号 + COMMA: /##/g, } /** - * 载入单个csv文件 + * 载入单个 csv 文件 * @param file_path */ async function load_csv(file_path: string): Promise { @@ -89,7 +93,7 @@ export namespace FMeta { // 属性名称数组 let property_name_list: string[] = [] // 处理结果 - let csv: Csv = {} + let csv: Csv = new Map() // 处理过程 line_list.forEach(line => { if (line === null || line.trim().length === 0) { @@ -102,51 +106,50 @@ export namespace FMeta { } else { // 内容行 let block_list = line.split(",") - let id = Number.parseInt(block_list[0]) - let csv_line: CsvLine = {} - block_list.forEach((block, index) => { - block = block.trim().length === 0 ? `${id}` : block // 替换empty为id - block = block.replace(REGEX.COMMA, ",") // 替换##为逗号 - let property_name = property_name_list[index] - csv_line[property_name] = block - }) - csv[id] = csv_line + let id = block_list[0] + let csv_line: CsvLine = new Map(block_list.map((block, index) => { + // 替换 empty 为 id + block = block.trim().length === 0 ? `${id} ` : block + // 替换##为逗号 + block = block.replace(REGEX.COMMA, ",") + return [property_name_list[index], block] + })) + csv.set(id, csv_line) } }) return csv } /** - * 合并多个csv文件 + * 合并多个 csv 文件 * @param csv_list */ function merge_csv(...csv_list: Csv[]): Csv { - let all_csv: Csv = {} + let all_csv: Csv = new Map() csv_list.forEach(csv => { - Object.keys(csv).forEach(id => { - if (!all_csv[id]) { all_csv[id] = {} } - Object.assign(all_csv[id], csv[id]) + csv.forEach((csv_line, id) => { + all_csv.set(id, new Map([...all_csv.has(id) ? all_csv.get(id) : [], ...csv_line])) }) }) return all_csv } /** - * 获取单个的meta + * 获取单个的 meta * @param meta_class * @param id */ - export function get_meta(meta_class: T, id: string | number): InstanceType { + export function get_meta(meta_class: T, id: string): InstanceType { let meta = new meta_class() - meta.on_load(meta_class.context.file_source[id]) + meta.on_load(meta_class.context.file_source.get(id)) return meta as any } /** - * 获取meta数组 + * 获取 meta 数组 * @param meta_class */ export function get_metas(meta_class: T): InstanceType[] { - return Object.keys(meta_class.context.file_source).map(id => get_meta(meta_class, id)) + return [...meta_class.context.file_source.keys()].map(id => get_meta(meta_class, id)) } } diff --git a/assets/script/framework/FNodeStateAnima.ts b/assets/script/framework/FNodeStateAnima.ts index ded4472..2875ab3 100644 --- a/assets/script/framework/FNodeStateAnima.ts +++ b/assets/script/framework/FNodeStateAnima.ts @@ -1,12 +1,11 @@ /** - * [T] 节点状态管理工具 - * - 用于绑定节点状态信息。 - * - 节点状态信息保存在node下。 + * 节点状态动画模块 + * - 用于绑定节点状态信息,保存在 node 下。 * - 通过传入动画参数,执行从一个状态到另一个状态的动画。 */ export namespace FNodeStateAnima { - /** 保存在node上的key */ + /** 保存在 node 上的 key */ const SAVE_KEY = Symbol() /** @@ -40,9 +39,9 @@ export namespace FNodeStateAnima { * @param params 动画参数 */ export async function anima(node: cc.Node, to: string, params: { - time?: number; // 时间,默认为0.3 - delay?: number; // 延迟,默认为0 - ease?: cc.tweenEasing; // ease函数,默认为linear + time?: number; // 时间,默认为 0.3 + delay?: number; // 延迟,默认为 0 + ease?: cc.tweenEasing; // ease 函数,默认为 linear }) { try { if (params.time === undefined) { params.time = 0.3 } diff --git a/assets/script/framework/FPanel.ts b/assets/script/framework/FPanel.ts index b769ee9..746bcac 100644 --- a/assets/script/framework/FPanel.ts +++ b/assets/script/framework/FPanel.ts @@ -2,9 +2,9 @@ import { FTool } from "./FTool"; import { FState } from "./FState"; /** - * [framework] 游戏窗口管理 - * - [注意] 需要在App中实例化,需要传入parent-node - * - [设计要求] 在设计上要求单个界面只允许存在一个实例;如果有需要打开多个的界面,可以转化为界面下打开多个组件 + * 界面模块 + * - *注意* 需要在 App 中实例化,传入 parent-node + * - *设计要求* 在设计上要求单个界面只允许存在一个实例;如果有需要打开多个的界面,可以转化为界面下打开多个组件 */ export namespace FPanel { @@ -13,12 +13,9 @@ export namespace FPanel { * - open 打开 * - close 关闭 */ - type PanelState = "open" | "close" + type PanelState = "prepare" | "ok" | "error" | "open" | "close" - /** - * 界面脚本的实现类 - * - 注意使用implements而不是extends,因为二者没有明显的父子关系 - */ + /** 界面脚本的实现基类 */ export abstract class PanelBase extends cc.Component { /** 界面的上下文信息 */ @@ -42,45 +39,44 @@ export namespace FPanel { abstract async on_close(...params: any): Promise; } - /** 获取类 on_open 方法的参数 */ - type GetParamsOpen = Parameters - - /** 获取类 on_close 方法的参数 */ - type GetParamsClose = Parameters - /** - * 设置PanelContext的装饰器 - * @param context + * 设置 panel 类上下文的装饰器 + * @param config */ - export function SetPanelContext(context: { + export function SetPanelContext(config: { path: string, z_index_base?: number, }) { return (constructor: typeof PanelBase) => { constructor.context = { - path: context.path, - z_index_base: context.z_index_base || 0, + path: config.path, + z_index_base: config.z_index_base || 0, prefab: null, state: new FState.StateJumpTable({ + "prepare": ["ok", "error"], + "ok": ["open"], + "error": [], "open": ["close"], "close": ["open"], - }, "close"), + }, "prepare"), ins: null, } + // 非编辑器模式下,载入 prefab + !CC_EDITOR && FTool.load_res(constructor.context.path, cc.Prefab).then(v => { + constructor.context.prefab = v + constructor.context.state.try_change_state("ok") + }) } } - /** prefab的基础的父节点 */ - const PATH = "Panel" - /** 父节点 */ let parent: cc.Node = null - /** 当前的zindex */ + /** 当前的 zindex */ let now_z_index: number = 0 /** - * 初始化系统,传入parent-node + * 初始化系统,传入 parent-node * @param node */ export function init_parent(node: cc.Node) { @@ -88,12 +84,13 @@ export namespace FPanel { } /** - * 载入界面的prefab + * 载入界面的 prefab + * - 暂时没有使用到 * @param panel */ - export async function load(panel: typeof PanelBase) { + async function load(panel: typeof PanelBase) { if (!panel.context.prefab) { - panel.context.prefab = await FTool.load_res(`${PATH}/${panel.context.path}`, cc.Prefab) + panel.context.prefab = await FTool.load_res(panel.context.path, cc.Prefab) } } @@ -102,14 +99,15 @@ export namespace FPanel { * @param panel * @param params */ - export async function open(panel: T, ...params: GetParamsOpen) { + export async function open(panel: T, ...params: Parameters) { // 校验 if (!panel.context.state.try_change_state("open")) { return } let z_index = now_z_index += 1 + // 暂时更换了载入方式,所以这些是不需要的 // 载入 - await load(panel) + // await load(panel) // 二次校验,如果载入完成后,panel状态已经不为open,则跳过创建 - if (!panel.context.state.try_change_state("open")) { return } + // if (!panel.context.state.try_change_state("open")) { return } let node = cc.instantiate(panel.context.prefab) node.parent = parent node.position = cc.Vec2.ZERO @@ -128,7 +126,7 @@ export namespace FPanel { * @param panel * @param params */ - export async function close(panel: T, ...params: GetParamsClose) { + export async function close(panel: T, ...params: Parameters) { // 校验 if (!panel.context.state.try_change_state("close")) { return } // 删除实例 diff --git a/assets/script/framework/FSound.ts b/assets/script/framework/FSound.ts index be3f3d3..e53a18d 100644 --- a/assets/script/framework/FSound.ts +++ b/assets/script/framework/FSound.ts @@ -4,15 +4,12 @@ import { FState } from "./FState"; import { FTool } from "./FTool"; /** - * [M] 声音管理 - * - 保存已经载入的声音,cc.AudioClip + * 声音模块 + * - 保存已经载入的声音,cc.AudioClip * - 保存已经播放的声音id */ export namespace FSound { - /** 声音文件的存储路径 */ - const PATH = "sound" - /** 所有声音的key */ type TypeSoundKey = keyof typeof DataSound @@ -54,10 +51,10 @@ export namespace FSound { /** 获取声音数据 */ async function get_sound(key: TypeSoundKey): Promise { - // 如果已经有缓存,则直接返回 + // 如果已经有缓存,则直接返回 let data = sound_all.get(key) if (data) { return data } - // 如果没有缓存,则从数据文件中获取 + // 如果没有缓存,则从数据文件中获取 data = { state: new FState.StateJumpTable({ "prepare": ["ok", "error"], @@ -70,7 +67,7 @@ export namespace FSound { data.url = sound_source_data[0] data.volume = sound_source_data[1] || 1 data.loop = sound_source_data[2] || false - data.clip = await FTool.load_res(`${PATH}/${sound_source_data[0]}`, cc.AudioClip) + data.clip = await FTool.load_res(sound_source_data[0], cc.AudioClip) data.state.try_change_state(data.clip ? "ok" : "error") } else { data.state.try_change_state("error") @@ -85,7 +82,7 @@ export namespace FSound { if (!get_sound_switch()) { return } let data = await get_sound(key) if (data.state.check_state("error")) { return } - // 特殊情况:bgm类型,如果已经在播放,则跳过 + // 特殊情况:bgm 类型,如果已经在播放,则跳过 if (data.loop && [cc.audioEngine.AudioState.INITIALZING, cc.audioEngine.AudioState.PLAYING] .includes(cc.audioEngine.getState(data.id))) { @@ -101,12 +98,12 @@ export namespace FSound { cc.audioEngine.stop(data.id) } - /** 常用:播放bgm */ + /** 常用:播放 bgm */ export function play_bgm() { FSound.play("bgm") } - /** 常用:播放按键音 */ + /** 常用:播放按键音 */ export function play_btn() { FSound.play("btn") } diff --git a/assets/script/framework/FText.ts b/assets/script/framework/FText.ts index 7978655..7dd12b8 100644 --- a/assets/script/framework/FText.ts +++ b/assets/script/framework/FText.ts @@ -2,22 +2,21 @@ import { DataText } from "../data/DataText"; import { FLocal } from "./FLocal"; import { FTool } from "./FTool"; -const C = { - EDITOR_TYPE: "chinese" as TypeLanguageKey // 默认语言 -} - -/** 语言类型 */ -type TypeLanguageKey = keyof typeof DataText - -/** 文字的key */ -type TypeTextKey = keyof typeof DataText["chinese"] - /** - * [framework] 语言本地化数据管理 + * 多语言模块 */ export namespace FText { - /** 获取当前的语言key */ + /** 语言类型 */ + type TypeLanguageKey = keyof typeof DataText + + /** 文字的 key */ + export type TypeTextKey = keyof typeof DataText["chinese"] + + /** 编辑器语言 */ + const EDITOR_TYPE = "chinese" as TypeLanguageKey + + /** 获取当前的语言 key */ export function get_language(): TypeLanguageKey { return FLocal.get("language") as TypeLanguageKey } @@ -28,12 +27,12 @@ export namespace FText { } /** - * 获取语言本地化数据,如果获取失败,则返回key + * 获取语言本地化数据,如果获取失败,则返回 key * @param key * @param params */ export function get_text(key: TypeTextKey, ...params: string[]): string { - let language = CC_EDITOR ? C.EDITOR_TYPE : FLocal.get("language") + let language = CC_EDITOR ? EDITOR_TYPE : FLocal.get("language") let text = DataText[language][key] if (text) { return FTool.get_template_string(text, ...params) diff --git a/assets/script/framework/FTool.ts b/assets/script/framework/FTool.ts index 477db1f..e9cd68d 100644 --- a/assets/script/framework/FTool.ts +++ b/assets/script/framework/FTool.ts @@ -1,7 +1,5 @@ /** - * [framework] 全局方法类 - * - 封装一些通用方法 - * @todo 对这些方法进行分类 + * 封装一些通用方法 */ export namespace FTool { @@ -35,6 +33,7 @@ export namespace FTool { /** 随机字符数组,默认去掉了容易混淆的字符oO/9gq/Vv/Uu/LlI1 */ const RANDOM_CHAR = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678" + const RANDOM_CHAR_LENGTH = RANDOM_CHAR.length /** * 随机字符串 @@ -43,7 +42,7 @@ export namespace FTool { export function get_random_string(length: number): string { let result = [] for (let i = 0; i < length; i += 1) { - result.push(RANDOM_CHAR[Math.trunc(Math.random() * RANDOM_CHAR.length)]) + result.push(RANDOM_CHAR[Math.trunc(Math.random() * RANDOM_CHAR_LENGTH)]) } return result.join("") } @@ -102,15 +101,6 @@ export namespace FTool { return node.parent.convertToNodeSpaceAR(w_position) } - /** - * 计算两点之间的距离 - * @param p0 - * @param p1 - */ - export function get_2p_distance(p0: cc.Vec2, p1: cc.Vec2) { - return p0.sub(p1).mag() - } - /** * 异步函数中等待一段时间 * @param time 单位s @@ -128,39 +118,6 @@ export namespace FTool { return template.replace(/\{([0-9]+?)\}/g, (match, index) => params[index] || `\{${index}\}`) } - /** - * 手动刷新widget1次,并在刷新完毕后置于false - * @param node - */ - export function do_widget_once(node: cc.Node) { - let w: cc.Widget = node.getComponent(cc.Widget) - if (w && w.enabled) { - w.updateAlignment() - if (w.alignMode == cc.Widget.AlignMode.ONCE || w.alignMode == cc.Widget.AlignMode.ON_WINDOW_RESIZE) { - w.enabled = false - } - } - } - - /** - * 判断两个数是否约等于 - * @param n0 - * @param n1 - * @param variance 精度,默认为1 - */ - export function is_number_fuzzy_equal(n0: number, n1: number, variance: number = 1): boolean { - return Math.abs(n0 - n1) <= variance - } - - /** - * 截取数字的几位小数 - * @param n 源数字 - * @param count 小数位数 - */ - export function get_number_fixed(n: number, count: number = 1): number { - return Math.trunc(n * 10 ** count) / 10 ** count - } - /** * 载入单个资源 * @param path @@ -190,6 +147,23 @@ export namespace FTool { }) } + /** + * 载入编辑器中的资源 + * - 注意一些资源的命名方式不一样 + * @param path + * @param type + */ + export async function load_res_in_editot(path: string, type: T): Promise> { + return await new Promise(res => { + let url = `db://assets/resources/${path}` + let uuid = Editor.assetdb.remote.urlToUuid(url) + cc.loader.load({ type: "uuid", uuid: uuid }, (err, resource: InstanceType) => { + err && cc.warn(`载入资源组失败, path=${path}, err=${err}`) + err ? res(null) : res(resource) + }) + }) + } + /** * 载入本地资源或网络资源 * 1. 本地资源传入uuid @@ -205,26 +179,4 @@ export namespace FTool { }) } - /** - * cc.misc.lerp的反向操作,获取value在min~max的lerp值 - * @param min - * @param max - * @param value - */ - export function get_number_lerp(value: number, min: number, max: number) { - return (value - min) / (max - min) - } - - /** - * 模运算,针对负数进行统一化 - * - [区别] n为正数时与%运算相同,n为负数:-1%10=-1;get_number_modulo(-1,10)=9 - * @param n - */ - export function get_number_modulo(n: number, modulo: number): number { - if (n < 0) { - n += Math.max(modulo, modulo * Math.floor(-n)) - } - return n % modulo - } - } diff --git a/assets/script/framework/FVersion.ts b/assets/script/framework/FVersion.ts index eda0670..ad10064 100644 --- a/assets/script/framework/FVersion.ts +++ b/assets/script/framework/FVersion.ts @@ -11,7 +11,7 @@ export namespace FVersion { /** 组合版本 */ const version = new FState.StateSet( - ...Object.keys(DataVersion).filter(v => DataVersion[v] === 1) + ...Object.keys(DataVersion).filter(v => DataVersion[v] === 1) as TypeVersionKey[] ) /** 获取当前版本标记 */ diff --git a/assets/script/framework/TChild.ts b/assets/script/framework/TChild.ts deleted file mode 100644 index cc96ce7..0000000 --- a/assets/script/framework/TChild.ts +++ /dev/null @@ -1,59 +0,0 @@ -const { ccclass, property, menu } = cc._decorator - -/** - * [T] 子节点管理工具 - * - [目的] 用于解决需要在节点内部getChildByName()来获取到子节点的场景 - * - [用法] 需要将此作为需要观察节点的组件,并将需要观察节点的子节点拖入组件,后面的静态方法定义了使用接口 - * - [注意] 理论上可以观察非子节点,但是逻辑上并不推荐使用 - * - [注意] 观察的子节点名称需要不同 - */ -@ccclass -@menu("t/TChild") -export class TChild extends cc.Component { - - /** - * 获取节点中被观察的子节点 - * @param parent_node - * @param child_node_nodename - */ - static get_child(parent_node: cc.Node, child_nodename: string): cc.Node { - return parent_node.getComponent(TChild).get_child(child_nodename) - } - - @property({ tooltip: "子节点列表", type: cc.Node }) - private child_list: cc.Node[] = [] - - private child_map: Map = new Map() - - /** 将list保存为map */ - private set_all_child() { - this.child_list.forEach(v => { - if (!v) { - cc.warn(`@TChild: node的值为null, name=${v.name}`) - return - } - if (this.child_map.has(v.name)) { - cc.warn(`@TChild: node-name重复, name=${v.name}`) - return - } - this.child_map.set(v.name, v) - }) - } - - /** - * 获取被观察的子节点 - * @param name - */ - private get_child(name: string): cc.Node { - // 第一次查询时写入map - if (this.child_map.size === 0) { - this.set_all_child() - } - // 查询 - let n = this.child_map.get(name) - if (!n) { - cc.error(`@TChild: node不存在, name=${name}`) - } - return n - } -} diff --git a/assets/script/framework/TColor.ts b/assets/script/framework/TColor.ts deleted file mode 100644 index 1721eca..0000000 --- a/assets/script/framework/TColor.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { FColor } from "./FColor"; - -const { ccclass, property, menu } = cc._decorator; -const C = { - DEFAULT_KEY: "none", // 默认key;对应颜色为白色 -} - -/** - * [T] 颜色工具 - * - [注意] 不在onLoad中执行,需要手动在编辑器中preview;如果未来有多个颜色配置文件,则需要在onLoad中执行. - */ -@ccclass -@menu("t/TColor") -export class TColor extends cc.Component { - - @property({ tooltip: "颜色字符串" }) - private key: string = C.DEFAULT_KEY - - @property({ tooltip: "编辑器操作" }) - private get E() { return false } - private set E(v: boolean) { CC_EDITOR && this.update_color() } - - private update_color() { - this.node.color = FColor.get_color(this.key) - } -} diff --git a/assets/script/framework/TSize.ts b/assets/script/framework/TSize.ts deleted file mode 100644 index d47c422..0000000 --- a/assets/script/framework/TSize.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { FTool } from "./FTool"; - -const { ccclass, property, menu } = cc._decorator - -/** - * [T] 调整node-size工具,使其保持比例 - * - [用法] 点击save,修改大小(width/height),点击根据width还是height修改 - * - [注意] 计算结果保留1位小数 - * - [注意] source_size是节点的源比例;尽量save后就不要进行修改 - */ -@ccclass -@menu("t/TSize") -export class TSize extends cc.Component { - - @property({ tooltip: "源size", readonly: true }) - private source_size: cc.Vec2 = cc.v2(1, 1) - - @property({ tooltip: "调整之后的size" }) - private current_size: cc.Vec2 = cc.v2(1, 1) - - @property({ tooltip: "编辑器操作-将当前size保存为源size" }) - private get E_save() { return false } - private set E_save(v: boolean) { - CC_EDITOR && this.save_size() - } - - @property({ tooltip: "编辑器操作-根据width修改" }) - private get E_change_by_width() { return false } - private set E_change_by_width(v: boolean) { - CC_EDITOR && this.change_size_by_width() - } - - @property({ tooltip: "编辑器操作-更具height修改" }) - private get E_change_by_height() { return false } - private set E_change_by_height(v: boolean) { - CC_EDITOR && this.change_size_by_height() - } - - /** 保存size */ - private save_size() { - this.source_size.x = this.node.width - this.source_size.y = this.node.height - this.current_size.x = this.node.width - this.current_size.y = this.node.height - } - - /** 根据width修改size */ - private change_size_by_width() { - this.current_size.y = FTool.get_number_fixed(this.current_size.x / this.source_size.x * this.source_size.y) - this.node.width = this.current_size.x - this.node.height = this.current_size.y - } - - /** 根据height修改size */ - private change_size_by_height() { - this.current_size.x = FTool.get_number_fixed(this.current_size.y * this.source_size.x / this.source_size.y) - this.node.width = this.current_size.x - this.node.height = this.current_size.y - } - -} diff --git a/assets/script/framework/TSize.ts.meta b/assets/script/framework/TSize.ts.meta deleted file mode 100644 index b44b0ed..0000000 --- a/assets/script/framework/TSize.ts.meta +++ /dev/null @@ -1,9 +0,0 @@ -{ - "ver": "1.0.5", - "uuid": "948982fb-8aec-46c7-b6bb-c5660a85f6e0", - "isPlugin": false, - "loadPluginInWeb": true, - "loadPluginInNative": true, - "loadPluginInEditor": false, - "subMetas": {} -} \ No newline at end of file diff --git a/assets/script/framework/TText.ts b/assets/script/framework/TText.ts deleted file mode 100644 index eeff94c..0000000 --- a/assets/script/framework/TText.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { FText } from "./FText"; -import { FTool } from "./FTool"; - -const { ccclass, property, menu } = cc._decorator; - -/** - * [T] 文字工具 - * - [支持] cc.Label,cc.RichText,cc.Sprite三种渲染组件,其中sprite通过传入资源路径的方式动态载入 - * - [用法] 将此组件挂载到相应节点下,修改key - * - [注意] 有多个文字配置文件,所以会在onLoad时执行 - */ -@ccclass -@menu("t/TText") -export class TText extends cc.Component { - - onLoad() { - this.is_do_onload && this.update_show() - } - - @property({ tooltip: "显示组件:cc.Label", type: cc.Label, readonly: true }) - private show_component_label: cc.Label = null - - @property({ tooltip: "显示组件:cc.RichText", type: cc.RichText, readonly: true }) - private show_component_rich_text: cc.RichText = null - - @property({ tooltip: "显示组件:cc.Sprite", type: cc.Sprite, readonly: true }) - private show_component_sprite: cc.Sprite = null - - @property({ tooltip: "编辑器操作:获取渲染组件" }) - private get E_get_show_component() { return false } - private set E_get_show_component(v: boolean) { CC_EDITOR && this.get_show_component() } - - /** 获取渲染组件 */ - private get_show_component() { - this.show_component_label = this.getComponent(cc.Label) || null - this.show_component_rich_text = this.getComponent(cc.RichText) || null - this.show_component_sprite = this.getComponent(cc.Sprite) || null - } - - @property({ tooltip: "字符串key" }) - private key: string = "" - - @property({ tooltip: "字符串参数", type: cc.String }) - private params: string[] = [] - - @property({ tooltip: "是否在onLoad时候修改;考虑有多个文字配置文件,默认为true" }) - private is_do_onload: boolean = true - - @property({ tooltip: "编辑器操作" }) - private get E_update_show_component() { return false } - private set E_update_show_component(v: boolean) { CC_EDITOR && this.update_show() } - - /** 更新显示,cc.Label,cc.RichText,cc.Sprite */ - private async update_show() { - if (!!this.show_component_label) { - this.show_component_label.string = FText.get_text(this.key, ...this.params) - return - } - if (!!this.show_component_rich_text) { - this.show_component_rich_text.string = FText.get_text(this.key, ...this.params) - return - } - if (!!this.show_component_sprite) { - if (CC_EDITOR) { - cc.warn("@TText: sprite渲染组件不允许在editor下写入") - return - } - this.show_component_sprite.spriteFrame = await FTool.load_res(FText.get_text(this.key, ...this.params), cc.SpriteFrame) - return - } - } -} diff --git a/assets/script/framework/TZIndex.ts b/assets/script/framework/TZIndex.ts deleted file mode 100644 index b1ba3ad..0000000 --- a/assets/script/framework/TZIndex.ts +++ /dev/null @@ -1,26 +0,0 @@ -const { ccclass, property, menu } = cc._decorator - -/** - * [T] 调整node-zIndex(节点渲染次序)工具 - * - [注意] 仅在编辑器中执行,不在onLoad时执行 - */ -@ccclass -@menu("t/TZIndex") -export class TZIndex extends cc.Component { - - @property({ tooltip: "当前的zIndex", readonly: true }) - private now_z_index = 0 - - @property({ tooltip: "更改的zIndex" }) - private z_index = 0 - - @property({ tooltip: "编辑器操作" }) - private get E() { return false } - private set E(v: boolean) { CC_EDITOR && this.update_z_index() } - - private update_z_index() { - this.node.zIndex = this.z_index - this.now_z_index = this.node.zIndex - } - -} diff --git a/assets/script/framework/TZIndex.ts.meta b/assets/script/framework/TZIndex.ts.meta deleted file mode 100644 index 8dc38ca..0000000 --- a/assets/script/framework/TZIndex.ts.meta +++ /dev/null @@ -1,9 +0,0 @@ -{ - "ver": "1.0.5", - "uuid": "5145c25f-447f-4650-bfe2-92f92855daa7", - "isPlugin": false, - "loadPluginInWeb": true, - "loadPluginInNative": true, - "loadPluginInEditor": false, - "subMetas": {} -} \ No newline at end of file diff --git a/assets/script/framework/App.ts b/assets/script/game/App.ts similarity index 62% rename from assets/script/framework/App.ts rename to assets/script/game/App.ts index 23cec33..c5d5ef3 100644 --- a/assets/script/framework/App.ts +++ b/assets/script/game/App.ts @@ -1,16 +1,16 @@ -import { FLocal } from "./FLocal"; -import { FPanel } from "./FPanel"; -import { FSound } from "./FSound"; -import { FVersion } from "./FVersion"; +import { FLocal } from "../framework/FLocal" +import { FPanel } from "../framework/FPanel" +import { FSound } from "../framework/FSound" +import { FVersion } from "../framework/FVersion" -const { ccclass, property, menu } = cc._decorator +const { ccclass, property } = cc._decorator; /** - * [framework] 游戏启动主入口 - * - 显式调用调整屏幕适配,本地存储初始化,游戏资源的初始化,声音初始化,界面初始化 + * 游戏启动主入口 + * - 需要挂在 Canvas 节点下。 + * - 显式调用调整屏幕适配,各子系统初始化,游戏启动逻辑等。 */ @ccclass -@menu("f/App") export class App extends cc.Component { start() { @@ -29,12 +29,13 @@ export class App extends cc.Component { // 各子系统初始化 FLocal.init_local_data() FPanel.init_parent(this.panel_parent) + // 游戏启动逻辑 FSound.play_bgm() } /** * 调整屏幕适配 - * - 注意cc.winSize只有在适配后(修改fitHeight/fitWidth后)才能获取到正确的值,因此使用cc.getFrameSize()来获取初始的屏幕大小 + * - 注意 cc.winSize 只有在适配后才能获取到正确的值,因此需要使用 cc.getFrameSize() 来获取初始的屏幕大小。 */ private adjust_screen() { let screen_size = cc.view.getFrameSize().width / cc.view.getFrameSize().height diff --git a/assets/script/framework/App.ts.meta b/assets/script/game/App.ts.meta similarity index 100% rename from assets/script/framework/App.ts.meta rename to assets/script/game/App.ts.meta diff --git a/assets/script/game/Gameplay.ts b/assets/script/game/Gameplay.ts index a36d51e..ca41cc3 100644 --- a/assets/script/game/Gameplay.ts +++ b/assets/script/game/Gameplay.ts @@ -1,6 +1,6 @@ import { FState } from "../framework/FState"; -const { ccclass, menu } = cc._decorator; +const { ccclass } = cc._decorator; /** * 游戏状态 @@ -9,13 +9,12 @@ const { ccclass, menu } = cc._decorator; * - pause 暂停 * - end 结束 */ -type GameState = "init" | "start" | "pause" | "end" +type GameState = "init" | "start" | "pause" | "end"; /** - * [framework] 游戏主控逻辑 + * 游戏主逻辑 */ @ccclass -@menu("f/Gameplay") export class Gameplay extends cc.Component { static ins: Gameplay; @@ -24,10 +23,6 @@ export class Gameplay extends cc.Component { Gameplay.ins = this } - start() { - - } - /** 游戏状态 */ private state = new FState.StateJumpTable({ "init": ["start"], @@ -39,7 +34,7 @@ export class Gameplay extends cc.Component { /** 获取当前的游戏状态 */ get_state() { return this.state } - /** 游戏初始化;包括各个游戏内子系统的初始化 */ + /** 游戏初始化。包括各个游戏内子系统的初始化 */ game_init() { } diff --git a/assets/script/game/TChild.ts b/assets/script/game/TChild.ts new file mode 100644 index 0000000..d127adc --- /dev/null +++ b/assets/script/game/TChild.ts @@ -0,0 +1,24 @@ +const { ccclass, property } = cc._decorator; + +/** + * 子节点管理工具 + * - 使用场景:少量的子节点需要被使用到。 + * - 以节点名称作为区分。 + */ +@ccclass +export class TChild extends cc.Component { + + /** + * 获取子节点 + * @param parent_node 父节点 + * @param child_nodename 子节点名称 + */ + static get_child(parent_node: cc.Node, child_nodename: string): cc.Node { + let r = parent_node.getComponent(TChild).child_list.find(v => v.name === child_nodename) + cc.error(`@TChild: node不存在, name=${name}`) + return r + } + + @property({ tooltip: "子节点列表", type: cc.Node }) + private child_list: cc.Node[] = [] +} diff --git a/assets/script/framework/TChild.ts.meta b/assets/script/game/TChild.ts.meta similarity index 100% rename from assets/script/framework/TChild.ts.meta rename to assets/script/game/TChild.ts.meta diff --git a/assets/script/game/TColor.ts b/assets/script/game/TColor.ts new file mode 100644 index 0000000..483eb61 --- /dev/null +++ b/assets/script/game/TColor.ts @@ -0,0 +1,23 @@ +import { FColor } from "../framework/FColor"; + +const { ccclass, property } = cc._decorator; + +/** + * 颜色工具 + * - 不在 onLoad 中执行,因为只有一个颜色配置文件,所以在编辑器中操作保证所见即所得。 + * - 如果未来有多个颜色配置文件,则需要同 FText 一样。 + */ +@ccclass +export class TColor extends cc.Component { + + @property({ tooltip: "颜色字符串" }) + private key: string = "none" + + @property({ tooltip: "编辑器操作" }) + private get E() { return false } + private set E(v: boolean) { CC_EDITOR && this.update_color() } + + private update_color() { + this.node.color = FColor.get_color(this.key as any) + } +} diff --git a/assets/script/framework/TColor.ts.meta b/assets/script/game/TColor.ts.meta similarity index 100% rename from assets/script/framework/TColor.ts.meta rename to assets/script/game/TColor.ts.meta diff --git a/assets/script/game/TText.ts b/assets/script/game/TText.ts new file mode 100644 index 0000000..292c07e --- /dev/null +++ b/assets/script/game/TText.ts @@ -0,0 +1,52 @@ +import { FText, TypeTextKey } from "../framework/FText"; +import { FTool } from "../framework/FTool"; + +const { ccclass, property } = cc._decorator; + +/** + * 文字工具 + * - 支持 cc.Label cc.RichText cc.Sprite 三种不同的组件。 + */ +@ccclass +export class TText extends cc.Component { + + onLoad() { + this.is_do_onload && this.update_show() + } + + @property({ tooltip: "字符串key" }) + private key: TypeTextKey = "none" + + @property({ tooltip: "字符串参数" }) + private params: string[] = [] + + @property({ tooltip: "是否在onLoad时候修改,默认为true" }) + private is_do_onload: boolean = true + + @property({ tooltip: "编辑器操作" }) + private get E() { return false } + private set E(v: boolean) { CC_EDITOR && this.update_show() } + + /** 更新显示 */ + private async update_show() { + // cc.Label + if (this.getComponent(cc.Label)) { + this.getComponent(cc.Label).string = FText.get_text(this.key, ...this.params) + return + } + // cc.RichText + if (this.getComponent(cc.RichText)) { + this.getComponent(cc.RichText).string = FText.get_text(this.key, ...this.params) + return + } + // cc.Sprite + if (this.getComponent(cc.Sprite)) { + let editor_path = FText.get_text(this.key, ...this.params) + // 运行时载入需要对path进行进一步处理 + let runtime_path = editor_path.replace(/\..*$/, "") + this.getComponent(cc.Sprite).spriteFrame = CC_EDITOR + ? await FTool.load_res_in_editot(editor_path, cc.SpriteFrame) + : await FTool.load_res(runtime_path, cc.SpriteFrame) + } + } +} diff --git a/assets/script/framework/TText.ts.meta b/assets/script/game/TText.ts.meta similarity index 100% rename from assets/script/framework/TText.ts.meta rename to assets/script/game/TText.ts.meta diff --git a/assets/script/panel/PanelExample.ts b/assets/script/panel/PanelExample.ts index 6e9cf12..9d94321 100644 --- a/assets/script/panel/PanelExample.ts +++ b/assets/script/panel/PanelExample.ts @@ -13,7 +13,7 @@ const C = { @ccclass @menu("panel/PanelExample") @FPanel.SetPanelContext({ - path: "", + path: "panel/PanelExample", }) export class PanelExample extends FPanel.PanelBase { diff --git a/tsconfig.json b/tsconfig.json index 73b9c7c..02c9a71 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,18 +1,14 @@ { "compilerOptions": { - "module": "commonjs", + "module": "CommonJS", "lib": [ - "dom", - "es2015", - "es2016", - "es2017", - "es2018", - "es2019", - "esnext" + "DOM", + "ESNext", ], - "target": "es5", + "target": "ES5", "experimentalDecorators": true, - "skipLibCheck": true + "skipLibCheck": true, + "downlevelIteration": true }, "exclude": [ "node_modules",