From fc585fa67ee5a5a3bfda2da9ec2238ef33361c52 Mon Sep 17 00:00:00 2001 From: ksh999000 <740612340@qq.com> Date: Sat, 4 Jul 2026 16:07:08 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=8F=97=E5=87=BB=E6=B3=9B?= =?UTF-8?q?=E7=BA=A2=E6=95=88=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2.5D Engine/Scripts/HealthSystem.cs | 8 + unity/Assets/Scenes/Gameplay.unity | 87 +++++++++++ unity/Assets/UI/DamageFlashOverlay.cs | 138 ++++++++++++++++++ unity/Assets/UI/DamageFlashOverlay.cs.meta | 11 ++ unity/Assets/UI/GameHUD.cs | 7 + unity/UserSettings/EditorUserSettings.asset | 4 +- 6 files changed, 253 insertions(+), 2 deletions(-) create mode 100644 unity/Assets/UI/DamageFlashOverlay.cs create mode 100644 unity/Assets/UI/DamageFlashOverlay.cs.meta diff --git a/unity/Assets/2.5D Engine/Scripts/HealthSystem.cs b/unity/Assets/2.5D Engine/Scripts/HealthSystem.cs index 52cba1f..ce6c797 100644 --- a/unity/Assets/2.5D Engine/Scripts/HealthSystem.cs +++ b/unity/Assets/2.5D Engine/Scripts/HealthSystem.cs @@ -1,10 +1,14 @@ using UnityEngine; +using System; using GameFramework; namespace IndianOceanAssets.Engine2_5D { // Handles health, damage, and death for entities public class HealthSystem : MonoBehaviour { + /// 玩家受伤时触发(用于受击特效等) + public static Action onPlayerDamaged; + [Range(1, 100)] [SerializeField] private int maxHealth = 5; // Maximum health @@ -31,6 +35,10 @@ namespace IndianOceanAssets.Engine2_5D health -= damageAmount; + // 玩家受伤时触发事件(用于受击泛红特效) + if (isPlayer && onPlayerDamaged != null) + onPlayerDamaged.Invoke(); + // If dead if (health <= 0) { diff --git a/unity/Assets/Scenes/Gameplay.unity b/unity/Assets/Scenes/Gameplay.unity index 27e43da..ad787b5 100644 --- a/unity/Assets/Scenes/Gameplay.unity +++ b/unity/Assets/Scenes/Gameplay.unity @@ -6185,6 +6185,18 @@ PrefabInstance: propertyPath: m_Name value: enemy_05 objectReference: {fileID: 0} + - target: {fileID: 6306576444274981952, guid: 7c1df93486acb4e44bd78734e13d87a0, type: 3} + propertyPath: m_LocalScale.x + value: 0.7 + objectReference: {fileID: 0} + - target: {fileID: 6306576444274981952, guid: 7c1df93486acb4e44bd78734e13d87a0, type: 3} + propertyPath: m_LocalScale.y + value: 0.7 + objectReference: {fileID: 0} + - target: {fileID: 6306576444274981952, guid: 7c1df93486acb4e44bd78734e13d87a0, type: 3} + propertyPath: m_LocalScale.z + value: 0.7 + objectReference: {fileID: 0} - target: {fileID: 6306576444274981952, guid: 7c1df93486acb4e44bd78734e13d87a0, type: 3} propertyPath: m_LocalPosition.x value: 6.49 @@ -6225,6 +6237,10 @@ PrefabInstance: propertyPath: m_LocalEulerAnglesHint.z value: 0 objectReference: {fileID: 0} + - target: {fileID: 6306576444274981952, guid: 7c1df93486acb4e44bd78734e13d87a0, type: 3} + propertyPath: m_ConstrainProportionsScale + value: 1 + objectReference: {fileID: 0} m_RemovedComponents: [] m_RemovedGameObjects: [] m_AddedGameObjects: [] @@ -10212,6 +10228,18 @@ PrefabInstance: serializedVersion: 3 m_TransformParent: {fileID: 0} m_Modifications: + - target: {fileID: 2393803201260214047, guid: 8a195b2e97ff3d24f81953f5aec10187, type: 3} + propertyPath: m_LocalScale.x + value: 0.7 + objectReference: {fileID: 0} + - target: {fileID: 2393803201260214047, guid: 8a195b2e97ff3d24f81953f5aec10187, type: 3} + propertyPath: m_LocalScale.y + value: 0.7 + objectReference: {fileID: 0} + - target: {fileID: 2393803201260214047, guid: 8a195b2e97ff3d24f81953f5aec10187, type: 3} + propertyPath: m_LocalScale.z + value: 0.7 + objectReference: {fileID: 0} - target: {fileID: 2393803201260214047, guid: 8a195b2e97ff3d24f81953f5aec10187, type: 3} propertyPath: m_LocalPosition.x value: 1.4899998 @@ -10252,6 +10280,10 @@ PrefabInstance: propertyPath: m_LocalEulerAnglesHint.z value: 0 objectReference: {fileID: 0} + - target: {fileID: 2393803201260214047, guid: 8a195b2e97ff3d24f81953f5aec10187, type: 3} + propertyPath: m_ConstrainProportionsScale + value: 1 + objectReference: {fileID: 0} - target: {fileID: 8673329150658497095, guid: 8a195b2e97ff3d24f81953f5aec10187, type: 3} propertyPath: m_Name value: enemy_02 @@ -13415,6 +13447,22 @@ PrefabInstance: serializedVersion: 3 m_TransformParent: {fileID: 0} m_Modifications: + - target: {fileID: 1609478081808774938, guid: 6f6889c3968492343b4a748ec94e1d4d, type: 3} + propertyPath: m_LocalPosition.x + value: 2.69 + objectReference: {fileID: 0} + - target: {fileID: 6055015580396346534, guid: 6f6889c3968492343b4a748ec94e1d4d, type: 3} + propertyPath: m_LocalScale.x + value: 0.7 + objectReference: {fileID: 0} + - target: {fileID: 6055015580396346534, guid: 6f6889c3968492343b4a748ec94e1d4d, type: 3} + propertyPath: m_LocalScale.y + value: 0.7 + objectReference: {fileID: 0} + - target: {fileID: 6055015580396346534, guid: 6f6889c3968492343b4a748ec94e1d4d, type: 3} + propertyPath: m_LocalScale.z + value: 0.7 + objectReference: {fileID: 0} - target: {fileID: 6055015580396346534, guid: 6f6889c3968492343b4a748ec94e1d4d, type: 3} propertyPath: m_LocalPosition.x value: 11.49 @@ -13455,6 +13503,10 @@ PrefabInstance: propertyPath: m_LocalEulerAnglesHint.z value: 0 objectReference: {fileID: 0} + - target: {fileID: 6055015580396346534, guid: 6f6889c3968492343b4a748ec94e1d4d, type: 3} + propertyPath: m_ConstrainProportionsScale + value: 1 + objectReference: {fileID: 0} - target: {fileID: 6153816677019540685, guid: 6f6889c3968492343b4a748ec94e1d4d, type: 3} propertyPath: m_Name value: enemy_01 @@ -22068,6 +22120,9 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: gameState: 0 + lightExpandDuration: 1.5 + lightExpandTargetRadius: 20 + fadeOutDuration: 1 --- !u!4 &1385715428 Transform: m_ObjectHideFlags: 0 @@ -32132,6 +32187,18 @@ PrefabInstance: serializedVersion: 3 m_TransformParent: {fileID: 0} m_Modifications: + - target: {fileID: 1123674622178506746, guid: 8f8c995dea0cb274baeaf2a7bdfe1037, type: 3} + propertyPath: m_LocalScale.x + value: 0.7 + objectReference: {fileID: 0} + - target: {fileID: 1123674622178506746, guid: 8f8c995dea0cb274baeaf2a7bdfe1037, type: 3} + propertyPath: m_LocalScale.y + value: 0.7 + objectReference: {fileID: 0} + - target: {fileID: 1123674622178506746, guid: 8f8c995dea0cb274baeaf2a7bdfe1037, type: 3} + propertyPath: m_LocalScale.z + value: 0.7 + objectReference: {fileID: 0} - target: {fileID: 1123674622178506746, guid: 8f8c995dea0cb274baeaf2a7bdfe1037, type: 3} propertyPath: m_LocalPosition.x value: 1.4899998 @@ -32172,6 +32239,10 @@ PrefabInstance: propertyPath: m_LocalEulerAnglesHint.z value: 0 objectReference: {fileID: 0} + - target: {fileID: 1123674622178506746, guid: 8f8c995dea0cb274baeaf2a7bdfe1037, type: 3} + propertyPath: m_ConstrainProportionsScale + value: 1 + objectReference: {fileID: 0} - target: {fileID: 5471001682465061791, guid: 8f8c995dea0cb274baeaf2a7bdfe1037, type: 3} propertyPath: m_Name value: enemy_04 @@ -33851,6 +33922,18 @@ PrefabInstance: serializedVersion: 3 m_TransformParent: {fileID: 0} m_Modifications: + - target: {fileID: 6513886605935214580, guid: 75afe3f1a4ed9f64abe61fa9c3070a7d, type: 3} + propertyPath: m_LocalScale.x + value: 0.7 + objectReference: {fileID: 0} + - target: {fileID: 6513886605935214580, guid: 75afe3f1a4ed9f64abe61fa9c3070a7d, type: 3} + propertyPath: m_LocalScale.y + value: 0.7 + objectReference: {fileID: 0} + - target: {fileID: 6513886605935214580, guid: 75afe3f1a4ed9f64abe61fa9c3070a7d, type: 3} + propertyPath: m_LocalScale.z + value: 0.7 + objectReference: {fileID: 0} - target: {fileID: 6513886605935214580, guid: 75afe3f1a4ed9f64abe61fa9c3070a7d, type: 3} propertyPath: m_LocalPosition.x value: 11.49 @@ -33891,6 +33974,10 @@ PrefabInstance: propertyPath: m_LocalEulerAnglesHint.z value: 0 objectReference: {fileID: 0} + - target: {fileID: 6513886605935214580, guid: 75afe3f1a4ed9f64abe61fa9c3070a7d, type: 3} + propertyPath: m_ConstrainProportionsScale + value: 1 + objectReference: {fileID: 0} - target: {fileID: 9149581610257369843, guid: 75afe3f1a4ed9f64abe61fa9c3070a7d, type: 3} propertyPath: m_Name value: enemy_03 diff --git a/unity/Assets/UI/DamageFlashOverlay.cs b/unity/Assets/UI/DamageFlashOverlay.cs new file mode 100644 index 0000000..2ccbf36 --- /dev/null +++ b/unity/Assets/UI/DamageFlashOverlay.cs @@ -0,0 +1,138 @@ +using UnityEngine; +using UnityEngine.UI; +using IndianOceanAssets.Engine2_5D; + +namespace GameFramework +{ + /// + /// 受击泛红特效 —— 玩家受伤时屏幕四周闪烁红色暗角。 + /// + /// 挂载到场景中任意物体上(或由 GameHUD 自动创建)。 + /// 运行时自动创建全屏暗角遮罩,监听 HealthSystem.onPlayerDamaged 事件。 + /// + public class DamageFlashOverlay : MonoBehaviour + { + [Header("特效参数")] + [Tooltip("受击时暗角最大透明度(0~1)")] + [SerializeField] private float flashAlpha = 0.8f; + + [Tooltip("闪烁淡出时间(秒)")] + [SerializeField] private float fadeDuration = 0.4f; + + [Tooltip("暗角内圈半径(0~1,0=全屏幕红色,1=只有最边缘)")] + [SerializeField] private float innerRadius = 0.8f; + + private Canvas _canvas; + private Image _overlayImage; + private float _currentAlpha; + private bool _isFlashing; + + private void Start() + { + CreateOverlay(); + HealthSystem.onPlayerDamaged += OnPlayerDamaged; + } + + private void OnDestroy() + { + HealthSystem.onPlayerDamaged -= OnPlayerDamaged; + } + + private void Update() + { + if (!_isFlashing) return; + + // 淡出 + _currentAlpha -= Time.unscaledDeltaTime / fadeDuration; + if (_currentAlpha <= 0f) + { + _currentAlpha = 0f; + _isFlashing = false; + _overlayImage.gameObject.SetActive(false); + } + + _overlayImage.color = new Color(1f, 0f, 0f, _currentAlpha); + } + + private void OnPlayerDamaged() + { + // 重置闪烁 + _currentAlpha = flashAlpha; + _isFlashing = true; + _overlayImage.gameObject.SetActive(true); + _overlayImage.color = new Color(1f, 0f, 0f, _currentAlpha); + } + + /// + /// 创建全屏暗角遮罩(运行时生成暗角纹理)。 + /// + private void CreateOverlay() + { + // 创建 Canvas + var canvasObj = new GameObject("DamageFlashCanvas"); + _canvas = canvasObj.AddComponent(); + _canvas.renderMode = RenderMode.ScreenSpaceOverlay; + _canvas.sortingOrder = 10000; // 在 HUD 之上 + canvasObj.AddComponent(); + + // 创建全屏 Image + var imageObj = new GameObject("DamageFlashImage"); + imageObj.transform.SetParent(canvasObj.transform, false); + var rect = imageObj.AddComponent(); + rect.anchorMin = Vector2.zero; + rect.anchorMax = Vector2.one; + rect.sizeDelta = Vector2.zero; + + _overlayImage = imageObj.AddComponent(); + _overlayImage.sprite = CreateVignetteSprite(); + _overlayImage.type = Image.Type.Simple; + _overlayImage.raycastTarget = false; // 不阻挡点击 + imageObj.SetActive(false); // 初始隐藏 + } + + /// + /// 运行时生成暗角纹理(中心透明,边缘红色)。 + /// + private Sprite CreateVignetteSprite() + { + int size = 256; + var texture = new Texture2D(size, size, TextureFormat.RGBA32, false); + var pixels = new Color[size * size]; + + float center = size * 0.5f; + float maxDist = center; // 最大距离(角到中心) + + for (int y = 0; y < size; y++) + { + for (int x = 0; x < size; x++) + { + // 计算到中心的归一化距离 + float dx = (x - center) / center; + float dy = (y - center) / center; + float dist = Mathf.Sqrt(dx * dx + dy * dy); + + // 暗角效果:内圈透明,外圈不透明 + float alpha; + if (dist <= innerRadius) + { + alpha = 0f; + } + else + { + // 从内圈到边缘平滑过渡 + float t = (dist - innerRadius) / (1.414f - innerRadius); // 1.414 = sqrt(2) + alpha = Mathf.SmoothStep(0f, 1f, t); + } + + pixels[y * size + x] = new Color(1f, 0f, 0f, alpha); + } + } + + texture.SetPixels(pixels); + texture.Apply(); + texture.filterMode = FilterMode.Bilinear; + + return Sprite.Create(texture, new Rect(0, 0, size, size), Vector2.one * 0.5f); + } + } +} diff --git a/unity/Assets/UI/DamageFlashOverlay.cs.meta b/unity/Assets/UI/DamageFlashOverlay.cs.meta new file mode 100644 index 0000000..dd82a2f --- /dev/null +++ b/unity/Assets/UI/DamageFlashOverlay.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: DH8Z4XurAC+mXJCLMO3KhftlwfsTEfnqj4q0hJGAb8EiGnEHR1zldgM= +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/unity/Assets/UI/GameHUD.cs b/unity/Assets/UI/GameHUD.cs index 829aac7..560f705 100644 --- a/unity/Assets/UI/GameHUD.cs +++ b/unity/Assets/UI/GameHUD.cs @@ -57,6 +57,13 @@ namespace GameFramework UpdateSoulCount(ScoreManager.Instance != null ? ScoreManager.Instance.CurrentScore : 0); UpdateLifeIcons(); + + // 自动创建受击泛红特效(如果场景中没有) + if (FindObjectOfType() == null) + { + var overlayObj = new GameObject("DamageFlashOverlay"); + overlayObj.AddComponent(); + } } void OnDestroy() diff --git a/unity/UserSettings/EditorUserSettings.asset b/unity/UserSettings/EditorUserSettings.asset index 12bcbd5..865866b 100644 --- a/unity/UserSettings/EditorUserSettings.asset +++ b/unity/UserSettings/EditorUserSettings.asset @@ -27,13 +27,13 @@ EditorUserSettings: value: 5300055151055f5a5e0c0f27477708444515192b287124367c791f30b3b9616d flags: 0 RecentlyUsedSceneGuid-7: - value: 0209025f575750595c57092149765d444e4e49727e7c7068757b1c65b6e36c3b + value: 5a55515156575a0b0f56592346260f444f16197c7e7f24697d2a4a32b1b0353e flags: 0 RecentlyUsedSceneGuid-8: value: 5a5757560101590a5d0c0e24427b5d44434e4c7a7b7a23677f2b4565b7b5353a flags: 0 RecentlyUsedSceneGuid-9: - value: 5a55515156575a0b0f56592346260f444f16197c7e7f24697d2a4a32b1b0353e + value: 0209025f575750595c57092149765d444e4e49727e7c7068757b1c65b6e36c3b flags: 0 UnityEditor.ShaderGraph.Blackboard: value: 18135939215a0a5004000b0e15254b524c030a3f2964643d120d1230e9e93a3fd6e826abbd2e2d293c4ead313b08042de6030a0afa240c0d020be94c4ba75e435d8715fa32c70d15d11612dacc11fee5d3c5d1fe9ab1bf968e93e2ffcbc3e7e2f0b3ffe0e8b0be9af8ffaeffff8e85dd8390e3949c8899daa7