DC优化
This commit is contained in:
@@ -0,0 +1,398 @@
|
||||
# FullScreenCover 全屏遮挡省 DC — 使用方法与避坑
|
||||
|
||||
> 源文件:`my_libs/unityLib/GameFrame/Runtime/frame/module/moduleUI/FullScreenCover.cs`(组件,17 行)
|
||||
> 配套工具:`Assets/Editor/FullScreenCoverTool.cs`(菜单 `Tools/UI/全屏面板遮挡工具`)
|
||||
> 验证环境:Unity 团结引擎(Tuanjie)+ MFrame 框架 + URP
|
||||
> **一句话:全屏面板打开时,把它下面那些"反正被盖住看不见"的界面 `SetActive(false)`,这些界面就不再提交 DrawCall;全屏面板关闭时自动恢复。业务代码零改动,策划在编辑器里挂个组件就能配。**
|
||||
|
||||
---
|
||||
|
||||
## 第一章 它到底省了多少(T5 实测数据)
|
||||
|
||||
| 项目 | 优化前 | 优化后 |
|
||||
| --- | --- | --- |
|
||||
| 大厅整帧批次数 | 约 100 | **35** |
|
||||
| 其中 SSAO 占用 | 4 个 DC | 0(见 `03_渲染设置与资源清理/`) |
|
||||
| LevelGiftPanel 打开时 | 自身 101 批 | 见 `01_UIEffect材质共享降DC/` |
|
||||
|
||||
遮挡机制本身的收益验证方式很直观:**打开全屏面板时,去 Hierarchy 里看 MainPanel / HomePanel 是不是变灰了**(变灰 = `SetActive(false)` = 不再产生 DC)。这是用户在 T5 上亲手确认过的。
|
||||
|
||||
---
|
||||
|
||||
## 第二章 5 分钟配置(策划操作,不用碰代码)
|
||||
|
||||
### 方式 A:用编辑器工具(推荐)
|
||||
|
||||
菜单:`Tools/UI/全屏面板遮挡工具`
|
||||
|
||||
窗口打开时会**自动扫描全工程**,列出所有已挂组件的面板。三个功能区:
|
||||
|
||||
| 操作 | 怎么做 |
|
||||
| --- | --- |
|
||||
| **给新面板加遮挡** | 把面板预制体拖进上方"添加组件"槽 → 点【添加组件】 |
|
||||
| **改"被遮挡时保持显示"** | 在结果列表里直接勾/取消那个复选框,**勾完立刻写回预制体**,不用再点保存 |
|
||||
| **取消某个面板的遮挡** | 点该行【移除组件】→ 二次确认弹窗 → 移除 |
|
||||
| **定位预制体** | 点面板名字 = Ping 到 Project 窗口;点【打开】= 进预制体编辑模式 |
|
||||
|
||||
列表还会告诉你每个面板的**组件启用状态**。如果显示"已禁用",说明组件被人在 Inspector 里取消勾选了,这时**不会生效**,窗口会用黄字提醒你。
|
||||
|
||||
### 方式 B:手动挂(工具不在手边时)
|
||||
|
||||
1. 打开面板预制体,选中**根节点**(必须和 `UI_PanelBase` 在同一个节点上);
|
||||
2. Inspector → Add Component → 搜 `FullScreenCover`;
|
||||
3. 完事。不需要写任何代码,也不需要注册。
|
||||
|
||||
> ⚠️ **必须挂在根节点**。框架是在 `_TryInitGameObject` 里用 `transform.GetComponent<FullScreenCover>()` 找的(非递归),挂在子节点上**完全无效**且不会报错——这是最容易踩的空坑。
|
||||
|
||||
### `isKeepShowWhenCovered` 这个勾到底啥意思
|
||||
|
||||
它是**"我不要被隐藏"的豁免权**,配在**被遮挡的那个面板**身上,不是配在全屏面板身上。
|
||||
|
||||
```
|
||||
通行证(全屏,挂了 FullScreenCover)打开
|
||||
↓ 会去隐藏所有比它层级低的面板
|
||||
主界面 MainPanel → 没勾豁免 → 被隐藏(省 DC)✅
|
||||
某个常驻活动图标面板 → 勾了豁免 → 保持显示(仍然出 DC)
|
||||
```
|
||||
|
||||
**什么时候才该勾**:这个面板必须一直可见,哪怕被全屏页盖住。比如某些常驻的悬浮入口、全局提示条。
|
||||
|
||||
**绝大多数面板都不要勾**。勾了就等于放弃这个面板的省 DC 收益。T5 现在的 7 个面板**全部没勾**(keepShow=0),这是正确状态。
|
||||
|
||||
> 历史备注:T5 早期有 6 个面板被误勾成 keepShow=1,后来在提交 `c61b9012` 里统一改回 0。当时的判断是"商店和通行证业务互斥,不会同时出现",但勾了这个之后**未来任何更高层的全屏页叠加都会失效**,所以还是改回来了。
|
||||
|
||||
---
|
||||
|
||||
## 第三章 哪些面板能挂 / 绝对不能挂
|
||||
|
||||
### ✅ 可以挂
|
||||
|
||||
**完全铺满屏幕、打开后下层一点都看不见**的面板:
|
||||
|
||||
- 通行证、商店、抽卡、宠物、技能、神话英雄、等级礼包(T5 现有 7 个)
|
||||
- 活动大页、图鉴、邮件全屏页、设置大页
|
||||
|
||||
### ❌ 绝对不能挂
|
||||
|
||||
| 类型 | 为什么不能挂 |
|
||||
| --- | --- |
|
||||
| **半屏弹窗**(确认框、奖励弹窗、底部抽屉) | 它盖不住下层,但会把下层隐藏 → **玩家看到下半截界面凭空消失** |
|
||||
| **带半透明背景的面板** | 同理,透出来的部分会是黑的/空的 |
|
||||
| **顶部飘字、Toast、加载条** | 这些在高层级,本身不会去隐藏别人;挂了也没意义 |
|
||||
| **战斗中需要看到主界面的面板** | 比如伤害飘字叠加在大厅上的情况 |
|
||||
|
||||
**判断口诀**:把这个面板打开,**肉眼能不能看到它下面的任何界面**?能看到 → 不能挂。
|
||||
|
||||
---
|
||||
|
||||
## 第四章 原理(通俗版)
|
||||
|
||||
Unity 的 UI 只要 GameObject 是**激活状态**,哪怕被别的界面完全盖住、一个像素都看不见,它**照样提交 DrawCall**——GPU 老老实实画一遍然后被上面的盖掉。这是纯浪费。
|
||||
|
||||
`FullScreenCover` 做的事就是:**打开全屏面板的瞬间,把下面那些白画一遍的界面关掉(`SetActive(false)`);关闭全屏面板时再打开回来。**
|
||||
|
||||
关键点:
|
||||
|
||||
1. **不是销毁,是隐藏**。对象还在内存里,还在面板管理器的注册表里,重新激活是瞬间的,不需要重新加载资源。
|
||||
2. **只隐藏"比自己层级低"的面板**。判定条件是 `panel.panelLayerIdx < _layerIdx`(严格小于),所以同层和更高层的面板不受影响。
|
||||
3. **业务语义不变**。被隐藏的面板调 `isShowing()` 仍然返回 `true`(框架特意这么写的),业务逻辑感知不到自己被藏了。
|
||||
|
||||
层级从低到高(`UILayerIdx` 枚举):
|
||||
|
||||
```
|
||||
layer_0 背景层 → layer_1 游戏层 → layer_2 UI基础层 → layer_3 功能层
|
||||
→ layer_4 弹窗层 → layer_5 提示层 → layer_6 特效层 → layer_7 通知层 → layer_8 加载层
|
||||
```
|
||||
|
||||
所以挂在 `layer_4`(弹窗层)的通行证,打开时会隐藏 `layer_0~layer_3` 里正在显示的面板(大厅 MainPanel、HomePanel 等)。
|
||||
|
||||
---
|
||||
|
||||
## 第五章 原理(程序版:改了哪 4 个文件)
|
||||
|
||||
补丁:`fullscreen_cover_mechanism.patch`(4 文件,+474 行)
|
||||
|
||||
| 文件 | 改动 |
|
||||
| --- | --- |
|
||||
| `FullScreenCover.cs` | **新建**。17 行纯配置组件,只有一个 `isKeepShowWhenCovered` 字段 |
|
||||
| `iface/IPanelBase.cs` | **新增 5 个成员**:`panelLayerIdx`、`isKeepShowWhenCovered`、`isHiddenByCover`(只读)+ `SetCoverHidden()`、`RestoreFromCover()`(方法) |
|
||||
| `PanelBase.cs` | **核心逻辑**,见下表 |
|
||||
| `FullScreenCoverTool.cs` | **新建**编辑器工具(Assets/Editor 下,不进包) |
|
||||
|
||||
`PanelBase.cs` 的 6 个改动点:
|
||||
|
||||
| 位置 | 代码 | 作用 |
|
||||
| --- | --- | --- |
|
||||
| 字段 | `_fullScreenCover` / `_hiddenByCover` / `_panelsHiddenByMe` | 组件缓存 / 我被藏了吗 / 我藏了谁 |
|
||||
| `_TryInitGameObject` | `_fullScreenCover = transform.GetComponent<FullScreenCover>();` | 加载完预制体后取组件(**只取根节点**) |
|
||||
| `Show()` | `if (_fullScreenCover != null && _fullScreenCover.enabled) HidePanelsUnderThis();` | 打开时隐藏下层 |
|
||||
| `Show()` | `if (_hiddenByCover) RestoreFromCover();` | 被藏着的面板主动 Show 时先恢复自己 |
|
||||
| `___CloseForPanelMgr()` | 关闭动画回调里 `RestorePanelsHiddenByMe();` | 关闭时恢复下层 |
|
||||
| `_Destroy()` | 开头 `RestorePanelsHiddenByMe();` | 兜底:没走 Close 直接销毁也要恢复 |
|
||||
| `isShowing()` | `return _view.gameObject.activeSelf \|\| _hiddenByCover;` | 被藏着也算"正在显示" |
|
||||
|
||||
两个恢复函数都做了**幂等**处理:`RestorePanelsHiddenByMe()` 遍历时检查 `panel.isHiddenByCover`,`RestoreFromCover()` 开头检查 `if (!_hiddenByCover) return;`。重复调用不会出错。
|
||||
|
||||
`HidePanelsUnderThis()` 的筛选条件(4 个全满足才隐藏):
|
||||
|
||||
```csharp
|
||||
if (panel.panelLayerIdx < _layerIdx // 1. 层级比我低
|
||||
&& !panel.isKeepShowWhenCovered // 2. 没勾豁免
|
||||
&& !panel.isHiddenByCover // 3. 还没被别人藏着(避免重复记录)
|
||||
&& panel.isShowing()) // 4. 当前正在显示
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 第六章 移植到新项目
|
||||
|
||||
### 6.1 前提核对(3 项,缺一不可)
|
||||
|
||||
| 前提 | 怎么查 | 不满足怎么办 |
|
||||
| --- | --- | --- |
|
||||
| 用的是 MFrame 的 `PanelBase<V>` + `PanelMgr` 面板体系 | 搜 `class PanelBase<V> : UIBase, IPanelBase` | 不是的话本机制**不能直接搬**,得按 6.3 的思路重写 |
|
||||
| 有 `UILayerIdx` 层级枚举,且每个面板知道自己层级 | 搜 `enum UILayerIdx` 和 `_layerIdx` | 需要自己补一个层级来源 |
|
||||
| 面板预制体根节点上有 `UI_PanelBase` | 打开任一面板预制体看根节点 | 组件要挂在同一节点 |
|
||||
|
||||
### 6.2 移植步骤
|
||||
|
||||
1. **应用补丁**(推荐,能看清每行改了什么):
|
||||
```powershell
|
||||
cd <新项目的 T5_game 对应目录>
|
||||
git apply --stat <归档路径>/02_全屏面板遮挡省DC/fullscreen_cover_mechanism.patch
|
||||
git apply --check <归档路径>/02_全屏面板遮挡省DC/fullscreen_cover_mechanism.patch
|
||||
git apply <归档路径>/02_全屏面板遮挡省DC/fullscreen_cover_mechanism.patch
|
||||
```
|
||||
`--check` 不报错才继续。报错通常是目标工程的 `PanelBase.cs` 版本与 T5 有差异 → 改用第 2 步。
|
||||
|
||||
2. **兜底:直接覆盖 4 个成品文件**(本目录里的 `FullScreenCover.cs`、`IPanelBase.cs`、`PanelBase.cs`、`FullScreenCoverTool.cs`)。
|
||||
⚠️ 覆盖 `PanelBase.cs` 前**必须先 diff**,确认新项目的 PanelBase 没有 T5 之外的自定义改动,否则会覆盖掉别人的代码。
|
||||
|
||||
3. **改命名空间**:如果新项目不叫 `MFrame`,全局替换。
|
||||
|
||||
4. **编译通过后配置面板**:用 `Tools/UI/全屏面板遮挡工具` 逐个给全屏面板挂组件。**一次只挂一个,挂完立刻进游戏验证**(打开→看 Hierarchy 变灰→关闭→看下层恢复)。
|
||||
|
||||
5. **验证收益**:`Window → Analysis → Frame Debugger`,对比挂载前后同一画面的批次数。
|
||||
|
||||
### 6.3 如果新项目不是 MFrame 体系
|
||||
|
||||
机制本身不依赖 MFrame,只需要三个能力:
|
||||
|
||||
1. 面板管理器能**枚举所有正在显示的面板**及其**层级**;
|
||||
2. 每个面板能**被隐藏 / 被恢复**(`SetActive(false/true)`);
|
||||
3. 面板**打开时**和**关闭完成时**各有一个可插入的时机点。
|
||||
|
||||
把 `HidePanelsUnderThis()` / `RestorePanelsHiddenByMe()` 两个方法照搬过去,接到这三个点上即可。**第七章的两个陷阱同样适用,务必一起看。**
|
||||
|
||||
---
|
||||
|
||||
## 第七章 ★两个已知陷阱(T5 真实事故复盘)
|
||||
|
||||
这两个都是**机制本身的设计边界**,不是 bug。移植到新项目时**必须一并注意**。
|
||||
|
||||
### 陷阱一:已经 Close 掉的面板被"复活"(T5 副本异常,真实发生)
|
||||
|
||||
**现象**:副本界面挂了 `FullScreenCover`,点"开始挑战"后出现异常,看起来像"主界面找不到了"。
|
||||
|
||||
**根因**(提交 `cdbbca4b` → `d9fc47e0` 处置):
|
||||
|
||||
| 时刻 | 发生了什么 | 状态 |
|
||||
| --- | --- | --- |
|
||||
| T0 | 打开 RaidSelectPanel(挂了 FullScreenCover + Scale 关闭动画 0.15s) | MainPanel/HomePanel 被 `SetActive(false)`,记进 RaidSelect 的 `_panelsHiddenByMe` |
|
||||
| T1 | 点"开始挑战" → 战斗加载完成回调里业务主动执行 `PanelMgr.Close(MainPanel)` + `Close(RaidSelectPanel)` | MainPanel **业务语义已关闭**,但物理对象还在(`autoDestroy=false`,Close 只是 inactive) |
|
||||
| T2 | 0.15 秒后 RaidSelectPanel 关闭动画播完 → `RestorePanelsHiddenByMe()` | 遍历列表,看到 MainPanel 的 `isHiddenByCover == true` → **`SetActive(true)` 把它复活了** |
|
||||
| T3 | 后续所有检查逻辑 | MainPanel 处于"**业务说它关了、物理对象却活着**"的矛盾状态,检查分支全乱 |
|
||||
|
||||
问题出在 `RestorePanelsHiddenByMe()` 的守卫**只看"是否被遮挡隐藏",不看"是否已被业务关闭"**:
|
||||
|
||||
```csharp
|
||||
if (panel != null && panel.isHiddenByCover) // ← 少了 isClosed 判断
|
||||
{
|
||||
panel.RestoreFromCover();
|
||||
}
|
||||
```
|
||||
|
||||
**T5 的处置**:提交 `d9fc47e0 debug` 里直接把 RaidSelectPanel 的 `FullScreenCover` 组件**摘掉了**(保守做法,不动框架)。所以现在的 7 个挂载面板里没有 RaidSelectPanel。
|
||||
|
||||
**⚠️ 框架层隐患至今未修**:`PanelBase.cs` 里**没有任何 `_closed` 守卫**(已确认,全文搜 `_closed`/`isClosed` 零命中)。只要再出现"某面板在被遮挡状态下被业务 Close,且它 `autoDestroy=false`",同样的复活就会重演。
|
||||
|
||||
**推荐的框架层修复(约 4 行,不破坏遮挡机制)**:
|
||||
|
||||
```csharp
|
||||
// ① IPanelBase.cs 新增只读成员
|
||||
/// <summary>业务是否已关闭(区别于"被遮挡隐藏")</summary>
|
||||
bool isClosed { get; }
|
||||
|
||||
// ② PanelBase.cs 新增字段与实现
|
||||
private bool _closed;
|
||||
bool IPanelBase.isClosed => _closed;
|
||||
|
||||
// ③ PanelBase.Show() 里,_data = data; 之后加一行
|
||||
_closed = false;
|
||||
|
||||
// ④ PanelBase.___CloseForPanelMgr(Action complete) 方法体第一行加
|
||||
_closed = true;
|
||||
|
||||
// ⑤ isShowing() 改为
|
||||
return !_closed && (_view.gameObject.activeSelf || _hiddenByCover);
|
||||
|
||||
// ⑥ RestorePanelsHiddenByMe() 的守卫改为
|
||||
if (panel != null && panel.isHiddenByCover && !panel.isClosed)
|
||||
```
|
||||
|
||||
**为什么 `_closed = true` 要放在 `___CloseForPanelMgr` 而不是 `Close()`**:
|
||||
`PanelBase.Close()` 只是转发给 `PanelMgr.Instance.Close(_registerModule)`,而业务代码里很多地方**直接调 `PanelMgr.Close(...)`**(比如 `EntrancePanel._CloseAllPanel`),根本不经过 `PanelBase.Close()`。`___CloseForPanelMgr` 是 PanelMgr 回调面板的**唯一内部关闭入口**,所有关闭路径都必经此处,守卫放这里才没有漏网。
|
||||
|
||||
**这个修复的安全性**:只增加一个"已关闭就别复活"的判断,不改隐藏逻辑、不改层级判定、不删任何资源。已关闭的面板本来就不该被显示出来。
|
||||
|
||||
### 陷阱二:被遮挡(inactive)的面板如果挂动画 tween,Close 会卡死
|
||||
|
||||
Unity 的硬规则:**`MonoBehaviour.Update()` 在 `SetActive(false)` 的对象上完全不运行。**
|
||||
|
||||
MFrame 的 `PanelTween_Scale` 这类动画 tween 是由 `AbsCom.Update()` 驱动的,关闭回调挂在 tween 播完之后。所以:
|
||||
|
||||
```
|
||||
面板被遮挡 → inactive → 此时业务 Close 它
|
||||
→ tween 的 Update 不跑 → 动画永远停在第一帧
|
||||
→ 关闭回调永不触发 → RestorePanelsHiddenByMe() 永不执行
|
||||
→ 这个面板永远关不掉,它藏着的下层面板也永远出不来
|
||||
```
|
||||
|
||||
**T5 当前安全的原因**:MainPanel 挂的是 `PanelTween_None`(同步回调,不依赖 Update),所以走的是"立即完成"路径,不会卡。
|
||||
|
||||
**规避方法(三选一)**:
|
||||
1. **给可能被遮挡的面板(尤其是主界面)用 `PanelTween_None`**,别用动画版 —— T5 现在就是这个状态;
|
||||
2. 业务在 Close 一个可能被遮挡的面板前,先确认它 `isHiddenByCover`,是的话先让它恢复;
|
||||
3. 框架层在 `___CloseForPanelMgr` 开头补一句:若 `_hiddenByCover` 则先 `RestoreFromCover()` 再播关闭动画。
|
||||
|
||||
**排查这个陷阱的特征**:面板"关不掉"、下层界面"再也不出现"、没有任何报错、Hierarchy 里那个面板一直是灰的。看到这三个特征同时出现,直接查这条。
|
||||
|
||||
---
|
||||
|
||||
## 第八章 排查技巧
|
||||
|
||||
### 8.1 ⚠️ 团结引擎的 guid 坑(文本反查会落空)
|
||||
|
||||
T5 用的是团结引擎(Tuanjie),`.cs.meta` 里的 guid 是**加密长串**(56 字符,含 `/` `+` `=`):
|
||||
|
||||
```
|
||||
guid: Dysd4X//V3yyisRZkbBdkO/Yqfm+oXtw45Vx0v70tF8fEn5k7g7wkdI=
|
||||
```
|
||||
|
||||
而 **prefab 里写入的不是这个字符串**,是转换后的 32 位 hex:
|
||||
|
||||
```
|
||||
FullScreenCover 在 prefab 中的 hex = 0a2deb478a85eef4883e8465d48c426f
|
||||
```
|
||||
|
||||
所以「拿 `.meta` 的 guid 去 grep prefab」**永远搜不到**(我亲自踩过,两种写法都失败)。
|
||||
|
||||
**正确做法(两条,任选)**:
|
||||
|
||||
```powershell
|
||||
# 做法一:搜组件的序列化字段名(最简单,不依赖 guid)
|
||||
Get-ChildItem "Assets\Resources" -Recurse -Include *.prefab |
|
||||
Where-Object { Select-String -Path $_.FullName -Pattern 'isKeepShowWhenCovered' -Quiet } |
|
||||
ForEach-Object { $_.Name }
|
||||
|
||||
# 做法二:用转换后的 hex(能顺便确认组件引用完整)
|
||||
Get-ChildItem "Assets\Resources" -Recurse -Include *.prefab |
|
||||
Where-Object { Select-String -Path $_.FullName -Pattern '0a2deb478a85eef4883e8465d48c426f' -Quiet }
|
||||
```
|
||||
|
||||
两种做法在 T5 上都返回**同样的 7 个面板**,可以互相验证。
|
||||
|
||||
> 移植到别的项目后 hex 会不同(跟 guid 绑定),用做法一最稳。
|
||||
|
||||
### 8.2 验证机制是否生效(3 步)
|
||||
|
||||
1. **Hierarchy 变灰法**(最快):Play → 打开全屏面板 → 看 Hierarchy 里 MainPanel/HomePanel 是否变灰 → 关闭 → 是否恢复。变灰即生效。
|
||||
2. **Frame Debugger 对照法**(量化):打开全屏面板,数批次数;然后临时把组件取消勾选(Inspector 里去掉 `FullScreenCover` 的启用勾)再数一次。差值就是省下的 DC。
|
||||
3. **组件状态自查**:`Tools/UI/全屏面板遮挡工具` 扫一遍,看有没有"已禁用"的黄字警告。
|
||||
|
||||
### 8.3 临时禁用做对照实验(不改预制体)
|
||||
|
||||
不需要移除组件,两种无损办法:
|
||||
|
||||
- **编辑器里**:选中预制体根节点 → Inspector 里把 `FullScreenCover` 组件**左上角的勾去掉** → Apply。框架判断的是 `_fullScreenCover.enabled`,取消勾选即完全失效。实验完再勾回来。
|
||||
- **运行时代码**(临时调试用):
|
||||
```csharp
|
||||
var cover = panel.view.GetComponent<MFrame.FullScreenCover>();
|
||||
if (cover != null) cover.enabled = false; // 之后 Show 就不会隐藏下层
|
||||
```
|
||||
|
||||
### 8.4 出问题时看哪里
|
||||
|
||||
| 症状 | 优先查 |
|
||||
| --- | --- |
|
||||
| 打开全屏面板后下层界面消失且不恢复 | 陷阱二(tween 卡死)+ 该面板 `autoDestroy` 配置 |
|
||||
| 已关闭的界面自己冒出来了 | 陷阱一(复活),查是谁在 Close 之后又 SetActive |
|
||||
| 挂了组件但完全没效果 | ①组件是否挂在**根节点** ②组件是否被禁用 ③面板层级是否真的比目标高 |
|
||||
| 半屏弹窗导致下层消失 | 挂错了,该面板不该挂(第三章) |
|
||||
|
||||
---
|
||||
|
||||
## 第九章 T5 当前挂载现状(截至归档时)
|
||||
|
||||
7 个面板,全部 `keepShow=0`(正确配置)、组件全部启用:
|
||||
|
||||
| 面板预制体 | 业务 | keepShow |
|
||||
| --- | --- | --- |
|
||||
| `UI_DrawCardPanel` | 抽卡 | 0 |
|
||||
| `UI_LevelGiftPanel` | 等级礼包 | 0 |
|
||||
| `UI_MythHeroPanel` | 神话英雄 | 0 |
|
||||
| `UI_PassPanel` | 通行证 | 0 |
|
||||
| `UI_PetPanel` | 宠物 | 0 |
|
||||
| `UI_ShopPanel` | 商店 | 0 |
|
||||
| `UI_SkillPanel` | 技能 | 0 |
|
||||
|
||||
**`UI_RaidSelectPanel`(副本选择)不在列表里** —— 它曾经挂过(`cdbbca4b` 加上,keepShow=1 → `c61b9012` 改 0 → `d9fc47e0` 整个组件摘掉),原因就是第七章陷阱一的事故。
|
||||
|
||||
**如果第七章的框架层守卫修好了,RaidSelectPanel 可以重新挂回去**(它是全屏面板,本身符合挂载条件),能再省一批 DC。在守卫没修之前**不要挂**。
|
||||
|
||||
---
|
||||
|
||||
## 本目录文件清单
|
||||
|
||||
| 文件 | 说明 |
|
||||
| --- | --- |
|
||||
| `FullScreenCover.cs` | 组件本体(17 行,挂预制体根节点) |
|
||||
| `IPanelBase.cs` | 接口(新增 5 个成员) |
|
||||
| `PanelBase.cs` | 核心实现(遮挡/恢复全部逻辑在这) |
|
||||
| `FullScreenCoverTool.cs` | 编辑器工具(放 `Assets/Editor/`,不进包) |
|
||||
| `fullscreen_cover_mechanism.patch` | 上述 4 文件的 git 标准补丁(+474 行) |
|
||||
| `FullScreenCover_使用方法与避坑.md` | 本文 |
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 第十章 T11 移植增强记录(2026-09-10)
|
||||
|
||||
> 本目录的 4 个 `.cs` 成品文件已同步为 **T11_game 验证过的增强版**(含第七章两个陷阱的框架层防护)。
|
||||
> 原始 T5 版本保留在 `fullscreen_cover_mechanism_T5原始.patch`,仅供历史对照,移植时不要用它。
|
||||
|
||||
### 相比 T5 原版的 2 处增强(均落在 PanelBase.cs / IPanelBase.cs)
|
||||
|
||||
**增强 1:`_closed` 复活守卫**(= 第七章陷阱一的框架层修复,按原文档推荐方案落地)
|
||||
|
||||
- `IPanelBase` 新增 `bool isClosed { get; }`;
|
||||
- `PanelBase` 新增 `_closed` 字段:`Show()` 时置 false,`___CloseForPanelMgr()` 开头置 true;
|
||||
- `isShowing()` 改为 `return !_closed && (_view.gameObject.activeSelf || _hiddenByCover);`;
|
||||
- `RestorePanelsHiddenByMe()` 恢复守卫加 `!panel.isClosed`——**已关闭的面板永不会被"复活"**。
|
||||
|
||||
**增强 2:被遮挡面板关闭前先恢复**(= 第七章陷阱二的规避方法 3)
|
||||
|
||||
- `___CloseForPanelMgr()` 开头:若 `_hiddenByCover` 则先 `RestoreFromCover()` 再播关闭动画。
|
||||
- 防止面板在 inactive 状态下关闭时 tween 的 `Update` 不跑、关闭回调永不触发、下层面板永远出不来。
|
||||
|
||||
### 移植到新项目时的文件对应关系
|
||||
|
||||
| 本目录文件 | 目标位置 |
|
||||
| --- | --- |
|
||||
| `FullScreenCover.cs` | `my_libs/unityLib/GameFrame/Runtime/frame/module/moduleUI/` |
|
||||
| `IPanelBase.cs` / `PanelBase.cs` | 同上(`iface/` 子目录)——**建议只看 `fullscreen_cover_t11_guard_mechanism.patch` 手工合入**,别整文件覆盖 |
|
||||
| `FullScreenCoverTool.cs` | `Assets/Editor/`(不进包) |
|
||||
|
||||
### T11 实际改动验证
|
||||
|
||||
`fullscreen_cover_t11_guard_mechanism.patch` 由 T11_game 仓库 `git diff` 直接导出,覆盖 `PanelBase.cs`(+135/-3)与 `IPanelBase.cs`(+28)两文件;`FullScreenCover.cs`、`FullScreenCoverTool.cs` 为全新文件,直接复制即可。
|
||||
Reference in New Issue
Block a user