376 lines
12 KiB
C#
376 lines
12 KiB
C#
using SmoothShakeFree;
|
|
using System.Collections;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
|
|
public class globalNoteEffect : MonoBehaviour
|
|
{
|
|
public static globalNoteEffect Instance { get; private set; }
|
|
|
|
[Header("Camera Shake Event")]
|
|
public float cameraShakeAmplitude = 0.12f;
|
|
|
|
[Header("Flash Blink Event")]
|
|
public Image flashBlinkImage;
|
|
public float flashBlinkFadeDuration = 0.2f;
|
|
|
|
[Header("Camera Dash Event")]
|
|
public float targetCameraZPosition = -6.5f;
|
|
public AnimationCurve cameraDashCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
|
|
public float cameraDashDuration = 0.12f;
|
|
|
|
[Header("Camera Wave FX")]
|
|
[Range(0f, 1f)]
|
|
public float cameraWaveIntensity = 1f;
|
|
public float cameraWaveEnterDuration = 0.12f;
|
|
public float cameraWaveRecoverDuration = 0.12f;
|
|
|
|
[Header("Camera Glitch FX")]
|
|
public float cameraGlitchEnterDuration = 0.08f;
|
|
public float cameraGlitchRecoverDuration = 0.12f;
|
|
|
|
[Header("Camera Monochrome FX")]
|
|
public float cameraMonochromeEnterDuration = 0.1f;
|
|
public float cameraMonochromeRecoverDuration = 0.14f;
|
|
|
|
[Header("Screenshot Scale FX")]
|
|
public float screenshotScaleStartOpacity = 0.5f;
|
|
public float screenshotScaleFadeDuration = 0.22f;
|
|
public float screenshotScaleEndScale = 1.12f;
|
|
|
|
private Transform cachedCameraTransform;
|
|
private Coroutine flashBlinkCoroutine;
|
|
private Coroutine cameraDashCoroutine;
|
|
private float cameraBaseLocalZ;
|
|
private bool hasCameraBaseLocalZ;
|
|
|
|
private void Awake()
|
|
{
|
|
if (Instance == null)
|
|
{
|
|
Instance = this;
|
|
}
|
|
else if (Instance != this)
|
|
{
|
|
Destroy(gameObject);
|
|
return;
|
|
}
|
|
|
|
CacheCameraTransform();
|
|
PrewarmRuntime();
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
SetFlashImageAlpha(0f);
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
CacheCameraTransform();
|
|
SetFlashImageAlpha(0f);
|
|
PrewarmRuntime();
|
|
}
|
|
|
|
private void LateUpdate()
|
|
{
|
|
if (cachedCameraTransform == null)
|
|
{
|
|
CacheCameraTransform();
|
|
}
|
|
|
|
if (cachedCameraTransform != null && cameraDashCoroutine == null)
|
|
{
|
|
cameraBaseLocalZ = cachedCameraTransform.localPosition.z;
|
|
hasCameraBaseLocalZ = true;
|
|
}
|
|
}
|
|
|
|
private void CacheCameraTransform()
|
|
{
|
|
if (Camera.main != null)
|
|
{
|
|
cachedCameraTransform = Camera.main.transform;
|
|
cameraBaseLocalZ = cachedCameraTransform.localPosition.z;
|
|
hasCameraBaseLocalZ = true;
|
|
}
|
|
}
|
|
|
|
public void PrewarmRuntime()
|
|
{
|
|
CacheCameraTransform();
|
|
|
|
if (cachedCameraTransform != null)
|
|
{
|
|
SmoothShake shake = cachedCameraTransform.GetComponent<SmoothShake>();
|
|
if (shake == null)
|
|
{
|
|
shake = cachedCameraTransform.gameObject.AddComponent<SmoothShake>();
|
|
}
|
|
|
|
if (shake.positionShake == null) shake.positionShake = new Shaker();
|
|
if (shake.rotationShake == null) shake.rotationShake = new Shaker();
|
|
if (shake.shakers == null || shake.shakers.Length != 2)
|
|
shake.shakers = new[] { shake.positionShake, shake.rotationShake };
|
|
if (shake.sum == null || shake.sum.Length != 2)
|
|
shake.sum = new Vector3[2];
|
|
}
|
|
|
|
GlobalDistortionRuntimeController.EnsureInstance();
|
|
GlobalGlitchRuntimeController.EnsureInstance();
|
|
GlobalMonochromeRuntimeController.EnsureInstance();
|
|
GlobalAfterimageRuntimeController.EnsureInstance();
|
|
}
|
|
|
|
public static void TryTrigger(string noteFunction)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(noteFunction))
|
|
return;
|
|
|
|
globalNoteEffect controller = GetOrCreateInstance();
|
|
if (controller == null)
|
|
return;
|
|
|
|
controller.TriggerInternal(noteFunction.Trim());
|
|
}
|
|
|
|
private static globalNoteEffect GetOrCreateInstance()
|
|
{
|
|
if (Instance != null)
|
|
return Instance;
|
|
|
|
globalNoteEffect found = SceneObjectLookupCache.FindAny<globalNoteEffect>();
|
|
if (found != null)
|
|
{
|
|
Instance = found;
|
|
return found;
|
|
}
|
|
|
|
GameObject runtimeObject = new GameObject("__global_note_effect_runtime");
|
|
return runtimeObject.AddComponent<globalNoteEffect>();
|
|
}
|
|
|
|
private void TriggerInternal(string noteFunction)
|
|
{
|
|
switch (noteFunction)
|
|
{
|
|
case "CameraShakeEvent":
|
|
TriggerCameraShake();
|
|
break;
|
|
case "FlashBlinkEvent":
|
|
TriggerFlashBlink();
|
|
break;
|
|
case "CameraScaleEvent":
|
|
TriggerCameraDash();
|
|
break;
|
|
case "CameraWaveFX":
|
|
TriggerCameraWaveFx();
|
|
break;
|
|
case "CameraGlitchFX":
|
|
TriggerCameraGlitchFx();
|
|
break;
|
|
case "CameraMonochromeFX":
|
|
TriggerCameraMonochromeFx();
|
|
break;
|
|
case "ScreenshotScale":
|
|
TriggerScreenshotScaleFx();
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void TriggerCameraShake()
|
|
{
|
|
CacheCameraTransform();
|
|
if (cachedCameraTransform == null)
|
|
return;
|
|
|
|
float amplitudeValue = Mathf.Max(0f, cameraShakeAmplitude);
|
|
if (amplitudeValue <= 0f)
|
|
return;
|
|
|
|
SmoothShake shake = cachedCameraTransform.GetComponent<SmoothShake>();
|
|
if (shake == null)
|
|
{
|
|
shake = cachedCameraTransform.gameObject.AddComponent<SmoothShake>();
|
|
}
|
|
|
|
if (shake.positionShake == null) shake.positionShake = new Shaker();
|
|
if (shake.rotationShake == null) shake.rotationShake = new Shaker();
|
|
|
|
shake.positionShake.noiseType = Shaker.NoiseType.SineWave;
|
|
shake.positionShake.amplitude = new Vector3(amplitudeValue, amplitudeValue, 0f);
|
|
shake.positionShake.frequency = new Vector3(18f, 18f, 0f);
|
|
shake.rotationShake.amplitude = Vector3.zero;
|
|
shake.rotationShake.frequency = Vector3.zero;
|
|
|
|
shake.timeSettings.constantShake = false;
|
|
shake.timeSettings.fadeInDuration = 0.02f;
|
|
shake.timeSettings.holdDuration = 0.04f;
|
|
shake.timeSettings.fadeOutDuration = 0.05f;
|
|
|
|
if (shake.timeSettings.fadeInCurve == null || shake.timeSettings.fadeInCurve.length == 0)
|
|
shake.timeSettings.fadeInCurve = AnimationCurve.Linear(0f, 0f, 1f, 1f);
|
|
if (shake.timeSettings.fadeOutCurve == null || shake.timeSettings.fadeOutCurve.length == 0)
|
|
shake.timeSettings.fadeOutCurve = AnimationCurve.Linear(0f, 1f, 1f, 0f);
|
|
|
|
// 复用内部数组,仅在缺失/尺寸不符时重建,避免每次(近乎每音符)相机震动都分配两个数组。
|
|
if (shake.shakers == null || shake.shakers.Length != 2)
|
|
shake.shakers = new[] { shake.positionShake, shake.rotationShake };
|
|
if (shake.sum == null || shake.sum.Length != 2)
|
|
shake.sum = new Vector3[2];
|
|
|
|
try
|
|
{
|
|
shake.StartShake();
|
|
}
|
|
catch (System.Exception ex)
|
|
{
|
|
Debug.LogWarning($"[globalNoteEffect] Camera shake failed (check shake asset references in Inspector): {ex.Message}");
|
|
}
|
|
}
|
|
|
|
private void TriggerFlashBlink()
|
|
{
|
|
if (flashBlinkImage == null)
|
|
return;
|
|
|
|
if (flashBlinkCoroutine != null)
|
|
{
|
|
StopCoroutine(flashBlinkCoroutine);
|
|
}
|
|
|
|
flashBlinkCoroutine = StartCoroutine(FlashBlinkCoroutine());
|
|
}
|
|
|
|
private IEnumerator FlashBlinkCoroutine()
|
|
{
|
|
SetFlashImageAlpha(1f);
|
|
|
|
float duration = Mathf.Max(0.01f, flashBlinkFadeDuration);
|
|
float elapsed = 0f;
|
|
while (elapsed < duration)
|
|
{
|
|
elapsed += Time.deltaTime;
|
|
float t = Mathf.Clamp01(elapsed / duration);
|
|
SetFlashImageAlpha(1f - t);
|
|
yield return null;
|
|
}
|
|
|
|
SetFlashImageAlpha(0f);
|
|
flashBlinkCoroutine = null;
|
|
}
|
|
|
|
private void TriggerCameraDash()
|
|
{
|
|
CacheCameraTransform();
|
|
if (cachedCameraTransform == null)
|
|
return;
|
|
|
|
if (cameraDashCoroutine != null)
|
|
{
|
|
StopCoroutine(cameraDashCoroutine);
|
|
if (hasCameraBaseLocalZ)
|
|
{
|
|
Vector3 resetPosition = cachedCameraTransform.localPosition;
|
|
resetPosition.z = cameraBaseLocalZ;
|
|
cachedCameraTransform.localPosition = resetPosition;
|
|
}
|
|
}
|
|
|
|
cameraDashCoroutine = StartCoroutine(CameraDashCoroutine());
|
|
}
|
|
|
|
private IEnumerator CameraDashCoroutine()
|
|
{
|
|
if (!hasCameraBaseLocalZ)
|
|
{
|
|
cameraBaseLocalZ = cachedCameraTransform.localPosition.z;
|
|
hasCameraBaseLocalZ = true;
|
|
}
|
|
|
|
float baseLocalZ = cameraBaseLocalZ;
|
|
float targetZ = targetCameraZPosition;
|
|
if (Mathf.Approximately(targetZ, baseLocalZ))
|
|
{
|
|
targetZ = baseLocalZ + 1.5f;
|
|
}
|
|
float duration = Mathf.Max(0.01f, cameraDashDuration);
|
|
AnimationCurve curve = cameraDashCurve == null || cameraDashCurve.length == 0
|
|
? AnimationCurve.EaseInOut(0f, 0f, 1f, 1f)
|
|
: cameraDashCurve;
|
|
|
|
float elapsed = 0f;
|
|
while (elapsed < duration)
|
|
{
|
|
elapsed += Time.deltaTime;
|
|
float t = Mathf.Clamp01(elapsed / duration);
|
|
float curvedT = curve.Evaluate(t);
|
|
Vector3 position = cachedCameraTransform.localPosition;
|
|
position.z = Mathf.LerpUnclamped(baseLocalZ, targetZ, curvedT);
|
|
cachedCameraTransform.localPosition = position;
|
|
yield return null;
|
|
}
|
|
|
|
elapsed = 0f;
|
|
while (elapsed < duration)
|
|
{
|
|
elapsed += Time.deltaTime;
|
|
float t = Mathf.Clamp01(elapsed / duration);
|
|
float curvedT = curve.Evaluate(t);
|
|
Vector3 position = cachedCameraTransform.localPosition;
|
|
position.z = Mathf.LerpUnclamped(targetZ, baseLocalZ, curvedT);
|
|
cachedCameraTransform.localPosition = position;
|
|
yield return null;
|
|
}
|
|
|
|
Vector3 finalPosition = cachedCameraTransform.localPosition;
|
|
finalPosition.z = baseLocalZ;
|
|
cachedCameraTransform.localPosition = finalPosition;
|
|
cameraDashCoroutine = null;
|
|
}
|
|
|
|
private void TriggerCameraWaveFx()
|
|
{
|
|
GlobalDistortionRuntimeController.TriggerWaveEffect(
|
|
Mathf.Clamp01(cameraWaveIntensity),
|
|
Mathf.Max(0.0001f, cameraWaveEnterDuration),
|
|
Mathf.Max(0.0001f, cameraWaveRecoverDuration)
|
|
);
|
|
}
|
|
|
|
private void TriggerCameraGlitchFx()
|
|
{
|
|
GlobalGlitchRuntimeController.TriggerWaveEffect(
|
|
Mathf.Max(0.0001f, cameraGlitchEnterDuration),
|
|
Mathf.Max(0.0001f, cameraGlitchRecoverDuration)
|
|
);
|
|
}
|
|
|
|
private void TriggerCameraMonochromeFx()
|
|
{
|
|
GlobalMonochromeRuntimeController.Trigger(
|
|
Mathf.Max(0.0001f, cameraMonochromeEnterDuration),
|
|
Mathf.Max(0.0001f, cameraMonochromeRecoverDuration)
|
|
);
|
|
}
|
|
|
|
private void TriggerScreenshotScaleFx()
|
|
{
|
|
GlobalAfterimageRuntimeController.Trigger(
|
|
Mathf.Clamp01(screenshotScaleStartOpacity),
|
|
Mathf.Max(0.0001f, screenshotScaleFadeDuration),
|
|
Mathf.Max(1f, screenshotScaleEndScale)
|
|
);
|
|
}
|
|
|
|
private void SetFlashImageAlpha(float alpha)
|
|
{
|
|
if (flashBlinkImage == null)
|
|
return;
|
|
|
|
Color color = flashBlinkImage.color;
|
|
color.a = Mathf.Clamp01(alpha);
|
|
flashBlinkImage.color = color;
|
|
}
|
|
}
|