feat: Enhance scene transition management and HUD scaffolding
- Added RequestTransition method to ISceneService for direct scene transition requests without needing Inspector SO references. - Updated DoorTransition and RoomTransition to utilize the new RequestTransition method via ServiceLocator. - Introduced SceneFadeController to manage scene fade effects during transitions, with event channel integration for fade requests. - Created HUDScaffoldWizard to automate HUD Canvas setup, including various UI elements and event channel bindings. - Updated assembly definitions to include necessary dependencies for new UI components. - Added Streaming assets for budget configuration to optimize scene loading and memory management.
This commit is contained in:
402
Assets/_Game/Scripts/Editor/UI/HUDScaffoldWizard.cs
Normal file
402
Assets/_Game/Scripts/Editor/UI/HUDScaffoldWizard.cs
Normal file
@@ -0,0 +1,402 @@
|
||||
using System.Collections.Generic;
|
||||
using BaseGames.UI;
|
||||
using BaseGames.UI.HUD;
|
||||
using TMPro;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace BaseGames.Editor.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// HUD 脚手架工具(架构 10_UIModule §HUD)。
|
||||
/// 在当前活动场景中生成完整的 HUD Canvas 层级结构并自动绑定已存在的事件频道资产。
|
||||
/// 执行路径:BaseGames ▸ Scene ▸ Setup ▸ Scaffold HUD Canvas
|
||||
/// </summary>
|
||||
public static class HUDScaffoldWizard
|
||||
{
|
||||
[MenuItem("BaseGames/Scene/Setup/Scaffold HUD Canvas", priority = 203)]
|
||||
public static void ScaffoldHUDCanvas()
|
||||
{
|
||||
var report = new List<string>();
|
||||
Undo.SetCurrentGroupName("Scaffold HUD Canvas");
|
||||
int undoGroup = Undo.GetCurrentGroup();
|
||||
|
||||
// ── Canvas ────────────────────────────────────────────────────────
|
||||
GameObject canvasGo = GetOrCreateRootCanvas("HUD Canvas", 0);
|
||||
|
||||
// ── HUDRoot ───────────────────────────────────────────────────────
|
||||
GameObject hudRootGo = GetOrCreateChild(canvasGo.transform, "HUDRoot").gameObject;
|
||||
HUDController hudCtrl = GetOrAddComponent<HUDController>(hudRootGo);
|
||||
|
||||
// 若场景中已存在 UIManager,自动将 _hudRoot 指向本 HUDRoot
|
||||
UIManager uiManager = Object.FindFirstObjectByType<UIManager>();
|
||||
if (uiManager != null)
|
||||
AssignRef(uiManager, "_hudRoot", hudRootGo);
|
||||
|
||||
// ── HP 区域 ───────────────────────────────────────────────────────
|
||||
GameObject hpContainerGo = GetOrCreateChild(hudRootGo.transform, "HP_Container").gameObject;
|
||||
var hpLayout = GetOrAddComponent<HorizontalLayoutGroup>(hpContainerGo);
|
||||
hpLayout.childForceExpandWidth = false;
|
||||
hpLayout.childForceExpandHeight = false;
|
||||
hpLayout.spacing = 4f;
|
||||
|
||||
// ── 魄元(Soul)量条 ──────────────────────────────────────────────
|
||||
GameObject soulGaugeGo = GetOrCreateChild(hudRootGo.transform, "Gauge_Soul").gameObject;
|
||||
Image soulFill = GetOrAddComponent<Image>(soulGaugeGo);
|
||||
soulFill.type = Image.Type.Filled;
|
||||
soulFill.fillMethod = Image.FillMethod.Horizontal;
|
||||
soulFill.fillAmount = 1f;
|
||||
|
||||
// ── 灵力(Spirit)量条 ────────────────────────────────────────────
|
||||
GameObject spiritGaugeGo = GetOrCreateChild(hudRootGo.transform, "Gauge_Spirit").gameObject;
|
||||
Image spiritFill = GetOrAddComponent<Image>(spiritGaugeGo);
|
||||
spiritFill.type = Image.Type.Filled;
|
||||
spiritFill.fillMethod = Image.FillMethod.Horizontal;
|
||||
spiritFill.fillAmount = 1f;
|
||||
|
||||
// ── 灵铢(LingZhu)文本 ───────────────────────────────────────────
|
||||
GameObject lingZhuGo = GetOrCreateChild(hudRootGo.transform, "Text_LingZhu").gameObject;
|
||||
TMP_Text lingZhuText = GetOrAddComponent<TextMeshProUGUI>(lingZhuGo);
|
||||
lingZhuText.text = "0";
|
||||
|
||||
// ── 回春图标(Spring Charges)─────────────────────────────────────
|
||||
GameObject springContainerGo = GetOrCreateChild(hudRootGo.transform, "Spring_Container").gameObject;
|
||||
var springLayout = GetOrAddComponent<HorizontalLayoutGroup>(springContainerGo);
|
||||
springLayout.childForceExpandWidth = false;
|
||||
springLayout.childForceExpandHeight = false;
|
||||
springLayout.spacing = 4f;
|
||||
|
||||
// ── 形态图标(Form Icons × 4)────────────────────────────────────
|
||||
const int kFormIconCount = 4;
|
||||
GameObject formIconsRoot = GetOrCreateChild(hudRootGo.transform, "FormIcons").gameObject;
|
||||
Image[] formImages = new Image[kFormIconCount];
|
||||
for (int i = 0; i < kFormIconCount; i++)
|
||||
{
|
||||
GameObject iconGo = GetOrCreateChild(formIconsRoot.transform, $"FormIcon_{i}").gameObject;
|
||||
formImages[i] = GetOrAddComponent<Image>(iconGo);
|
||||
}
|
||||
|
||||
// ── 交互提示(InteractPrompt)─────────────────────────────────────
|
||||
GameObject interactPromptGo = GetOrCreateChild(hudRootGo.transform, "InteractPrompt").gameObject;
|
||||
InteractPromptWidget interactWidget = GetOrAddComponent<InteractPromptWidget>(interactPromptGo);
|
||||
|
||||
GameObject promptRootGo = GetOrCreateChild(interactPromptGo.transform, "Root").gameObject;
|
||||
GameObject promptKeyIconGo = GetOrCreateChild(promptRootGo.transform, "KeyIcon").gameObject;
|
||||
Image keyIcon = GetOrAddComponent<Image>(promptKeyIconGo);
|
||||
GameObject promptLabelGo = GetOrCreateChild(promptRootGo.transform, "LabelText").gameObject;
|
||||
TMP_Text promptLabel = GetOrAddComponent<TextMeshProUGUI>(promptLabelGo);
|
||||
promptLabel.text = "互动";
|
||||
promptRootGo.SetActive(false);
|
||||
|
||||
AssignRef(interactWidget, "_keyIcon", keyIcon);
|
||||
AssignRef(interactWidget, "_labelText", promptLabel);
|
||||
AssignRef(interactWidget, "_root", promptRootGo);
|
||||
|
||||
// ── 法术槽(SpellSlot)───────────────────────────────────────────
|
||||
GameObject spellSlotGo = GetOrCreateChild(hudRootGo.transform, "SpellSlot").gameObject;
|
||||
SpellSlotWidget spellWidget = GetOrAddComponent<SpellSlotWidget>(spellSlotGo);
|
||||
|
||||
GameObject spellIconGo = GetOrCreateChild(spellSlotGo.transform, "IconImage").gameObject;
|
||||
Image spellIcon = GetOrAddComponent<Image>(spellIconGo);
|
||||
GameObject spellCdGo = GetOrCreateChild(spellSlotGo.transform, "CooldownFill").gameObject;
|
||||
Image spellCd = GetOrAddComponent<Image>(spellCdGo);
|
||||
spellCd.type = Image.Type.Filled;
|
||||
spellCd.fillMethod = Image.FillMethod.Radial360;
|
||||
spellCd.fillAmount = 0f;
|
||||
GameObject spellEmptyGo = GetOrCreateChild(spellSlotGo.transform, "EmptySlot").gameObject;
|
||||
|
||||
AssignRef(spellWidget, "_iconImage", spellIcon);
|
||||
AssignRef(spellWidget, "_cooldownFill", spellCd);
|
||||
AssignRef(spellWidget, "_emptySlot", spellEmptyGo);
|
||||
|
||||
// ── 工具栏(ToolHUD × 2 slots)──────────────────────────────────
|
||||
GameObject toolHUDGo = GetOrCreateChild(hudRootGo.transform, "ToolHUD").gameObject;
|
||||
ToolHUD toolHUD = GetOrAddComponent<ToolHUD>(toolHUDGo);
|
||||
const int kToolSlotCount = 2;
|
||||
var toolSlots = new ToolSlotUI[kToolSlotCount];
|
||||
|
||||
for (int i = 0; i < kToolSlotCount; i++)
|
||||
{
|
||||
GameObject slotGo = GetOrCreateChild(toolHUDGo.transform, $"ToolSlot_{i}").gameObject;
|
||||
ToolSlotUI slotUI = GetOrAddComponent<ToolSlotUI>(slotGo);
|
||||
|
||||
GameObject iconGo = GetOrCreateChild(slotGo.transform, "Icon").gameObject;
|
||||
Image slotIcon = GetOrAddComponent<Image>(iconGo);
|
||||
GameObject usesGo = GetOrCreateChild(slotGo.transform, "UsesText").gameObject;
|
||||
TMP_Text usesText = GetOrAddComponent<TextMeshProUGUI>(usesGo);
|
||||
usesText.text = "0";
|
||||
GameObject cdGo = GetOrCreateChild(slotGo.transform, "CooldownMask").gameObject;
|
||||
Image cdMask = GetOrAddComponent<Image>(cdGo);
|
||||
cdMask.type = Image.Type.Filled;
|
||||
cdMask.fillMethod = Image.FillMethod.Horizontal;
|
||||
cdMask.fillAmount = 0f;
|
||||
|
||||
AssignRef(slotUI, "_icon", slotIcon);
|
||||
AssignRef(slotUI, "_usesText", usesText);
|
||||
AssignRef(slotUI, "_cooldownMask", cdMask);
|
||||
toolSlots[i] = slotUI;
|
||||
}
|
||||
|
||||
AssignArrayRefs(toolHUD, "_slots", toolSlots, report);
|
||||
|
||||
// ── Boss 血条(BossHPBar)────────────────────────────────────────
|
||||
GameObject bossBarGo = GetOrCreateChild(hudRootGo.transform, "BossHPBar").gameObject;
|
||||
bossBarGo.SetActive(false);
|
||||
BossHPBar bossHPBar = GetOrAddComponent<BossHPBar>(bossBarGo);
|
||||
|
||||
GameObject bossNameGo = GetOrCreateChild(bossBarGo.transform, "BossName").gameObject;
|
||||
TMP_Text bossName = GetOrAddComponent<TextMeshProUGUI>(bossNameGo);
|
||||
bossName.text = "Boss 名称";
|
||||
GameObject bossHPFillGo = GetOrCreateChild(bossBarGo.transform, "HPFill").gameObject;
|
||||
Image bossHPFill = GetOrAddComponent<Image>(bossHPFillGo);
|
||||
bossHPFill.type = Image.Type.Filled;
|
||||
bossHPFill.fillMethod = Image.FillMethod.Horizontal;
|
||||
bossHPFill.fillAmount = 1f;
|
||||
GameObject phaseRootGo = GetOrCreateChild(bossBarGo.transform, "PhaseMarkersRoot").gameObject;
|
||||
|
||||
AssignRef(bossHPBar, "_bossNameText", bossName);
|
||||
AssignRef(bossHPBar, "_hpFill", bossHPFill);
|
||||
AssignRef(bossHPBar, "_phaseMarkersRoot", phaseRootGo.transform);
|
||||
|
||||
// ── 状态效果 HUD(StatusEffectHUD)──────────────────────────────
|
||||
GameObject statusHUDGo = GetOrCreateChild(hudRootGo.transform, "StatusEffectHUD").gameObject;
|
||||
StatusEffectHUD statusHUD = GetOrAddComponent<StatusEffectHUD>(statusHUDGo);
|
||||
|
||||
GameObject statusTemplateGo = GetOrCreateChild(statusHUDGo.transform, "SlotTemplate").gameObject;
|
||||
statusTemplateGo.SetActive(false);
|
||||
GetOrAddComponent<Image>(statusTemplateGo);
|
||||
GameObject statusContainerGo = GetOrCreateChild(statusHUDGo.transform, "Container").gameObject;
|
||||
var statusLayout = GetOrAddComponent<HorizontalLayoutGroup>(statusContainerGo);
|
||||
statusLayout.childForceExpandWidth = false;
|
||||
statusLayout.spacing = 4f;
|
||||
|
||||
AssignRef(statusHUD, "_slotTemplate", statusTemplateGo);
|
||||
AssignRef(statusHUD, "_container", statusContainerGo.transform);
|
||||
|
||||
// ── 任务追踪(QuestTracker)──────────────────────────────────────
|
||||
GameObject questTrackerGo = GetOrCreateChild(hudRootGo.transform, "QuestTracker").gameObject;
|
||||
QuestTrackerWidget questWidget = GetOrAddComponent<QuestTrackerWidget>(questTrackerGo);
|
||||
|
||||
GameObject questTitleGo = GetOrCreateChild(questTrackerGo.transform, "QuestTitle").gameObject;
|
||||
TMP_Text questTitle = GetOrAddComponent<TextMeshProUGUI>(questTitleGo);
|
||||
questTitle.text = "任务名称";
|
||||
GameObject objTemplateGo = GetOrCreateChild(questTrackerGo.transform, "ObjectiveRowTemplate").gameObject;
|
||||
objTemplateGo.SetActive(false);
|
||||
GetOrAddComponent<TextMeshProUGUI>(objTemplateGo);
|
||||
GameObject objContainerGo = GetOrCreateChild(questTrackerGo.transform, "ObjectiveContainer").gameObject;
|
||||
var objLayout = GetOrAddComponent<VerticalLayoutGroup>(objContainerGo);
|
||||
objLayout.childForceExpandWidth = false;
|
||||
objLayout.spacing = 2f;
|
||||
|
||||
AssignRef(questWidget, "_questTitleText", questTitle);
|
||||
AssignRef(questWidget, "_objectiveRowTemplate", objTemplateGo);
|
||||
AssignRef(questWidget, "_objectiveContainer", objContainerGo.transform);
|
||||
|
||||
// ── HUDController 子组件引用 ──────────────────────────────────────
|
||||
AssignRef(hudCtrl, "_hpContainer", hpContainerGo.transform);
|
||||
AssignRef(hudCtrl, "_soulGaugeFill", soulFill);
|
||||
AssignRef(hudCtrl, "_spiritGaugeFill", spiritFill);
|
||||
AssignRef(hudCtrl, "_lingZhuText", lingZhuText);
|
||||
AssignRef(hudCtrl, "_springContainer", springContainerGo.transform);
|
||||
AssignRef(hudCtrl, "_interactPromptWidget", interactWidget);
|
||||
AssignArrayRefs(hudCtrl, "_formIcons", formImages, report);
|
||||
|
||||
// ── 事件频道 ──────────────────────────────────────────────────────
|
||||
AssignAsset(hudCtrl, "_onHPChanged", report, true, "EVT_HPChanged", "EVT_PlayerHPChanged");
|
||||
AssignAsset(hudCtrl, "_onMaxHPChanged", report, false, "EVT_MaxHPChanged", "EVT_PlayerMaxHPChanged");
|
||||
AssignAsset(hudCtrl, "_onSoulPowerChanged", report, false, "EVT_SoulPowerChanged", "EVT_MagicPowerChanged");
|
||||
AssignAsset(hudCtrl, "_onSpiritPowerChanged", report, false, "EVT_SpiritPowerChanged");
|
||||
AssignAsset(hudCtrl, "_onLingZhuChanged", report, false, "EVT_LingZhuChanged", "EVT_CurrencyChanged");
|
||||
AssignAsset(hudCtrl, "_onSpringChargesChanged", report, false, "EVT_SpringChargesChanged", "EVT_SpringCharges");
|
||||
AssignAsset(hudCtrl, "_onFormChanged", report, false, "EVT_FormChanged");
|
||||
|
||||
AssignAsset(interactWidget, "_onShowPrompt", report, false, "EVT_ShowInteractPrompt", "EVT_InteractPromptShow");
|
||||
AssignAsset(interactWidget, "_onHidePrompt", report, false, "EVT_HideInteractPrompt", "EVT_InteractPromptHide");
|
||||
|
||||
AssignAsset(bossHPBar, "_onBossFightToggled", report, false, "EVT_BossFightToggled", "EVT_BossFightStarted");
|
||||
AssignAsset(bossHPBar, "_onBossHPChanged", report, false, "EVT_BossHPChanged");
|
||||
AssignAsset(bossHPBar, "_onBossHPMaxSet", report, false, "EVT_BossHPMaxSet");
|
||||
AssignAsset(bossHPBar, "_onBossNameSet", report, false, "EVT_BossNameSet");
|
||||
AssignAsset(bossHPBar, "_onBossPhaseThreshold", report, false, "EVT_BossPhaseThreshold");
|
||||
|
||||
AssignAsset(statusHUD, "_onStatusEffectApplied", report, false, "EVT_StatusEffectApplied");
|
||||
AssignAsset(statusHUD, "_onStatusEffectExpired", report, false, "EVT_StatusEffectExpired");
|
||||
|
||||
AssignAsset(questWidget, "_onQuestStarted", report, false, "EVT_QuestStarted");
|
||||
AssignAsset(questWidget, "_onQuestCompleted", report, false, "EVT_QuestCompleted");
|
||||
AssignAsset(questWidget, "_onQuestFailed", report, false, "EVT_QuestFailed");
|
||||
AssignAsset(questWidget, "_onQuestAbandoned", report, false, "EVT_QuestAbandoned");
|
||||
AssignAsset(questWidget, "_onQuestReadyToComplete", report, false, "EVT_QuestReadyToComplete");
|
||||
AssignAsset(questWidget, "_onObjectiveBatchUpdated", report, false, "EVT_QuestObjectiveBatchUpdated");
|
||||
|
||||
AssignAsset(toolHUD, "_onToolUsed", report, false, "EVT_ToolUsed");
|
||||
|
||||
// ── 手工步骤说明 ──────────────────────────────────────────────────
|
||||
report.Add("HUDController._hpCellPrefab:请将 HP 格子 Prefab 赋给该字段。");
|
||||
report.Add("HUDController._springIconPrefab:请将回春图标 Prefab 赋给该字段。");
|
||||
report.Add("BossHPBar._phaseMarkerPrefab:请将阶段标记点 Prefab 赋给该字段。");
|
||||
report.Add("StatusEffectHUD._slotConfigs:请在 Inspector 中配置各状态效果的图标映射。");
|
||||
|
||||
Undo.CollapseUndoOperations(undoGroup);
|
||||
MarkDirtyAndLog("HUD Canvas 脚手架", canvasGo, report);
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────
|
||||
// Private helpers
|
||||
// ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>
|
||||
/// 在活动场景中查找或创建 HUD Canvas。
|
||||
/// 查找顺序:
|
||||
/// 1. 遍历场景根节点中的直接同名节点
|
||||
/// 2. 遍历各根节点下的 [UI]/UIRoot/{name} 或 UIRoot/{name} 子路径
|
||||
/// 若均不存在则新建 Canvas,并优先挂载至 UIRoot(兼容 ScaffoldPersistentScene 层级);
|
||||
/// 若场景中不存在 UIRoot,则回退到场景根层并发出警告。
|
||||
/// </summary>
|
||||
private static GameObject GetOrCreateRootCanvas(string name, int sortOrder)
|
||||
{
|
||||
Scene scene = SceneManager.GetActiveScene();
|
||||
|
||||
// ── Phase 1: 搜索已存在的 Canvas ─────────────────────────────────
|
||||
foreach (GameObject root in scene.GetRootGameObjects())
|
||||
{
|
||||
if (root.name == name)
|
||||
return root;
|
||||
|
||||
// 兼容 ScaffoldPersistentScene 层级:[Persistent] ▸ [UI] ▸ UIRoot ▸ HUD Canvas
|
||||
foreach (string path in new[] { $"[UI]/UIRoot/{name}", $"UIRoot/{name}", name })
|
||||
{
|
||||
Transform found = root.transform.Find(path);
|
||||
if (found != null) return found.gameObject;
|
||||
}
|
||||
}
|
||||
|
||||
// ── Phase 2: 定位 UIRoot(Canvas 的正确父节点)───────────────────
|
||||
Transform uiRoot = null;
|
||||
foreach (GameObject root in scene.GetRootGameObjects())
|
||||
{
|
||||
uiRoot = root.transform.Find("[UI]/UIRoot")
|
||||
?? root.transform.Find("UIRoot");
|
||||
if (uiRoot != null) break;
|
||||
}
|
||||
|
||||
if (uiRoot == null)
|
||||
Debug.LogWarning(
|
||||
"[HUDScaffold] 未找到 UIRoot(期望路径:[Persistent]/[UI]/UIRoot)。" +
|
||||
"将在场景根层创建 HUD Canvas。建议先执行 BaseGames/Scene/Setup/Scaffold Persistent Scene。");
|
||||
|
||||
// ── Phase 3: 创建 Canvas 并挂载至正确父节点 ──────────────────────
|
||||
GameObject canvasGo = new GameObject(name);
|
||||
Undo.RegisterCreatedObjectUndo(canvasGo, $"Create {name}");
|
||||
|
||||
if (uiRoot != null)
|
||||
canvasGo.transform.SetParent(uiRoot, false);
|
||||
|
||||
Canvas canvas = canvasGo.AddComponent<Canvas>();
|
||||
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
|
||||
canvas.sortingOrder = sortOrder;
|
||||
|
||||
CanvasScaler scaler = canvasGo.AddComponent<CanvasScaler>();
|
||||
scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
|
||||
scaler.referenceResolution = new Vector2(1920, 1080);
|
||||
|
||||
canvasGo.AddComponent<GraphicRaycaster>();
|
||||
return canvasGo;
|
||||
}
|
||||
|
||||
private static Transform GetOrCreateChild(Transform parent, string name)
|
||||
{
|
||||
Transform child = parent.Find(name);
|
||||
if (child != null) return child;
|
||||
|
||||
GameObject go = new GameObject(name);
|
||||
Undo.RegisterCreatedObjectUndo(go, $"Create {name}");
|
||||
go.transform.SetParent(parent, false);
|
||||
return go.transform;
|
||||
}
|
||||
|
||||
private static T GetOrAddComponent<T>(GameObject go) where T : Component
|
||||
{
|
||||
T c = go.GetComponent<T>();
|
||||
return c != null ? c : Undo.AddComponent<T>(go);
|
||||
}
|
||||
|
||||
private static void AssignRef(Object target, string propertyName, Object value)
|
||||
{
|
||||
var so = new SerializedObject(target);
|
||||
var prop = so.FindProperty(propertyName);
|
||||
if (prop == null)
|
||||
{
|
||||
Debug.LogWarning($"[HUDScaffold] 未找到属性 {target.GetType().Name}.{propertyName}", target);
|
||||
return;
|
||||
}
|
||||
prop.objectReferenceValue = value;
|
||||
so.ApplyModifiedPropertiesWithoutUndo();
|
||||
}
|
||||
|
||||
private static void AssignArrayRefs<T>(Object target, string propertyName, T[] values, List<string> report)
|
||||
where T : Object
|
||||
{
|
||||
var so = new SerializedObject(target);
|
||||
var prop = so.FindProperty(propertyName);
|
||||
if (prop == null || !prop.isArray)
|
||||
{
|
||||
report.Add($"{target.GetType().Name}.{propertyName} 不是可写数组字段。");
|
||||
return;
|
||||
}
|
||||
prop.arraySize = values.Length;
|
||||
for (int i = 0; i < values.Length; i++)
|
||||
prop.GetArrayElementAtIndex(i).objectReferenceValue = values[i];
|
||||
so.ApplyModifiedPropertiesWithoutUndo();
|
||||
}
|
||||
|
||||
private static void AssignAsset(Object target, string propertyName, List<string> report,
|
||||
bool required, params string[] candidates)
|
||||
{
|
||||
Object asset = FindFirstAsset(candidates);
|
||||
if (asset == null)
|
||||
{
|
||||
if (required)
|
||||
report.Add($"未找到 {target.GetType().Name}.{propertyName} 所需资产: {string.Join(" / ", candidates)}");
|
||||
return;
|
||||
}
|
||||
AssignRef(target, propertyName, asset);
|
||||
}
|
||||
|
||||
private static Object FindFirstAsset(params string[] candidates)
|
||||
{
|
||||
foreach (string candidate in candidates)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(candidate)) continue;
|
||||
string[] guids = AssetDatabase.FindAssets(candidate);
|
||||
foreach (string guid in guids)
|
||||
{
|
||||
string path = AssetDatabase.GUIDToAssetPath(guid);
|
||||
Object asset = AssetDatabase.LoadMainAssetAtPath(path);
|
||||
if (asset != null && asset.name == candidate)
|
||||
return asset;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void MarkDirtyAndLog(string scaffoldName, GameObject root, List<string> report)
|
||||
{
|
||||
EditorSceneManager.MarkSceneDirty(SceneManager.GetActiveScene());
|
||||
Selection.activeGameObject = root;
|
||||
|
||||
if (report.Count == 0)
|
||||
{
|
||||
Debug.Log($"[HUDScaffold] {scaffoldName} 完成。", root);
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.LogWarning(
|
||||
$"[HUDScaffold] {scaffoldName} 完成,以下 {report.Count} 项需手动确认:\n- {string.Join("\n- ", report)}",
|
||||
root);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/_Game/Scripts/Editor/UI/HUDScaffoldWizard.cs.meta
Normal file
11
Assets/_Game/Scripts/Editor/UI/HUDScaffoldWizard.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 74e18b6a781df434c86d28bb3bf54101
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user