更新game HUD 界面

This commit is contained in:
2026-07-04 12:15:13 +08:00
parent 58d1f54e0d
commit 0b6dc2653f
21 changed files with 5347 additions and 597 deletions
+142 -80
View File
@@ -132,6 +132,13 @@ public static class UIBuilder
[MenuItem("Tools/搭建 HUD Canvas")]
public static void BuildHUD()
{
// 加载 HUD 美术资源(可选,没有则用占位)
var soulIconSprite = AssetDatabase.LoadAssetAtPath<Sprite>("Assets/UI/Art/HUD/soul_icon.png");
var lifeIconSprite = AssetDatabase.LoadAssetAtPath<Sprite>("Assets/UI/Art/HUD/life_icon.png");
var sprintIconSprite = AssetDatabase.LoadAssetAtPath<Sprite>("Assets/UI/Art/HUD/skill_sprint.png");
var bellIconSprite = AssetDatabase.LoadAssetAtPath<Sprite>("Assets/UI/Art/HUD/skill_bell.png");
var lanternIconSprite = AssetDatabase.LoadAssetAtPath<Sprite>("Assets/UI/Art/HUD/skill_lantern.png");
// 创建 HUD Canvas
var hudCanvasObj = new GameObject("HUD_Canvas");
var canvas = hudCanvasObj.AddComponent<Canvas>();
@@ -143,104 +150,89 @@ public static class UIBuilder
// 添加 GameHUD 脚本
var hud = hudCanvasObj.AddComponent<GameHUD>();
var so = new SerializedObject(hud);
// ===== 左上角:血量区域 =====
var healthArea = CreateChild(hudCanvasObj, "HealthArea", new Vector2(20, -20));
var healthLayout = healthArea.AddComponent<VerticalLayoutGroup>();
healthLayout.spacing = 5;
healthLayout.childForceExpandWidth = false;
healthLayout.childForceExpandHeight = false;
healthArea.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
// ===== 左上角:魂灵计数 =====
var soulArea = CreateChild(hudCanvasObj, "SoulArea", new Vector2(20, -20));
var soulLayout = soulArea.AddComponent<HorizontalLayoutGroup>();
soulLayout.spacing = 8;
soulLayout.childForceExpandWidth = false;
soulLayout.childForceExpandHeight = true;
soulLayout.childAlignment = TextAnchor.MiddleLeft;
soulArea.AddComponent<ContentSizeFitter>().horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
// 血量 Slider
var sliderObj = new GameObject("HealthSlider");
sliderObj.transform.SetParent(healthArea.transform, false);
var slider = sliderObj.AddComponent<Slider>();
slider.minValue = 0;
slider.maxValue = 1;
slider.value = 1;
slider.interactable = false;
var sliderRect = sliderObj.GetComponent<RectTransform>();
sliderRect.sizeDelta = new Vector2(200, 20);
// 魂灵 Icon
var soulIconObj = CreateIcon(soulArea.transform, "SoulIcon", soulIconSprite, new Vector2(40, 40), Color.cyan);
so.FindProperty("soulIcon").objectReferenceValue = soulIconObj.GetComponent<Image>();
// Slider 背景
var sliderBg = new GameObject("Background");
sliderBg.transform.SetParent(sliderObj.transform, false);
var bgImage = sliderBg.AddComponent<Image>();
bgImage.color = new Color(0.2f, 0.2f, 0.2f, 0.8f);
var bgRect = sliderBg.GetComponent<RectTransform>();
bgRect.anchorMin = Vector2.zero;
bgRect.anchorMax = Vector2.one;
bgRect.sizeDelta = Vector2.zero;
// 魂灵数字
var soulCountObj = CreateText(soulArea.transform, "SoulCount", "0", 28, TextAnchor.MiddleLeft);
soulCountObj.GetComponent<Text>().fontStyle = FontStyle.Bold;
soulCountObj.GetComponent<RectTransform>().sizeDelta = new Vector2(60, 40);
so.FindProperty("soulCountText").objectReferenceValue = soulCountObj.GetComponent<Text>();
// Slider 填充区域
var fillArea = new GameObject("Fill Area");
fillArea.transform.SetParent(sliderObj.transform, false);
var fillAreaRect = fillArea.AddComponent<RectTransform>();
fillAreaRect.anchorMin = new Vector2(0, 0);
fillAreaRect.anchorMax = new Vector2(1, 1);
fillAreaRect.sizeDelta = Vector2.zero;
// ===== 左下角:生命图标(5个) =====
var lifeArea = CreateChild(hudCanvasObj, "LifeArea", new Vector2(20, -20));
var lifeAreaRect = lifeArea.GetComponent<RectTransform>();
lifeAreaRect.anchorMin = new Vector2(0, 0);
lifeAreaRect.anchorMax = new Vector2(0, 0);
lifeAreaRect.pivot = new Vector2(0, 0);
lifeAreaRect.anchoredPosition = new Vector2(20, 20);
var fill = new GameObject("Fill");
fill.transform.SetParent(fillArea.transform, false);
var fillImage = fill.AddComponent<Image>();
fillImage.color = new Color(0.8f, 0.1f, 0.1f, 0.9f);
var fillRect = fill.GetComponent<RectTransform>();
fillRect.anchorMin = Vector2.zero;
fillRect.anchorMax = Vector2.one;
fillRect.sizeDelta = Vector2.zero;
var lifeLayout = lifeArea.AddComponent<HorizontalLayoutGroup>();
lifeLayout.spacing = 5;
lifeLayout.childForceExpandWidth = false;
lifeLayout.childForceExpandHeight = true;
lifeLayout.childAlignment = TextAnchor.LowerLeft;
slider.fillRect = fillRect;
var lifeIconsProp = so.FindProperty("lifeIcons");
lifeIconsProp.arraySize = 5;
for (int i = 0; i < 5; i++)
{
var lifeIconObj = CreateIcon(lifeArea.transform, $"LifeIcon_{i}", lifeIconSprite, new Vector2(36, 36), Color.red);
lifeIconsProp.GetArrayElementAtIndex(i).objectReferenceValue = lifeIconObj.GetComponent<Image>();
}
// 血量文字
var healthTextObj = CreateText(healthArea.transform, "HealthText", "100/100", 14, TextAnchor.MiddleLeft);
healthTextObj.GetComponent<RectTransform>().sizeDelta = new Vector2(200, 20);
// ===== 右下角:技能图标(冲刺/摇铃/灵灯) =====
var skillArea = CreateChild(hudCanvasObj, "SkillArea", new Vector2(-20, -20));
var skillAreaRect = skillArea.GetComponent<RectTransform>();
skillAreaRect.anchorMin = new Vector2(1, 0);
skillAreaRect.anchorMax = new Vector2(1, 0);
skillAreaRect.pivot = new Vector2(1, 0);
skillAreaRect.anchoredPosition = new Vector2(-20, 20);
// ===== 左上角下方:灵灯区域 =====
var lanternArea = CreateChild(hudCanvasObj, "LanternArea", new Vector2(20, -80));
var lanternLayout = lanternArea.AddComponent<VerticalLayoutGroup>();
lanternLayout.spacing = 3;
lanternLayout.childForceExpandWidth = false;
lanternLayout.childForceExpandHeight = false;
lanternArea.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
var skillLayout = skillArea.AddComponent<HorizontalLayoutGroup>();
skillLayout.spacing = 12;
skillLayout.childForceExpandWidth = false;
skillLayout.childForceExpandHeight = true;
skillLayout.childAlignment = TextAnchor.LowerRight;
var lanternCountObj = CreateText(lanternArea.transform, "LanternCount", "灵灯: 5", 16, TextAnchor.MiddleLeft);
lanternCountObj.GetComponent<RectTransform>().sizeDelta = new Vector2(200, 24);
// 冲刺技能
var sprintObj = CreateSkillIcon(skillArea.transform, "SkillSprint", sprintIconSprite, new Color(0.3f, 0.8f, 1f));
so.FindProperty("skillSprintIcon").objectReferenceValue = sprintObj.transform.Find("Icon").GetComponent<Image>();
so.FindProperty("skillSprintCD").objectReferenceValue = sprintObj.transform.Find("CDOverlay").GetComponent<Image>();
var lanternCDObj = CreateText(lanternArea.transform, "LanternCD", "就绪", 14, TextAnchor.MiddleLeft);
lanternCDObj.GetComponent<RectTransform>().sizeDelta = new Vector2(200, 20);
// 摇铃技能
var bellObj = CreateSkillIcon(skillArea.transform, "SkillBell", bellIconSprite, new Color(1f, 0.85f, 0.2f));
so.FindProperty("skillBellIcon").objectReferenceValue = bellObj.transform.Find("Icon").GetComponent<Image>();
so.FindProperty("skillBellCD").objectReferenceValue = bellObj.transform.Find("CDOverlay").GetComponent<Image>();
// ===== 右上角:分数 + 暂停 =====
// 灵灯技能
var lanternObj = CreateSkillIcon(skillArea.transform, "SkillLantern", lanternIconSprite, new Color(1f, 0.6f, 0.2f));
so.FindProperty("skillLanternIcon").objectReferenceValue = lanternObj.transform.Find("Icon").GetComponent<Image>();
so.FindProperty("skillLanternCD").objectReferenceValue = lanternObj.transform.Find("CDOverlay").GetComponent<Image>();
// ===== 右上角:暂停按钮 =====
var topRight = CreateChild(hudCanvasObj, "TopRight", new Vector2(-20, -20));
var topRightRect = topRight.GetComponent<RectTransform>();
topRightRect.anchorMin = new Vector2(1, 1);
topRightRect.anchorMax = new Vector2(1, 1);
topRightRect.pivot = new Vector2(1, 1);
var topRightLayout = topRight.AddComponent<VerticalLayoutGroup>();
topRightLayout.spacing = 8;
topRightLayout.childForceExpandWidth = false;
topRightLayout.childForceExpandHeight = false;
topRightLayout.childAlignment = TextAnchor.UpperRight;
topRight.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
var scoreObj = CreateText(topRight.transform, "ScoreText", "分数: 0", 20, TextAnchor.MiddleRight);
scoreObj.GetComponent<RectTransform>().sizeDelta = new Vector2(200, 30);
// 暂停按钮
var pauseObj = CreateButton(topRight.transform, "PauseButton", "暂停", new Vector2(100, 35));
// ===== 连接 GameHUD 引用 =====
var so = new SerializedObject(hud);
so.FindProperty("healthSlider").objectReferenceValue = slider;
so.FindProperty("healthText").objectReferenceValue = healthTextObj.GetComponent<Text>();
so.FindProperty("lanternCountText").objectReferenceValue = lanternCountObj.GetComponent<Text>();
so.FindProperty("lanternCDText").objectReferenceValue = lanternCDObj.GetComponent<Text>();
so.FindProperty("scoreText").objectReferenceValue = scoreObj.GetComponent<Text>();
var pauseObj = CreateButton(topRight.transform, "PauseButton", "||", new Vector2(50, 50));
so.FindProperty("pauseButton").objectReferenceValue = pauseObj.GetComponent<Button>();
so.ApplyModifiedProperties();
Debug.Log("[UIBuilder] HUD Canvas 搭建完成");
so.ApplyModifiedProperties();
Debug.Log("[UIBuilder] HUD Canvas 搭建完成(魂灵+生命+技能CD");
}
/// <summary>
@@ -361,6 +353,76 @@ public static class UIBuilder
return btnObj;
}
private static GameObject CreateIcon(Transform parent, string name, Sprite sprite, Vector2 size, Color placeholderColor)
{
var obj = new GameObject(name);
obj.transform.SetParent(parent, false);
obj.AddComponent<RectTransform>().sizeDelta = size;
var img = obj.AddComponent<Image>();
if (sprite != null)
{
img.sprite = sprite;
img.preserveAspect = true;
}
else
{
img.color = placeholderColor; // 占位色
}
return obj;
}
private static GameObject CreateSkillIcon(Transform parent, string name, Sprite sprite, Color cdColor)
{
var container = new GameObject(name);
container.transform.SetParent(parent, false);
container.AddComponent<RectTransform>().sizeDelta = new Vector2(56, 56);
// 背景
var bgObj = new GameObject("BG");
bgObj.transform.SetParent(container.transform, false);
var bgRect = bgObj.AddComponent<RectTransform>();
bgRect.anchorMin = Vector2.zero;
bgRect.anchorMax = Vector2.one;
bgRect.sizeDelta = Vector2.zero;
var bgImg = bgObj.AddComponent<Image>();
bgImg.color = new Color(0.1f, 0.1f, 0.1f, 0.7f);
// 技能图标
var iconObj = new GameObject("Icon");
iconObj.transform.SetParent(container.transform, false);
var iconRect = iconObj.AddComponent<RectTransform>();
iconRect.anchorMin = new Vector2(0.1f, 0.1f);
iconRect.anchorMax = new Vector2(0.9f, 0.9f);
iconRect.sizeDelta = Vector2.zero;
var iconImg = iconObj.AddComponent<Image>();
if (sprite != null)
{
iconImg.sprite = sprite;
iconImg.preserveAspect = true;
}
else
{
iconImg.color = cdColor; // 占位色
}
// CD 遮罩(覆盖在图标上方)
var cdObj = new GameObject("CDOverlay");
cdObj.transform.SetParent(container.transform, false);
var cdRect = cdObj.AddComponent<RectTransform>();
cdRect.anchorMin = Vector2.zero;
cdRect.anchorMax = Vector2.one;
cdRect.sizeDelta = Vector2.zero;
var cdImg = cdObj.AddComponent<Image>();
cdImg.color = new Color(0, 0, 0, 0.6f);
cdImg.type = Image.Type.Filled;
cdImg.fillMethod = Image.FillMethod.Radial360;
cdImg.fillOrigin = 2; // Top
cdImg.fillAmount = 0f;
cdObj.SetActive(false); // 初始无 CD
return container;
}
private static GameObject CreateImageButton(Transform parent, string name, Sprite sprite)
{
var btnObj = new GameObject(name);