Files
aibis-dream/Assets/Scripts/MiniGame/HuoShan/EmotionWave/EmotionWaveController.cs
T
2026-02-25 16:19:28 +08:00

135 lines
4.8 KiB
C#

using UnityEngine;
namespace AibisDream.MiniGame.HuoShan.EmotionWave
{
/// <summary>
/// Controls the EmotionWave visualization.
/// Drag the progress slider in the Inspector to drive the 3-act narrative.
/// Ported from Web_EmotionWave/js/app.js.
/// </summary>
[ExecuteAlways]
public class EmotionWaveController : MonoBehaviour
{
[Header("References")]
[SerializeField] private EmotionWaveConfig config;
[SerializeField] private EmotionWaveRenderer waveRenderer;
[Header("Progress Control")]
[Range(0f, 1f)]
[SerializeField] private float progress = 0f;
[Header("Smooth Tracking")]
[SerializeField] private float lerpSpeed = 4f;
[Header("Tweak (active in 0.75~1.0 range)")]
[Range(0f, 1f)] [SerializeField] private float tweakFuzz = 0f;
[Range(0f, 1f)] [SerializeField] private float tweakSpin = 0.5f;
[Range(0f, 1f)] [SerializeField] private float tweakHue = 0f;
[Header("CRT Startup")]
[SerializeField] private float startupDuration = 1.8f;
[Header("Debug")]
[SerializeField] [ReadOnlyField] private string currentStage = "";
[SerializeField] [ReadOnlyField] private string currentStageName = "";
[SerializeField] [ReadOnlyField] private float smoothedProgress;
private float _currentValue;
private float _elapsedTime;
public float Progress
{
get => progress;
set => progress = Mathf.Clamp01(value);
}
void Update()
{
if (config == null || waveRenderer == null) return;
float dt = Time.deltaTime;
_elapsedTime += dt;
// CRT startup ease
float startupFactor = Mathf.Clamp01(_elapsedTime / startupDuration);
float startupEase = startupFactor * startupFactor;
// Smooth tracking
_currentValue += (progress - _currentValue) * Mathf.Min(1f, dt * lerpSpeed);
smoothedProgress = _currentValue;
// Interpolate wave params
var waveParams = config.Interpolate(_currentValue);
// Inject review parameters based on stage phase
string phase = config.GetStagePhase(_currentValue);
currentStage = phase;
currentStageName = config.GetStageName(_currentValue);
if (phase == "REVIEW")
{
float r0 = 0.35f, r1 = 0.5f, r2 = 0.65f;
if (_currentValue <= r1)
waveParams.reviewIntensity = Smoothstep((_currentValue - r0) / (r1 - r0));
else
waveParams.reviewIntensity = 0.15f + 0.85f * Smoothstep((r2 - _currentValue) / (r2 - r1));
waveParams.featureBoxRate = 3f;
waveParams.thresholdLevel = 0.75f;
waveParams.cursorSpeed = 0.5f;
}
else
{
waveParams.reviewIntensity = 0f;
waveParams.featureBoxRate = 0f;
waveParams.thresholdLevel = 0.8f;
waveParams.cursorSpeed = 0f;
}
// End-stage tweaks (smoothstep fade-in from 0.75)
float tweakLinear = Mathf.Clamp01((_currentValue - 0.75f) / 0.1f);
float tweakWeight = tweakLinear * tweakLinear * (3f - 2f * tweakLinear);
if (tweakWeight > 0.001f)
{
float fuzz = tweakFuzz * 0.8f;
float spin = 0.2f + tweakSpin * 1f;
float hueVal = tweakHue * 128f;
waveParams.weierstrassAmount = Mathf.Lerp(waveParams.weierstrassAmount, fuzz, tweakWeight);
waveParams.phaseSpeed = Mathf.Lerp(waveParams.phaseSpeed, spin, tweakWeight);
waveParams.hue = Mathf.Lerp(waveParams.hue, hueVal, tweakWeight);
}
// CRT startup fade
waveParams.glowIntensity *= startupEase;
waveParams.lightness *= startupEase;
// Push to renderer
waveRenderer.currentParams = waveParams;
waveRenderer.time = _elapsedTime;
}
static float Smoothstep(float t)
{
t = Mathf.Clamp01(t);
return t * t * (3f - 2f * t);
}
}
/// <summary>
/// Makes a field read-only in the Inspector.
/// </summary>
public class ReadOnlyFieldAttribute : PropertyAttribute { }
#if UNITY_EDITOR
[UnityEditor.CustomPropertyDrawer(typeof(ReadOnlyFieldAttribute))]
public class ReadOnlyFieldDrawer : UnityEditor.PropertyDrawer
{
public override void OnGUI(Rect position, UnityEditor.SerializedProperty property, GUIContent label)
{
UnityEditor.EditorGUI.BeginDisabledGroup(true);
UnityEditor.EditorGUI.PropertyField(position, property, label);
UnityEditor.EditorGUI.EndDisabledGroup();
}
}
#endif
}