From 0b6dc2653f6bec534988672800e6e83b3c0e461e Mon Sep 17 00:00:00 2001 From: ksh999000 <740612340@qq.com> Date: Sat, 4 Jul 2026 12:15:13 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0game=20HUD=20=E7=95=8C?= =?UTF-8?q?=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2.5D Engine/Scripts/CameraFollow.cs | 10 +- .../2.5D Engine/Scripts/HealthSystem.cs | 4 +- unity/Assets/Editor/UIBuilder.cs | 222 +- unity/Assets/Light/scripts/LightMaskSystem.cs | 3 +- unity/Assets/Scenes/Gameplay.unity | 2143 +++++++++++---- unity/Assets/Scenes/MainMenu.unity | 2341 +++++++++++++++++ unity/Assets/UI/Art/HUD/bg.png | Bin 0 -> 8623 bytes unity/Assets/UI/Art/HUD/bg.png.meta | 175 ++ unity/Assets/UI/Art/HUD/life_icon.png | Bin 0 -> 10899 bytes unity/Assets/UI/Art/HUD/life_icon.png.meta | 175 ++ unity/Assets/UI/Art/HUD/skill_bell.png | Bin 0 -> 52789 bytes unity/Assets/UI/Art/HUD/skill_bell.png.meta | 175 ++ unity/Assets/UI/Art/HUD/skill_lantern.png | Bin 0 -> 45513 bytes .../Assets/UI/Art/HUD/skill_lantern.png.meta | 175 ++ unity/Assets/UI/Art/HUD/skill_sprint.png | Bin 0 -> 45513 bytes unity/Assets/UI/Art/HUD/skill_sprint.png.meta | 175 ++ unity/Assets/UI/Art/HUD/soul_icon.png | Bin 0 -> 10183 bytes unity/Assets/UI/Art/HUD/soul_icon.png.meta | 175 ++ unity/Assets/UI/GameHUD.cs | 161 +- unity/Assets/eco/Prefabs/SpiritLantern.prefab | 2 +- unity/UserSettings/EditorUserSettings.asset | 8 +- 21 files changed, 5347 insertions(+), 597 deletions(-) create mode 100644 unity/Assets/UI/Art/HUD/bg.png create mode 100644 unity/Assets/UI/Art/HUD/bg.png.meta create mode 100644 unity/Assets/UI/Art/HUD/life_icon.png create mode 100644 unity/Assets/UI/Art/HUD/life_icon.png.meta create mode 100644 unity/Assets/UI/Art/HUD/skill_bell.png create mode 100644 unity/Assets/UI/Art/HUD/skill_bell.png.meta create mode 100644 unity/Assets/UI/Art/HUD/skill_lantern.png create mode 100644 unity/Assets/UI/Art/HUD/skill_lantern.png.meta create mode 100644 unity/Assets/UI/Art/HUD/skill_sprint.png create mode 100644 unity/Assets/UI/Art/HUD/skill_sprint.png.meta create mode 100644 unity/Assets/UI/Art/HUD/soul_icon.png create mode 100644 unity/Assets/UI/Art/HUD/soul_icon.png.meta diff --git a/unity/Assets/2.5D Engine/Scripts/CameraFollow.cs b/unity/Assets/2.5D Engine/Scripts/CameraFollow.cs index 870348b..1234629 100644 --- a/unity/Assets/2.5D Engine/Scripts/CameraFollow.cs +++ b/unity/Assets/2.5D Engine/Scripts/CameraFollow.cs @@ -10,12 +10,16 @@ namespace IndianOceanAssets.Engine2_5D // The positional offset from the target. [SerializeField] private Vector3 offset; - // Called once per frame. - private void Update() + [Tooltip("跟随平滑度(值越大跟随越紧密,10=几乎即时跟随)")] + [SerializeField] private float followSmoothness = 20f; + + // Called once per frame — 使用 LateUpdate 确保在 FixedUpdate 物理移动之后执行, + // 与 LightMaskSystem 的 LateUpdate 同步,避免光照抖动 + private void LateUpdate() { // If a target is assigned, smoothly move the camera towards the target's position plus the offset. if (target) - transform.position = Vector3.Lerp(transform.position, target.position + offset, Time.deltaTime * 8f); + transform.position = Vector3.Lerp(transform.position, target.position + offset, Time.deltaTime * followSmoothness); } } } \ No newline at end of file diff --git a/unity/Assets/2.5D Engine/Scripts/HealthSystem.cs b/unity/Assets/2.5D Engine/Scripts/HealthSystem.cs index a7d2f36..51ddc50 100644 --- a/unity/Assets/2.5D Engine/Scripts/HealthSystem.cs +++ b/unity/Assets/2.5D Engine/Scripts/HealthSystem.cs @@ -7,8 +7,8 @@ namespace IndianOceanAssets.Engine2_5D { [Range(1, 100)] [SerializeField] - private int maxHealth = 100; // Maximum health - private int health = 100; // Current health + private int maxHealth = 5; // Maximum health + private int health = 5; // Current health [SerializeField] private GameObject deathEffect; // Effect prefab on death diff --git a/unity/Assets/Editor/UIBuilder.cs b/unity/Assets/Editor/UIBuilder.cs index 804853a..a7d4ff8 100644 --- a/unity/Assets/Editor/UIBuilder.cs +++ b/unity/Assets/Editor/UIBuilder.cs @@ -132,6 +132,13 @@ public static class UIBuilder [MenuItem("Tools/搭建 HUD Canvas")] public static void BuildHUD() { + // 加载 HUD 美术资源(可选,没有则用占位) + var soulIconSprite = AssetDatabase.LoadAssetAtPath("Assets/UI/Art/HUD/soul_icon.png"); + var lifeIconSprite = AssetDatabase.LoadAssetAtPath("Assets/UI/Art/HUD/life_icon.png"); + var sprintIconSprite = AssetDatabase.LoadAssetAtPath("Assets/UI/Art/HUD/skill_sprint.png"); + var bellIconSprite = AssetDatabase.LoadAssetAtPath("Assets/UI/Art/HUD/skill_bell.png"); + var lanternIconSprite = AssetDatabase.LoadAssetAtPath("Assets/UI/Art/HUD/skill_lantern.png"); + // 创建 HUD Canvas var hudCanvasObj = new GameObject("HUD_Canvas"); var canvas = hudCanvasObj.AddComponent(); @@ -143,104 +150,89 @@ public static class UIBuilder // 添加 GameHUD 脚本 var hud = hudCanvasObj.AddComponent(); + var so = new SerializedObject(hud); - // ===== 左上角:血量区域 ===== - var healthArea = CreateChild(hudCanvasObj, "HealthArea", new Vector2(20, -20)); - var healthLayout = healthArea.AddComponent(); - healthLayout.spacing = 5; - healthLayout.childForceExpandWidth = false; - healthLayout.childForceExpandHeight = false; - healthArea.AddComponent().verticalFit = ContentSizeFitter.FitMode.PreferredSize; + // ===== 左上角:魂灵计数 ===== + var soulArea = CreateChild(hudCanvasObj, "SoulArea", new Vector2(20, -20)); + var soulLayout = soulArea.AddComponent(); + soulLayout.spacing = 8; + soulLayout.childForceExpandWidth = false; + soulLayout.childForceExpandHeight = true; + soulLayout.childAlignment = TextAnchor.MiddleLeft; + soulArea.AddComponent().horizontalFit = ContentSizeFitter.FitMode.PreferredSize; - // 血量 Slider - var sliderObj = new GameObject("HealthSlider"); - sliderObj.transform.SetParent(healthArea.transform, false); - var slider = sliderObj.AddComponent(); - slider.minValue = 0; - slider.maxValue = 1; - slider.value = 1; - slider.interactable = false; - var sliderRect = sliderObj.GetComponent(); - 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(); - // Slider 背景 - var sliderBg = new GameObject("Background"); - sliderBg.transform.SetParent(sliderObj.transform, false); - var bgImage = sliderBg.AddComponent(); - bgImage.color = new Color(0.2f, 0.2f, 0.2f, 0.8f); - var bgRect = sliderBg.GetComponent(); - bgRect.anchorMin = Vector2.zero; - bgRect.anchorMax = Vector2.one; - bgRect.sizeDelta = Vector2.zero; + // 魂灵数字 + var soulCountObj = CreateText(soulArea.transform, "SoulCount", "0", 28, TextAnchor.MiddleLeft); + soulCountObj.GetComponent().fontStyle = FontStyle.Bold; + soulCountObj.GetComponent().sizeDelta = new Vector2(60, 40); + so.FindProperty("soulCountText").objectReferenceValue = soulCountObj.GetComponent(); - // Slider 填充区域 - var fillArea = new GameObject("Fill Area"); - fillArea.transform.SetParent(sliderObj.transform, false); - var fillAreaRect = fillArea.AddComponent(); - 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(); + 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(); - fillImage.color = new Color(0.8f, 0.1f, 0.1f, 0.9f); - var fillRect = fill.GetComponent(); - fillRect.anchorMin = Vector2.zero; - fillRect.anchorMax = Vector2.one; - fillRect.sizeDelta = Vector2.zero; + var lifeLayout = lifeArea.AddComponent(); + 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(); + } - // 血量文字 - var healthTextObj = CreateText(healthArea.transform, "HealthText", "100/100", 14, TextAnchor.MiddleLeft); - healthTextObj.GetComponent().sizeDelta = new Vector2(200, 20); + // ===== 右下角:技能图标(冲刺/摇铃/灵灯) ===== + var skillArea = CreateChild(hudCanvasObj, "SkillArea", new Vector2(-20, -20)); + var skillAreaRect = skillArea.GetComponent(); + 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(); - lanternLayout.spacing = 3; - lanternLayout.childForceExpandWidth = false; - lanternLayout.childForceExpandHeight = false; - lanternArea.AddComponent().verticalFit = ContentSizeFitter.FitMode.PreferredSize; + var skillLayout = skillArea.AddComponent(); + 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().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(); + so.FindProperty("skillSprintCD").objectReferenceValue = sprintObj.transform.Find("CDOverlay").GetComponent(); - var lanternCDObj = CreateText(lanternArea.transform, "LanternCD", "就绪", 14, TextAnchor.MiddleLeft); - lanternCDObj.GetComponent().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(); + so.FindProperty("skillBellCD").objectReferenceValue = bellObj.transform.Find("CDOverlay").GetComponent(); - // ===== 右上角:分数 + 暂停 ===== + // 灵灯技能 + var lanternObj = CreateSkillIcon(skillArea.transform, "SkillLantern", lanternIconSprite, new Color(1f, 0.6f, 0.2f)); + so.FindProperty("skillLanternIcon").objectReferenceValue = lanternObj.transform.Find("Icon").GetComponent(); + so.FindProperty("skillLanternCD").objectReferenceValue = lanternObj.transform.Find("CDOverlay").GetComponent(); + + // ===== 右上角:暂停按钮 ===== var topRight = CreateChild(hudCanvasObj, "TopRight", new Vector2(-20, -20)); var topRightRect = topRight.GetComponent(); topRightRect.anchorMin = new Vector2(1, 1); topRightRect.anchorMax = new Vector2(1, 1); topRightRect.pivot = new Vector2(1, 1); - - var topRightLayout = topRight.AddComponent(); - topRightLayout.spacing = 8; - topRightLayout.childForceExpandWidth = false; - topRightLayout.childForceExpandHeight = false; - topRightLayout.childAlignment = TextAnchor.UpperRight; - topRight.AddComponent().verticalFit = ContentSizeFitter.FitMode.PreferredSize; - - var scoreObj = CreateText(topRight.transform, "ScoreText", "分数: 0", 20, TextAnchor.MiddleRight); - scoreObj.GetComponent().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(); - so.FindProperty("lanternCountText").objectReferenceValue = lanternCountObj.GetComponent(); - so.FindProperty("lanternCDText").objectReferenceValue = lanternCDObj.GetComponent(); - so.FindProperty("scoreText").objectReferenceValue = scoreObj.GetComponent(); + var pauseObj = CreateButton(topRight.transform, "PauseButton", "||", new Vector2(50, 50)); so.FindProperty("pauseButton").objectReferenceValue = pauseObj.GetComponent