Files
Cielonos/Assets/OtherPlugins/Feel/MMFeedbacks/MMFeedbacksForThirdParty/Cinemachine/Shakers/MMCinemachineRotationShaker.cs
SoulliesOfficial f7af60351b 阶段性完成
2025-12-08 05:27:53 -05:00

191 lines
7.5 KiB
C#

using UnityEngine;
using MoreMountains.Feedbacks;
using MoreMountains.Tools;
#if MM_CINEMACHINE
using Cinemachine;
#elif MM_CINEMACHINE3
using Unity.Cinemachine;
#endif
namespace MoreMountains.FeedbacksForThirdParty
{
// 定义事件结构
public struct MMCameraRotationShakeEvent
{
static private event Delegate OnEvent;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] private static void RuntimeInitialization() { OnEvent = null; }
public static void Register(Delegate callback) { OnEvent += callback; }
public static void Unregister(Delegate callback) { OnEvent -= callback; }
public delegate void Delegate(AnimationCurve shakeCurve, float duration, Vector3 rotationAmplitude, float remapMin, float remapMax, bool relative,
float feedbacksIntensity = 1.0f, MMChannelData channelData = null, bool resetShakerValuesAfterShake = true, bool resetTargetValuesAfterShake = true, bool forwardDirection = true, TimescaleModes timescaleMode = TimescaleModes.Scaled, bool stop = false, bool restore = false);
public static void Trigger(AnimationCurve shakeCurve, float duration, Vector3 rotationAmplitude, float remapMin, float remapMax, bool relative,
float feedbacksIntensity = 1.0f, MMChannelData channelData = null, bool resetShakerValuesAfterShake = true, bool resetTargetValuesAfterShake = true, bool forwardDirection = true, TimescaleModes timescaleMode = TimescaleModes.Scaled, bool stop = false, bool restore = false)
{
OnEvent?.Invoke(shakeCurve, duration, rotationAmplitude, remapMin, remapMax, relative, feedbacksIntensity, channelData, resetShakerValuesAfterShake, resetTargetValuesAfterShake, forwardDirection, timescaleMode, stop, restore);
}
}
/// <summary>
/// Cinemachine Rotation Shaker
/// X/Y applied to FollowTarget, Z applied to Camera Dutch.
/// </summary>
[AddComponentMenu("More Mountains/Feedbacks/Shakers/Cinemachine/MM Cinemachine Rotation Shaker")]
#if MM_CINEMACHINE
[RequireComponent(typeof(CinemachineVirtualCamera))]
#elif MM_CINEMACHINE3
[RequireComponent(typeof(CinemachineCamera))]
#endif
public class MMCinemachineRotationShaker : MMShaker
{
public Transform FollowTarget => _targetCamera.Follow;
[MMInspectorGroup("Shake Settings", true, 42)]
public Vector3 ShakeRotationAmplitude = new Vector3(2f, 2f, 5f);
public AnimationCurve ShakeCurve = new AnimationCurve(new Keyframe(0, 0), new Keyframe(0.5f, 1), new Keyframe(1, 0));
[MMFInspectorButton("StartShaking")]
public bool TestShakeButton;
#if MM_CINEMACHINE
protected CinemachineVirtualCamera _targetCamera;
#elif MM_CINEMACHINE3
protected CinemachineCamera _targetCamera;
#endif
protected float _initialDutch;
protected Quaternion _initialTargetRotation;
// --- 修复点 1: 显式声明这些备份变量 ---
protected float _originalShakeDuration;
protected Vector3 _originalShakeRotationAmplitude;
protected AnimationCurve _originalShakeCurve;
protected override void Initialization()
{
base.Initialization();
#if MM_CINEMACHINE
_targetCamera = GetComponent<CinemachineVirtualCamera>();
#elif MM_CINEMACHINE3
_targetCamera = GetComponent<CinemachineCamera>();
#endif
}
protected override void GrabInitialValues()
{
if (_targetCamera != null)
{
#if MM_CINEMACHINE
_initialDutch = _targetCamera.m_Lens.Dutch;
#elif MM_CINEMACHINE3
_initialDutch = _targetCamera.Lens.Dutch;
#endif
}
if (FollowTarget != null)
{
_initialTargetRotation = FollowTarget.localRotation;
}
}
protected override void Shake()
{
// --- 修复点 2: 使用 ShakeFloat 代替手动 ShakeTime 计算 ---
// ShakeFloat 会自动处理时间、重映射和曲线计算
// 我们请求一个 0 到 1 之间的浮点数作为当前的“强度”
float intensity = ShakeFloat(ShakeCurve, 0f, 1f, false, 0f);
// 根据强度应用 XYZ
float xOffset = ShakeRotationAmplitude.x * intensity;
float yOffset = ShakeRotationAmplitude.y * intensity;
float zOffset = ShakeRotationAmplitude.z * intensity;
ApplyRotation(xOffset, yOffset, zOffset);
}
protected virtual void ApplyRotation(float x, float y, float z)
{
// Z -> Dutch
if (_targetCamera != null)
{
#if MM_CINEMACHINE
_targetCamera.m_Lens.Dutch = _initialDutch + z;
#elif MM_CINEMACHINE3
_targetCamera.Lens.Dutch = _initialDutch + z;
#endif
}
// X/Y -> FollowTarget
if (FollowTarget != null)
{
FollowTarget.localRotation = _initialTargetRotation * Quaternion.Euler(x, y, 0f);
}
}
protected override void ResetTargetValues()
{
base.ResetTargetValues();
ApplyRotation(0f, 0f, 0f);
}
protected override void ResetShakerValues()
{
base.ResetShakerValues();
// 恢复备份的值
ShakeDuration = _originalShakeDuration;
ShakeRotationAmplitude = _originalShakeRotationAmplitude;
ShakeCurve = _originalShakeCurve;
}
public virtual void OnMMCameraRotationShakeEvent(AnimationCurve shakeCurve, float duration, Vector3 rotationAmplitude, float remapMin, float remapMax, bool relative, float feedbacksIntensity = 1.0f, MMChannelData channelData = null, bool resetShakerValuesAfterShake = true, bool resetTargetValuesAfterShake = true, bool forwardDirection = true, TimescaleModes timescaleMode = TimescaleModes.Scaled, bool stop = false, bool restore = false)
{
if (!CheckEventAllowed(channelData)) return;
if (stop)
{
Stop();
return;
}
if (restore)
{
ResetTargetValues();
return;
}
if (!Interruptible && Shaking) return;
_resetShakerValuesAfterShake = resetShakerValuesAfterShake;
_resetTargetValuesAfterShake = resetTargetValuesAfterShake;
if (resetShakerValuesAfterShake)
{
// 备份当前值
_originalShakeDuration = ShakeDuration;
_originalShakeRotationAmplitude = ShakeRotationAmplitude;
_originalShakeCurve = ShakeCurve;
}
TimescaleMode = timescaleMode;
ShakeDuration = duration;
// 应用 Intensity
ShakeRotationAmplitude = rotationAmplitude * feedbacksIntensity;
ShakeCurve = shakeCurve;
ForwardDirection = forwardDirection;
Play();
}
public override void StartListening()
{
base.StartListening();
MMCameraRotationShakeEvent.Register(OnMMCameraRotationShakeEvent);
}
public override void StopListening()
{
base.StopListening();
MMCameraRotationShakeEvent.Unregister(OnMMCameraRotationShakeEvent);
}
}
}