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); } } /// /// Cinemachine Rotation Shaker /// X/Y applied to FollowTarget, Z applied to Camera Dutch. /// [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(); #elif MM_CINEMACHINE3 _targetCamera = GetComponent(); #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); } } }