Files
Cielonos/Assets/OtherPlugins/Feel/MMFeedbacks/MMFeedbacksForThirdParty/Cinemachine/Shakers/MMCinemachineCameraDistanceShaker.cs
2025-12-22 18:36:29 -05:00

178 lines
7.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using UnityEngine;
using MoreMountains.Feedbacks;
using MoreMountains.Tools;
// 强制引用 Cinemachine 3 的命名空间
using Unity.Cinemachine;
namespace MoreMountains.FeedbacksForThirdParty
{
/// <summary>
/// 定义 Shake 事件,用于传递距离震动的参数
/// </summary>
public struct MMCinemachineCameraDistanceShakeEvent
{
public delegate void Delegate(AnimationCurve distortionCurve, float duration, float remapMin, float remapMax, bool relativeDistortion = false,
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 event Delegate OnEvent;
public static void Trigger(AnimationCurve distortionCurve, float duration, float remapMin, float remapMax, bool relativeDistortion = false,
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(distortionCurve, duration, remapMin, remapMax, relativeDistortion, feedbacksIntensity, channelData, resetShakerValuesAfterShake, resetTargetValuesAfterShake, forwardDirection, timescaleMode, stop, restore);
}
}
/// <summary>
/// 这个 Shaker 能够控制 CinemachineCamera 的 CameraDistance。
/// 它会自动寻找 CinemachineThirdPersonFollow 或 CinemachinePositionComposer 组件。
/// </summary>
[AddComponentMenu("More Mountains/Feedbacks/Shakers/Cinemachine/MM Cinemachine Camera Distance Shaker")]
[RequireComponent(typeof(CinemachineCamera))]
public class MMCinemachineCameraDistanceShaker : MMShaker
{
[MMInspectorGroup("Camera Distance", true, 42)]
[Tooltip("是否在原始距离的基础上进行增减 (Relative),还是直接覆盖为新距离")]
public bool RelativeDistance = true; // 默认改为True通常更符合Distance的直觉
[Tooltip("控制距离变化的曲线")]
public AnimationCurve ShakeDistance = new AnimationCurve(new Keyframe(0, 0), new Keyframe(0.5f, 1), new Keyframe(1, 0));
[Tooltip("曲线 0 对应的值")]
public float RemapDistanceZero = 0f;
[Tooltip("曲线 1 对应的值")]
public float RemapDistanceOne = 5f;
protected CinemachineCamera _targetCamera;
protected CinemachineThirdPersonFollow _thirdPersonFollow;
protected CinemachinePositionComposer _positionComposer;
protected float _initialDistance;
protected float _originalShakeDuration;
protected bool _originalRelativeDistance;
protected AnimationCurve _originalShakeDistance;
protected float _originalRemapDistanceZero;
protected float _originalRemapDistanceOne;
protected override void Initialization()
{
base.Initialization();
_targetCamera = this.gameObject.GetComponent<CinemachineCamera>();
// 尝试获取 ThirdPersonFollow
_thirdPersonFollow = this.gameObject.GetComponent<CinemachineThirdPersonFollow>();
// 如果没有 Follow尝试获取 PositionComposer
if (_thirdPersonFollow == null)
{
_positionComposer = this.gameObject.GetComponent<CinemachinePositionComposer>();
}
}
protected virtual void Reset()
{
ShakeDuration = 0.5f;
}
protected override void Shake()
{
// 计算当前帧的 Distance
float newDistance = ShakeFloat(ShakeDistance, RemapDistanceZero, RemapDistanceOne, RelativeDistance, _initialDistance);
SetCameraDistance(newDistance);
}
protected virtual void SetCameraDistance(float newDistance)
{
// 为了安全,防止距离为负数(如果这不是你想要的效果)
if (newDistance < 0f) newDistance = 0f;
if (_thirdPersonFollow != null)
{
_thirdPersonFollow.CameraDistance = newDistance;
}
else if (_positionComposer != null)
{
_positionComposer.CameraDistance = newDistance;
}
}
protected override void GrabInitialValues()
{
if (_thirdPersonFollow != null)
{
_initialDistance = _thirdPersonFollow.CameraDistance;
}
else if (_positionComposer != null)
{
_initialDistance = _positionComposer.CameraDistance;
}
else
{
// 如果两个组件都没找到记录一个警告或者默认为0
// Debug.LogWarning("MMCinemachineCameraDistanceShaker: No compatible component (ThirdPersonFollow or PositionComposer) found on " + name);
}
}
protected override void ResetTargetValues()
{
base.ResetTargetValues();
SetCameraDistance(_initialDistance);
}
protected override void ResetShakerValues()
{
base.ResetShakerValues();
ShakeDuration = _originalShakeDuration;
ShakeDistance = _originalShakeDistance;
RemapDistanceZero = _originalRemapDistanceZero;
RemapDistanceOne = _originalRemapDistanceOne;
RelativeDistance = _originalRelativeDistance;
}
public virtual void OnMMCinemachineCameraDistanceShakeEvent(AnimationCurve distortionCurve, float duration, float remapMin, float remapMax, bool relativeDistortion = false,
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;
_originalShakeDistance = ShakeDistance;
_originalRemapDistanceZero = RemapDistanceZero;
_originalRemapDistanceOne = RemapDistanceOne;
_originalRelativeDistance = RelativeDistance;
}
if (!OnlyUseShakerValues)
{
TimescaleMode = timescaleMode;
ShakeDuration = duration;
ShakeDistance = distortionCurve;
RemapDistanceZero = remapMin * feedbacksIntensity;
RemapDistanceOne = remapMax * feedbacksIntensity;
RelativeDistance = relativeDistortion;
ForwardDirection = forwardDirection;
}
Play();
}
public override void StartListening()
{
base.StartListening();
MMCinemachineCameraDistanceShakeEvent.OnEvent += OnMMCinemachineCameraDistanceShakeEvent;
}
public override void StopListening()
{
base.StopListening();
MMCinemachineCameraDistanceShakeEvent.OnEvent -= OnMMCinemachineCameraDistanceShakeEvent;
}
}
}