178 lines
7.7 KiB
C#
178 lines
7.7 KiB
C#
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;
|
||
}
|
||
}
|
||
} |