DC优化
This commit is contained in:
@@ -0,0 +1,316 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using MFrame;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
/// <summary>
|
||||
/// 全屏面板遮挡工具:查找/添加/移除面板预制体上的 FullScreenCover 组件。
|
||||
/// 挂有该组件的面板 = 全屏面板(打开时自动隐藏下层 UI 省去 DrawCall,关闭/销毁自动恢复)。
|
||||
/// 策划可在此窗口自助管理,无需改代码。
|
||||
/// 说明:Project 窗口的 t: 搜索只能按资源类型过滤,搜不到“预制体里挂了某组件”,故提供本工具。
|
||||
/// </summary>
|
||||
public class FullScreenCoverTool : EditorWindow
|
||||
{
|
||||
private sealed class CoverInfo
|
||||
{
|
||||
public Object prefab; // 预制体资产引用(用于 Ping/打开)
|
||||
public string prefabPath; // 资源路径
|
||||
public string nodeName; // 组件所在节点名
|
||||
public bool enabled; // 组件是否启用
|
||||
public bool keepShow; // 被遮挡时保持显示
|
||||
}
|
||||
|
||||
private readonly List<CoverInfo> results = new List<CoverInfo>();
|
||||
private Vector2 scroll;
|
||||
private GameObject addTarget;
|
||||
private bool scanned;
|
||||
private string statusText = "尚未扫描,点击“扫描全工程”查找挂载 FullScreenCover 组件的面板预制体";
|
||||
|
||||
[MenuItem("Tools/UI/全屏面板遮挡工具")]
|
||||
private static void ShowWindow()
|
||||
{
|
||||
var win = GetWindow<FullScreenCoverTool>("全屏面板遮挡");
|
||||
win.minSize = new Vector2(540f, 320f);
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
// 打开窗口时自动扫描一次
|
||||
EditorApplication.delayCall += ScanAll;
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
EditorGUILayout.HelpBox(
|
||||
"挂有 FullScreenCover 组件的面板 = 全屏面板:打开时自动隐藏下层 UI(省去被遮住的 DrawCall),关闭/销毁自动恢复。\n" +
|
||||
"注意:仅用于完全铺满屏幕的面板(如通行证、商店、活动大页),半屏弹窗不要挂。", MessageType.Info);
|
||||
|
||||
// —— 添加区 ——
|
||||
EditorGUILayout.LabelField("添加组件(拖入面板预制体)", EditorStyles.boldLabel);
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
addTarget = (GameObject)EditorGUILayout.ObjectField(addTarget, typeof(GameObject), false);
|
||||
using (new EditorGUI.DisabledScope(addTarget == null))
|
||||
{
|
||||
if (GUILayout.Button("添加组件", GUILayout.Width(80f)))
|
||||
{
|
||||
AddComponentToPrefab(AssetDatabase.GetAssetPath(addTarget));
|
||||
addTarget = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(4f);
|
||||
|
||||
// —— 扫描区 ——
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
if (GUILayout.Button("扫描全工程", GUILayout.Height(24f)))
|
||||
{
|
||||
ScanAll();
|
||||
}
|
||||
GUILayout.Label(statusText, EditorStyles.miniLabel);
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(4f);
|
||||
|
||||
// —— 结果列表 ——
|
||||
if (!scanned)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (results.Count == 0)
|
||||
{
|
||||
EditorGUILayout.HelpBox("没有找到任何挂载 FullScreenCover 的面板。可用上方“添加组件”为全屏面板配置。", MessageType.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
scroll = EditorGUILayout.BeginScrollView(scroll);
|
||||
for (int i = 0; i < results.Count; i++)
|
||||
{
|
||||
DrawResultItem(results[i]);
|
||||
}
|
||||
EditorGUILayout.EndScrollView();
|
||||
}
|
||||
|
||||
private void DrawResultItem(CoverInfo info)
|
||||
{
|
||||
using (new EditorGUILayout.VerticalScope("box"))
|
||||
{
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
// 点击名称定位资源
|
||||
string title = info.prefab != null ? info.prefab.name : Path.GetFileName(info.prefabPath);
|
||||
if (GUILayout.Button(title, EditorStyles.boldLabel, GUILayout.Width(170f)))
|
||||
{
|
||||
EditorGUIUtility.PingObject(info.prefab);
|
||||
}
|
||||
|
||||
GUILayout.Label(info.enabled ? "已启用" : "已禁用",
|
||||
info.enabled ? EditorStyles.miniLabel : EditorStyles.whiteMiniLabel, GUILayout.Width(46f));
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
// 被遮挡时保持显示(勾选即写回预制体)
|
||||
bool newKeep = GUILayout.Toggle(info.keepShow, "被遮挡时保持显示", GUILayout.Width(132f));
|
||||
if (newKeep != info.keepShow)
|
||||
{
|
||||
info.keepShow = newKeep;
|
||||
SetKeepShow(info.prefabPath, newKeep);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("打开", GUILayout.Width(46f)))
|
||||
{
|
||||
AssetDatabase.OpenAsset(info.prefab);
|
||||
}
|
||||
if (GUILayout.Button("移除组件", GUILayout.Width(68f)))
|
||||
{
|
||||
if (EditorUtility.DisplayDialog("移除 FullScreenCover",
|
||||
$"确定从 {Path.GetFileName(info.prefabPath)} 移除 FullScreenCover 组件?\n该面板将不再自动隐藏下层。",
|
||||
"移除", "取消"))
|
||||
{
|
||||
RemoveComponent(info.prefabPath);
|
||||
ScanAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
EditorGUILayout.LabelField(info.prefabPath, EditorStyles.miniLabel);
|
||||
if (!info.enabled)
|
||||
{
|
||||
EditorGUILayout.LabelField("⚠ 组件处于禁用状态,不会生效(在预制体根节点 Inspector 勾选启用)。", EditorStyles.miniLabel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// —— 扫描 ——
|
||||
|
||||
private void ScanAll()
|
||||
{
|
||||
string scriptGuid = GetScriptGuid();
|
||||
if (string.IsNullOrEmpty(scriptGuid))
|
||||
{
|
||||
EditorUtility.DisplayDialog("错误", "无法获取 FullScreenCover 脚本 GUID,请确认脚本已编译无报错。", "确定");
|
||||
return;
|
||||
}
|
||||
|
||||
string[] prefabGuids = AssetDatabase.FindAssets("t:Prefab", new[] { "Assets" });
|
||||
results.Clear();
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < prefabGuids.Length; i++)
|
||||
{
|
||||
if (EditorUtility.DisplayCancelableProgressBar("全屏面板遮挡工具",
|
||||
$"扫描预制体中... ({i + 1}/{prefabGuids.Length})", (float)i / prefabGuids.Length))
|
||||
{
|
||||
break; // 用户取消
|
||||
}
|
||||
|
||||
string path = AssetDatabase.GUIDToAssetPath(prefabGuids[i]);
|
||||
if (string.IsNullOrEmpty(path) || !path.EndsWith(".prefab"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// 文本快筛:只有包含组件脚本 guid 的预制体才真正加载,避免逐个解析
|
||||
if (!ContainsGuidFast(path, scriptGuid))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(path);
|
||||
if (prefab == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
FullScreenCover[] comps = prefab.GetComponentsInChildren<FullScreenCover>(true);
|
||||
foreach (FullScreenCover comp in comps)
|
||||
{
|
||||
results.Add(new CoverInfo
|
||||
{
|
||||
prefab = prefab,
|
||||
prefabPath = path,
|
||||
nodeName = comp.gameObject.name,
|
||||
enabled = comp.enabled,
|
||||
keepShow = comp.isKeepShowWhenCovered
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
EditorUtility.ClearProgressBar();
|
||||
}
|
||||
|
||||
scanned = true;
|
||||
statusText = $"扫描完成:{results.Count} 个面板预制体挂载 FullScreenCover";
|
||||
Repaint();
|
||||
}
|
||||
|
||||
/// <summary>动态获取 FullScreenCover 脚本资产的 guid,避免硬编码。</summary>
|
||||
private static string GetScriptGuid()
|
||||
{
|
||||
GameObject probe = new GameObject("FullScreenCoverGuidProbe");
|
||||
try
|
||||
{
|
||||
MonoScript ms = MonoScript.FromMonoBehaviour(probe.AddComponent<FullScreenCover>());
|
||||
if (ms == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(ms));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Object.DestroyImmediate(probe);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>逐行读取文件快速判断是否包含 guid(找到即中断),比加载预制体快一个量级。</summary>
|
||||
private static bool ContainsGuidFast(string path, string guid)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (string line in File.ReadLines(path))
|
||||
{
|
||||
if (line.Contains(guid))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
// 文件被占用等情况按未命中处理
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// —— 修改预制体 ——
|
||||
|
||||
/// <summary>以“加载内容-修改-保存-卸载”的标准流程安全修改预制体资产。</summary>
|
||||
private static void EditPrefab(string path, System.Action<GameObject> edit)
|
||||
{
|
||||
GameObject root = PrefabUtility.LoadPrefabContents(path);
|
||||
try
|
||||
{
|
||||
edit(root);
|
||||
PrefabUtility.SaveAsPrefabAsset(root, path);
|
||||
}
|
||||
finally
|
||||
{
|
||||
PrefabUtility.UnloadPrefabContents(root);
|
||||
}
|
||||
AssetDatabase.SaveAssets();
|
||||
}
|
||||
|
||||
private void AddComponentToPrefab(string path)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path) || !path.EndsWith(".prefab"))
|
||||
{
|
||||
EditorUtility.DisplayDialog("无法添加", "请拖入一个预制体资产(.prefab),而不是场景对象或模型。", "确定");
|
||||
return;
|
||||
}
|
||||
|
||||
bool already = false;
|
||||
EditPrefab(path, root =>
|
||||
{
|
||||
if (root.GetComponent<FullScreenCover>() != null)
|
||||
{
|
||||
already = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
root.AddComponent<FullScreenCover>();
|
||||
}
|
||||
});
|
||||
|
||||
ShowNotification(new GUIContent(already ? "该预制体已挂载组件" : "已添加 FullScreenCover"));
|
||||
ScanAll();
|
||||
}
|
||||
|
||||
private void RemoveComponent(string path)
|
||||
{
|
||||
EditPrefab(path, root =>
|
||||
{
|
||||
FullScreenCover[] comps = root.GetComponentsInChildren<FullScreenCover>(true);
|
||||
foreach (FullScreenCover comp in comps)
|
||||
{
|
||||
Object.DestroyImmediate(comp, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void SetKeepShow(string path, bool value)
|
||||
{
|
||||
EditPrefab(path, root =>
|
||||
{
|
||||
FullScreenCover[] comps = root.GetComponentsInChildren<FullScreenCover>(true);
|
||||
foreach (FullScreenCover comp in comps)
|
||||
{
|
||||
comp.isKeepShowWhenCovered = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user