3
This commit is contained in:
156
unity/Assets/Light/scripts/EchoSystem.cs
Normal file
156
unity/Assets/Light/scripts/EchoSystem.cs
Normal file
@@ -0,0 +1,156 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace IndianOceanAssets.Engine2_5D
|
||||
{
|
||||
/// <summary>
|
||||
/// 回声系统 v2 —— 描边波纹版。
|
||||
/// 按 E 键从玩家位置释放扩散波纹,波纹扫过的精灵(非光源物体)
|
||||
/// 会显示外描边(默认白色,可自定义),维持一段时间后整体消散。
|
||||
///
|
||||
/// 与 v1 的区别:
|
||||
/// - 不再在黑暗遮罩上画光波(那样会漏出地板)
|
||||
/// - 改为通过全局 shader 参数控制精灵描边 shader (SpriteEchoOutline)
|
||||
/// - 时间模型:扩散 → 维持(sustainTime) → 消散(fadeTime)
|
||||
///
|
||||
/// 挂载位置:玩家物体上(或跟随玩家的空物体)
|
||||
/// 依赖:场景中需要有用 SpriteEchoOutline shader 的描边精灵
|
||||
/// (由 EchoOutlineManager 自动生成)
|
||||
/// </summary>
|
||||
public class EchoSystem : MonoBehaviour
|
||||
{
|
||||
[Header("按键")]
|
||||
[SerializeField] private KeyCode echoKey = KeyCode.E;
|
||||
|
||||
[Header("扩散参数")]
|
||||
[Tooltip("波纹扩散速度(世界单位/秒)")]
|
||||
[SerializeField] private float expandSpeed = 15f;
|
||||
|
||||
[Tooltip("最大扩散半径(到达后进入维持阶段)")]
|
||||
[SerializeField] private float maxRadius = 30f;
|
||||
|
||||
[Tooltip("波纹前沿柔和宽度(精灵被扫到时的过渡宽度,越大越柔)")]
|
||||
[SerializeField] private float ringWidth = 1.5f;
|
||||
|
||||
[Header("时间模型")]
|
||||
[Tooltip("扩散到最大半径后,描边维持的时间(秒)")]
|
||||
[SerializeField] private float sustainTime = 4f;
|
||||
|
||||
[Tooltip("维持结束后,描边消散的时间(秒)")]
|
||||
[SerializeField] private float fadeTime = 1.5f;
|
||||
|
||||
[Header("描边外观")]
|
||||
[Tooltip("描边颜色(默认白色,可自定义)")]
|
||||
[SerializeField] private Color outlineColor = Color.white;
|
||||
|
||||
[Header("冷却")]
|
||||
[Tooltip("回声冷却时间(秒)")]
|
||||
[SerializeField] private float cooldown = 2f;
|
||||
|
||||
// 全局 shader 属性 ID(通过 Shader.SetGlobalX 设置,所有描边精灵共享)
|
||||
private static readonly int EchoCenterID = Shader.PropertyToID("_EchoCenter");
|
||||
private static readonly int EchoRadiusID = Shader.PropertyToID("_EchoRadius");
|
||||
private static readonly int EchoWidthID = Shader.PropertyToID("_EchoWidth");
|
||||
private static readonly int EchoOutlineIntensityID = Shader.PropertyToID("_EchoOutlineIntensity");
|
||||
private static readonly int EchoOutlineColorID = Shader.PropertyToID("_EchoOutlineColor");
|
||||
|
||||
private enum State { Idle, Expanding, Sustaining, Fading }
|
||||
|
||||
private State _state = State.Idle;
|
||||
private float _radius;
|
||||
private float _intensity;
|
||||
private float _stateTimer;
|
||||
private Vector2 _center;
|
||||
private float _lastEchoTime = -999f;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
// 初始化:描边关闭
|
||||
Shader.SetGlobalFloat(EchoOutlineIntensityID, 0f);
|
||||
Shader.SetGlobalColor(EchoOutlineColorID, outlineColor);
|
||||
Shader.SetGlobalFloat(EchoWidthID, ringWidth);
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
// 触发
|
||||
if (Input.GetKeyDown(echoKey) && _state == State.Idle && Time.time > _lastEchoTime + cooldown)
|
||||
{
|
||||
StartEcho();
|
||||
}
|
||||
|
||||
// 状态机
|
||||
switch (_state)
|
||||
{
|
||||
case State.Expanding: UpdateExpanding(); break;
|
||||
case State.Sustaining: UpdateSustaining(); break;
|
||||
case State.Fading: UpdateFading(); break;
|
||||
}
|
||||
|
||||
// 每帧推送全局参数
|
||||
Shader.SetGlobalVector(EchoCenterID, new Vector4(_center.x, _center.y, 0f, 0f));
|
||||
Shader.SetGlobalFloat(EchoRadiusID, _radius);
|
||||
Shader.SetGlobalFloat(EchoWidthID, ringWidth);
|
||||
Shader.SetGlobalFloat(EchoOutlineIntensityID, _intensity);
|
||||
Shader.SetGlobalColor(EchoOutlineColorID, outlineColor);
|
||||
}
|
||||
|
||||
private void StartEcho()
|
||||
{
|
||||
_state = State.Expanding;
|
||||
_radius = 0f;
|
||||
_intensity = 1f;
|
||||
_stateTimer = 0f;
|
||||
_lastEchoTime = Time.time;
|
||||
|
||||
// 记录释放时刻的玩家位置(回声中心固定,不跟随移动)
|
||||
Vector3 p = transform.position;
|
||||
_center = new Vector2(p.x, p.z);
|
||||
}
|
||||
|
||||
private void UpdateExpanding()
|
||||
{
|
||||
_radius += expandSpeed * Time.deltaTime;
|
||||
if (_radius >= maxRadius)
|
||||
{
|
||||
_radius = maxRadius;
|
||||
_state = State.Sustaining;
|
||||
_stateTimer = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateSustaining()
|
||||
{
|
||||
_stateTimer += Time.deltaTime;
|
||||
_intensity = 1f; // 维持阶段满强度
|
||||
if (_stateTimer >= sustainTime)
|
||||
{
|
||||
_state = State.Fading;
|
||||
_stateTimer = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateFading()
|
||||
{
|
||||
_stateTimer += Time.deltaTime;
|
||||
// 消散阶段强度从 1 → 0
|
||||
_intensity = Mathf.Clamp01(1f - _stateTimer / Mathf.Max(0.0001f, fadeTime));
|
||||
if (_stateTimer >= fadeTime)
|
||||
{
|
||||
_state = State.Idle;
|
||||
_intensity = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 外部调用:强制停止回声
|
||||
/// </summary>
|
||||
public void StopEcho()
|
||||
{
|
||||
_state = State.Idle;
|
||||
_intensity = 0f;
|
||||
Shader.SetGlobalFloat(EchoOutlineIntensityID, 0f);
|
||||
}
|
||||
|
||||
public bool IsActive => _state != State.Idle;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user