Files
aibis-dream/Assets/Scripts/MiniGame/HuoShan/EmotionWave/EmotionWaveController.cs
T

129 lines
4.3 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("Preset")]
[Tooltip("当前波形预设:normal / predicted / modified_joke / empty,可由 switch_emotion_wave_config 切换")]
[SerializeField] private string presetId = "normal";
[Header("Progress Control")]
[Range(0f, 1f)]
[SerializeField] private float progress = 0f;
[Header("Smooth Tracking")]
[SerializeField] private float lerpSpeed = 4f;
[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);
}
public string PresetId => presetId;
public void SetPreset(string id)
{
if (!string.IsNullOrEmpty(id))
presetId = id;
}
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.InterpolatePreset(presetId, _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;
}
// 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
}