diff --git a/docs/superpowers/specs/UI-迁移参照手册.md b/docs/superpowers/specs/UI-迁移参照手册.md new file mode 100644 index 0000000..b16fcd2 --- /dev/null +++ b/docs/superpowers/specs/UI-迁移参照手册.md @@ -0,0 +1,203 @@ +# UI 迁移参照手册(Game_Surface_3 → YouleNexus) + +> **Status**: v1 (2026-09-03) +> **Purpose**: 记录已迁移 Layer 的 prefab 结构,作为之后**脚本绑定与驱动 UI** 的唯一参照。每个 prefab 的节点名、组件、坐标、spriteFrame、文本/字体均在此列出,脚本开发时无需回查 prefab JSON 或源数据。 +> **权威源**: Layer XML(`projects/Game_Surface_3/save/Layer*.xml`)+ gameabc_Object.json + gameabc_Image.json。 + +--- + +## 1. 全局迁移规则(实测确立) + +### 1.1 设计分辨率与布局策略 + +- 源工程(Game_Surface_3)UI 设计分辨率:**1280×720**。 +- 新工程(YouleNexus)画布:**1600×720(有意设计)**。 +- 布局策略:**1280×720 的 UI 在 1600×720 画布中水平居中**(左右各留 160 空白),全屏背景拉伸到 1600 填满。 + +> 水平居中靠 Widget `alignFlags=16`(水平居中)+ `_horizontalCenter = lpos.x` 实现(见 1.4),不是改坐标中心。 + +### 1.2 坐标系换算(源左上角 → Cocos 中心) + +源数据 X/Y 是左上角锚点(Layer XML 的 `X`/`Y` = gameabc_Object.json 的 `Left`/`Top`): + +``` +lpos.x = X + W/2 - 640 // 相对 1280 中心 +lpos.y = 360 - (Y + H/2) // Y-up 翻转,相对 720 中心 +``` + +> 中心取 **640/360(1280×720)**,不是 800/360。1600 的居中由 Widget 实现。 + +### 1.3 组件类型映射 + +**组件类型以 gameabc_Object.json 的 `ObjectType` 为准**(CLAUDE.md 已修正旧文档 off-by-one 与 SpiritType 误用): + +| ObjectType(JSON,权威) | 含义 | Cocos 组件 | +|---|---|---| +| 2 | Sprite | cc.Sprite | +| 4 | Text | cc.Label | + +Layer XML 的 `SpiritType` 是细分类,只作参考: + +| SpiritType(XML) | 含义 | +|---|---| +| 0 | 普通 Sprite | +| 1 | Text | +| 3 | 帧 Sprite(带 `Frame` 属性;`frame_all=1` 时无多帧效果) | + +### 1.4 Widget 规则 + +| 节点类型 | alignFlags | 说明 | +|---|---|---| +| root / group / 全屏背景 | **45**(全拉伸) | contentSize 1600×720,填满画布 | +| 固定元素 | **16**(水平居中)+ `_horizontalCenter = lpos.x` | 实现 1280 UI 在 1600 画布居中 | + +### 1.5 spriteFrame 引用 + +- `cc.Sprite._spriteFrame.__uuid__` 用 **SpriteFrame 真 UUID**,含 `@f9941` 子资源后缀。 +- `_type=0`(SIMPLE)、`_sizeMode=0`(CUSTOM)+ `_contentSize` = 源 W/H。 +- ⚠️ `create_sprite` 默认 `_sizeMode=1`(TRIMMED)会覆盖 contentSize,必须显式 `_sizeMode=0`。 + +### 1.6 全屏背景 contentSize + +源 1280×720 的全屏背景(如 `00011.png` 纯色遮罩,图片本身仅 4×4)→ contentSize **1600×720**(拉伸填满)。固定元素 contentSize = 源 W/H。 + +### 1.7 Text 对象字段映射 + +**文本/fontSize 的权威源是 Layer XML**(`Property Name="FontSize"` / `Text` 等),gameabc_Object.json 里 Text 对象只有语义名(ObjectName)+ W/H,**无 fontSize/文本**。 + +| 源字段(Layer XML,SpiritType=1) | cc.Label | 说明 | +|---|---|---| +| `FontSize` | `_fontSize` | **字体大小保持源值,不统一** | +| `FontColor` | `_color.r/g/b` | 整数 RGB:`16777215` = `0xFFFFFF` = 白 | +| `FontColorA` | `_color.a` | 透明度 | +| `Text` | `_string` | 初始文本(常 = ObjectName 占位,运行时由脚本替换) | +| `LineSpace` | `_lineHeight` | 当前用 `lineHeight = fontSize`(见 5.待验证) | +| `FontBold` | 加粗 | 待验证映射(复杂 Layer 补齐) | +| `AlignHorz` / `AlignVert` | `_horizontalAlign` / `_verticalAlign` | 待验证映射 | +| `WordWrap` | `_overflow` / `_enableWrapText` | 待验证映射 | + +### 1.8 根节点命名 + +prefab 根节点名 = 文件名(如 `Layer619_BackHall.prefab` → 根节点 `Layer619_BackHall`),Cocos 约定。 + +--- + +## 2. 已迁移 prefab 清单 + +| prefab | 源 Layer | spirits | 内容 | +|---|---|---|---| +| `Layer614_Loading.prefab` | Loading_Layer (614) | 2 | 载入遮罩 + 载入动画 | +| `Layer616_Kick.prefab` | Kick_Layer (616) | 3 | 强制下线提示 + 底 + 文字 | +| `Layer619_BackHall.prefab` | BackHall_Layer (619) | 1 | Spirit465(返回大厅按钮) | + +### 图片映射(ImageFileID → spriteFrame UUID) + +| ImageFileID | bmp | 图片实际尺寸 | 用途 | spriteFrame UUID | +|---|---|---|---|---| +| 11 | 00011.png | 4×4(拉伸) | 全屏遮罩 | `eabf148a-fa6a-460a-be4f-8e586eb80e07@f9941` | +| 108 | 00108.png | 100×100 | 载入动画 | `e966950a-fe3c-41d9-adcb-b8950fb77ae1@f9941` | +| 87 | 00087.png | 570×105 | 强制下线提示底 | `c6295419-a30e-4e88-b7d7-d4099114319d@f9941` | +| 31 | 00031.png | 91×91 | Spirit465 | `8e3905be-b629-4c4d-858b-b8a76e9f7752@f9941` | + +--- + +## 3. 每个 prefab 详细说明 + +> 约定:`lpos` = 相对父节点中心的偏移;`Widget hc` = `_horizontalCenter`;所有节点 anchorPoint = (0.5, 0.5)。 + +### 3.1 Layer619_BackHall.prefab(BackHall_Layer,返回大厅) + +源 Layer00619.xml:1 spirit,GroupID=55。 + +``` +Layer619_BackHall UITransform 1600×720 Widget 45 +└─ group-55 UITransform 1600×720 Widget 45 + └─ Spirit465 UITransform 91×91 Widget 16 (hc=569.5) +``` + +| 节点 | 源字段 | 组件属性 | +|---|---|---| +| Spirit465 | ObjectID=465, X=1164 Y=146 W=91 H=91, ImgResID=31, Frame=1, CanClick=1 | Sprite sf=`8e3905be-…@f9941` type=0 sizeMode=0;contentSize 91×91;lpos (569.5, 168.5);Widget 16 hc=569.5 | + +**脚本驱动要点**: +- Spirit465 是「返回大厅」按钮(`CanClick=1`),XML Event 为空 → 需脚本 `bind_button_click_event` 绑定点击回调。 + +### 3.2 Layer614_Loading.prefab(Loading_Layer,载入遮罩) + +源 Layer00614.xml:2 spirits,GroupID=40。 + +``` +Layer614_Loading UITransform 1600×720 Widget 45 +└─ group-40 UITransform 1600×720 Widget 45 + ├─ 载入遮罩 UITransform 1600×720 Widget 45 + └─ 载入动画 UITransform 150×150 Widget 16 (hc=0) +``` + +| 节点 | 源字段 | 组件属性 | +|---|---|---| +| 载入遮罩 | ObjectID=326, X=0 Y=0 W=1280 H=720, ImgResID=11, CanClick=1 | Sprite sf=`eabf148a-…@f9941` type=0 sizeMode=0;contentSize **1600×720**(全屏拉伸);lpos (0,0);Widget 45 | +| 载入动画 | ObjectID=327, X=565 Y=285 W=150 H=150, ImgResID=108, Frame=1 | Sprite sf=`e966950a-…@f9941` type=0 sizeMode=0;contentSize 150×150;lpos (0,0);Widget 16 hc=0 | + +**脚本驱动要点**: +- 载入遮罩(`CanClick=1`)XML Event `MouseUp=326`(自引用)→ 语义为「点击关闭 loading」,脚本绑定点击回调。 +- 载入动画 `frame_all=1`(单帧静态),若后续要转圈动画需脚本切 spriteFrame 或加 Animation(源为静态图)。 + +### 3.3 Layer616_Kick.prefab(Kick_Layer,强制下线提示) + +源 Layer00616.xml:3 spirits,GroupID=33。 + +``` +Layer616_Kick UITransform 1600×720 Widget 45 +└─ group-33 UITransform 1600×720 Widget 45 + ├─ 强制下线提示 UITransform 1600×720 Widget 45 + ├─ 强制下线提示底 UITransform 600×105 Widget 16 (hc=-1) + └─ 强制退出提示文字 UITransform 168×28 Widget 16 (hc=-18) [Label] +``` + +| 节点 | 源字段 | 组件属性 | +|---|---|---| +| 强制下线提示 | ObjectID=224, X=0 Y=0 W=1280 H=720, ImgResID=11 | Sprite sf=`eabf148a-…@f9941` type=0 sizeMode=0;contentSize **1600×720**;lpos (0,0);Widget 45 | +| 强制下线提示底 | ObjectID=225, X=339 Y=292 W=600 H=105, ImgResID=87 | Sprite sf=`c6295419-…@f9941` type=0 sizeMode=0;contentSize 600×105;lpos (-1, 15.5);Widget 16 hc=-1 | +| 强制退出提示文字 | ObjectID=227, X=538 Y=330 W=168 H=28, FontSize=16, FontColor=16777215, Text="强制退出提示文字" | Label string=`强制退出提示文字` fontSize=16 lineHeight=16 color=白(255,255,255,255);contentSize 168×28;lpos (-18, 16);Widget 16 hc=-18 | + +**脚本驱动要点**: +- 强制退出提示文字(Label)是**动态文本**:`_string` 运行时由脚本替换为实际提示内容(源 `Text="强制退出提示文字"` 是占位)。 +- 强制下线提示底是「提示框底图」,文字叠加其上(lpos 差 (17, 0.5),文字略偏左下对齐底图)。 + +--- + +## 4. 脚本驱动汇总 + +### 4.1 动态文本节点(脚本需 set string) + +| prefab | 节点 | 初始 _string | +|---|---|---| +| Layer616_Kick | 强制退出提示文字 | "强制退出提示文字"(占位,运行时替换) | + +### 4.2 可点击节点(脚本需 bind 回调) + +| prefab | 节点 | 源 Event | 语义 | +|---|---|---|---| +| Layer614_Loading | 载入遮罩 | MouseUp=326(自引用) | 点击关闭 loading | +| Layer619_BackHall | Spirit465 | 空 | 返回大厅按钮 | + +### 4.3 源 Event → Cocos 绑定映射 + +原工程 XML `EventList`(`MouseDown`/`MouseUp`/`MouseMove`/`OnTimer`)的 `Value` 是**回调目标 ObjectID**(`1`/空 = 无)。迁移时用 `bind_button_click_event` 把 Button 点击绑定到对应脚本 handler。若目标 ObjectID 指向自身,语义通常是「点击自身关闭该 Layer」。 + +--- + +## 5. 待验证事项 + +1. **`LineSpace` → `_lineHeight` 映射**:当前用 `lineHeight = fontSize`(对齐 Login_Layer 参考),但源 XML `LineSpace=0` 的精确语义(默认行距 vs 额外间距)待更多 Text 样本确认。 +2. **`FontBold` / `AlignHorz` / `AlignVert` / `WordWrap` → cc.Label** 的完整映射:复杂 Layer(含富文本/多行/对齐文本)迁移时补齐。 +3. **`FrameStyle`/`FrameIndex` 多帧 sprite**:试点 3 个 Layer 均为 `frame_all=1`(单帧),真正的多帧动画 sprite(`frame_all>1`)在 Cocos 中的驱动方式待验证。 +4. **`Option.vx/vy/vw/vh` 动画物理**:deferred 到 game logic 迁移。 + +--- + +## 关联文档 + +- `docs/superpowers/specs/UI-手工迁移规范.md`(9 步迁移流程 + 8 项验证清单) +- `docs/superpowers/specs/原工程数据模型.md`(JSON schema + 锚点公式) +- `docs/superpowers/data/layer-spirit-summary.json`(Layer → prefab 映射表)