后处理+FEEL完全改进
This commit is contained in:
@@ -0,0 +1,178 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ed0f8ba8298344842a1de7e54165b68e
|
||||
@@ -108,7 +108,7 @@ namespace MoreMountains.FeedbacksForThirdParty
|
||||
/// <param name="relativeDistortion"></param>
|
||||
/// <param name="feedbacksIntensity"></param>
|
||||
/// <param name="channel"></param>
|
||||
public virtual void OnMMCameraFieldOfViewShakeEvent(AnimationCurve distortionCurve, float duration, float remapMin, float remapMax, bool relativeDistortion = false,
|
||||
public virtual void OnMMCameraFieldOfViewShakeEvent(MMF_Feedback source, 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)
|
||||
{
|
||||
@@ -157,7 +157,7 @@ namespace MoreMountains.FeedbacksForThirdParty
|
||||
ForwardDirection = forwardDirection;
|
||||
}
|
||||
|
||||
Play();
|
||||
Play(source);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
using UnityEngine;
|
||||
using MoreMountains.Feedbacks;
|
||||
using MoreMountains.Tools;
|
||||
using Unity.Cinemachine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MoreMountains.FeedbacksForThirdParty
|
||||
{
|
||||
// 定义一个类来保存单个震动实例的状态
|
||||
public class MMCinemachinePositionShakeInstance
|
||||
{
|
||||
public float Duration;
|
||||
public float Timer;
|
||||
public Vector3 Amplitude;
|
||||
public AnimationCurve Curve;
|
||||
public float Intensity;
|
||||
public TimescaleModes TimescaleMode;
|
||||
|
||||
public MMCinemachinePositionShakeInstance(float duration, Vector3 amplitude, AnimationCurve curve, float intensity, TimescaleModes timescaleMode)
|
||||
{
|
||||
Duration = duration;
|
||||
Timer = 0f;
|
||||
Amplitude = amplitude;
|
||||
Curve = curve;
|
||||
Intensity = intensity;
|
||||
TimescaleMode = timescaleMode;
|
||||
}
|
||||
}
|
||||
|
||||
[AddComponentMenu("More Mountains/Feedbacks/Shakers/Cinemachine/MM Cinemachine Position Shaker (Additive)")]
|
||||
[RequireComponent(typeof(CinemachineCamera))]
|
||||
[RequireComponent(typeof(CinemachineCameraOffset))] // 确保有 Offset 组件
|
||||
public class MMCinemachinePositionShaker : MMShaker
|
||||
{
|
||||
[MMInspectorGroup("Debug Info", true, 43)]
|
||||
[MMReadOnly]
|
||||
public int ActiveShakesCount = 0; // 仅用于监视当前有多少个震动在叠加
|
||||
|
||||
protected CinemachineCamera _cmCamera;
|
||||
protected CinemachineCameraOffset _positionOffset;
|
||||
protected Vector3 _initialOffset;
|
||||
|
||||
// 维护一个活跃震动的列表
|
||||
protected List<MMCinemachinePositionShakeInstance> _activeShakes = new List<MMCinemachinePositionShakeInstance>();
|
||||
|
||||
protected override void Initialization()
|
||||
{
|
||||
// 注意:我们不调用 base.Initialization(),因为我们不想使用 MMShaker 默认的 Event 监听逻辑,
|
||||
// 我们需要完全接管 Shake 的逻辑来实现叠加。
|
||||
// 但为了兼容性,如果 Feel 内部有依赖,可以保留,但这里主要逻辑是自定义的。
|
||||
_cmCamera = GetComponent<CinemachineCamera>();
|
||||
_positionOffset = GetComponent<CinemachineCameraOffset>();
|
||||
GrabInitialValues();
|
||||
}
|
||||
|
||||
protected override void GrabInitialValues()
|
||||
{
|
||||
if (_positionOffset != null)
|
||||
{
|
||||
_initialOffset = _positionOffset.Offset;
|
||||
}
|
||||
}
|
||||
|
||||
// 我们重写 Update 来处理叠加逻辑
|
||||
protected override void Update()
|
||||
{
|
||||
if (_positionOffset == null) return;
|
||||
|
||||
// 如果没有活跃的震动,且当前不是初始位置,则复位(可选,作为保险)
|
||||
if (_activeShakes.Count == 0)
|
||||
{
|
||||
Stop();
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3 totalShakeOffset = Vector3.zero;
|
||||
|
||||
// 倒序遍历以便安全移除
|
||||
for (int i = _activeShakes.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var shake = _activeShakes[i];
|
||||
|
||||
// 更新时间
|
||||
float deltaTime = (shake.TimescaleMode == TimescaleModes.Scaled) ? Time.deltaTime : Time.unscaledDeltaTime;
|
||||
shake.Timer += deltaTime;
|
||||
|
||||
// 计算进度 (0 到 1)
|
||||
float percent = Mathf.Clamp01(shake.Timer / shake.Duration);
|
||||
|
||||
// 采样曲线并计算位移
|
||||
float curveValue = shake.Curve.Evaluate(percent);
|
||||
Vector3 currentOffset = shake.Amplitude * curveValue * shake.Intensity;
|
||||
|
||||
// 叠加
|
||||
totalShakeOffset += currentOffset;
|
||||
|
||||
// 如果结束,移除
|
||||
if (shake.Timer >= shake.Duration)
|
||||
{
|
||||
_activeShakes.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
// 应用叠加后的总偏移量 + 初始偏移量
|
||||
_positionOffset.Offset = _initialOffset + totalShakeOffset;
|
||||
//Debug.Log($"Total Shake Offset Applied: {totalShakeOffset}");
|
||||
|
||||
// 更新 Debug 计数
|
||||
ActiveShakesCount = _activeShakes.Count;
|
||||
|
||||
// 如果所有震动都结束了,强制归位以消除浮点误差
|
||||
if (_activeShakes.Count == 0)
|
||||
{
|
||||
_positionOffset.Offset = _initialOffset;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 接收事件
|
||||
/// </summary>
|
||||
public virtual void OnPositionShakeEvent(MMF_Feedback source, AnimationCurve shakeCurve, float duration, Vector3 positionAmplitude,
|
||||
float feedbacksIntensity = 1.0f, MMChannelData channelData = null, bool resetShakerValuesAfterShake = true,
|
||||
bool resetTargetValuesAfterShake = true, bool forwardDirection = true, TimescaleModes timescaleMode = TimescaleModes.Scaled, bool stop = false)
|
||||
{
|
||||
if (!CheckEventAllowed(channelData)) return;
|
||||
|
||||
if (stop)
|
||||
{
|
||||
Stop();
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建新的震动实例并添加到列表
|
||||
MMCinemachinePositionShakeInstance newShake = new MMCinemachinePositionShakeInstance(
|
||||
duration,
|
||||
positionAmplitude,
|
||||
shakeCurve,
|
||||
feedbacksIntensity,
|
||||
timescaleMode
|
||||
);
|
||||
|
||||
_activeShakes.Add(newShake);
|
||||
Play(source);
|
||||
}
|
||||
|
||||
// 强制停止所有震动
|
||||
public override void Stop()
|
||||
{
|
||||
_activeShakes.Clear();
|
||||
if (_positionOffset != null)
|
||||
{
|
||||
_positionOffset.Offset = _initialOffset;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ResetTargetValues()
|
||||
{
|
||||
base.ResetTargetValues();
|
||||
Stop();
|
||||
}
|
||||
|
||||
public override void StartListening()
|
||||
{
|
||||
// 注意:这里我们依然使用基类的注册机制,或者直接在这里注册
|
||||
base.StartListening();
|
||||
MMCinemachinePositionShakeEvent.Register(OnPositionShakeEvent);
|
||||
}
|
||||
|
||||
public override void StopListening()
|
||||
{
|
||||
base.StopListening();
|
||||
MMCinemachinePositionShakeEvent.Unregister(OnPositionShakeEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a6732be1ae6977e40bb682d19bca778e
|
||||
@@ -1,6 +1,7 @@
|
||||
using UnityEngine;
|
||||
using MoreMountains.Feedbacks;
|
||||
using MoreMountains.Tools;
|
||||
using System.Collections.Generic;
|
||||
#if MM_CINEMACHINE
|
||||
using Cinemachine;
|
||||
#elif MM_CINEMACHINE3
|
||||
@@ -9,7 +10,28 @@ using Unity.Cinemachine;
|
||||
|
||||
namespace MoreMountains.FeedbacksForThirdParty
|
||||
{
|
||||
// 定义事件结构
|
||||
// 1. 定义震动实例类 (保存单个震动的状态)
|
||||
public class MMCinemachineRotationShakeInstance
|
||||
{
|
||||
public float Duration;
|
||||
public float Timer;
|
||||
public Vector3 Amplitude;
|
||||
public AnimationCurve Curve;
|
||||
public float Intensity;
|
||||
public TimescaleModes TimescaleMode;
|
||||
|
||||
public MMCinemachineRotationShakeInstance(float duration, Vector3 amplitude, AnimationCurve curve, float intensity, TimescaleModes timescaleMode)
|
||||
{
|
||||
Duration = duration;
|
||||
Timer = 0f;
|
||||
Amplitude = amplitude;
|
||||
Curve = curve;
|
||||
Intensity = intensity;
|
||||
TimescaleMode = timescaleMode;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 定义事件
|
||||
public struct MMCinemachineRotationShakeEvent
|
||||
{
|
||||
static private event Delegate OnEvent;
|
||||
@@ -17,21 +39,22 @@ namespace MoreMountains.FeedbacksForThirdParty
|
||||
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,
|
||||
public delegate void Delegate(MMF_Feedback source, 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,
|
||||
public static void Trigger(MMF_Feedback source, 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);
|
||||
OnEvent?.Invoke(source, shakeCurve, duration, rotationAmplitude, remapMin, remapMax, relative, feedbacksIntensity, channelData, resetShakerValuesAfterShake, resetTargetValuesAfterShake, forwardDirection, timescaleMode, stop, restore);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cinemachine Rotation Shaker
|
||||
/// Cinemachine Rotation Shaker (Additive / Mixing Support)
|
||||
/// X/Y applied to FollowTarget, Z applied to Camera Dutch.
|
||||
/// 支持多个 Feedback 同时叠加震动。
|
||||
/// </summary>
|
||||
[AddComponentMenu("More Mountains/Feedbacks/Shakers/Cinemachine/MM Cinemachine Rotation Shaker")]
|
||||
[AddComponentMenu("More Mountains/Feedbacks/Shakers/Cinemachine/MM Cinemachine Rotation Shaker (Additive)")]
|
||||
#if MM_CINEMACHINE
|
||||
[RequireComponent(typeof(CinemachineVirtualCamera))]
|
||||
#elif MM_CINEMACHINE3
|
||||
@@ -41,12 +64,9 @@ namespace MoreMountains.FeedbacksForThirdParty
|
||||
{
|
||||
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;
|
||||
[MMInspectorGroup("Debug Info", true, 43)]
|
||||
[MMReadOnly]
|
||||
public int ActiveShakesCount = 0;
|
||||
|
||||
#if MM_CINEMACHINE
|
||||
protected CinemachineVirtualCamera _targetCamera;
|
||||
@@ -57,19 +77,18 @@ namespace MoreMountains.FeedbacksForThirdParty
|
||||
protected float _initialDutch;
|
||||
protected Quaternion _initialTargetRotation;
|
||||
|
||||
// --- 修复点 1: 显式声明这些备份变量 ---
|
||||
protected float _originalShakeDuration;
|
||||
protected Vector3 _originalShakeRotationAmplitude;
|
||||
protected AnimationCurve _originalShakeCurve;
|
||||
// 活跃震动列表
|
||||
protected List<MMCinemachineRotationShakeInstance> _activeShakes = new List<MMCinemachineRotationShakeInstance>();
|
||||
|
||||
protected override void Initialization()
|
||||
{
|
||||
base.Initialization();
|
||||
// 不调用 base.Initialization() 以完全接管 Update 逻辑
|
||||
#if MM_CINEMACHINE
|
||||
_targetCamera = GetComponent<CinemachineVirtualCamera>();
|
||||
#elif MM_CINEMACHINE3
|
||||
_targetCamera = GetComponent<CinemachineCamera>();
|
||||
#endif
|
||||
GrabInitialValues();
|
||||
}
|
||||
|
||||
protected override void GrabInitialValues()
|
||||
@@ -89,56 +108,84 @@ namespace MoreMountains.FeedbacksForThirdParty
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Shake()
|
||||
// 自定义 Update 处理叠加逻辑
|
||||
protected override void Update()
|
||||
{
|
||||
// --- 修复点 2: 使用 ShakeFloat 代替手动 ShakeTime 计算 ---
|
||||
// ShakeFloat 会自动处理时间、重映射和曲线计算
|
||||
// 我们请求一个 0 到 1 之间的浮点数作为当前的“强度”
|
||||
float intensity = ShakeFloat(ShakeCurve, 0f, 1f, false, 0f);
|
||||
if (_activeShakes.Count == 0)
|
||||
{
|
||||
Stop();
|
||||
return;
|
||||
}
|
||||
|
||||
// 根据强度应用 XYZ
|
||||
float xOffset = ShakeRotationAmplitude.x * intensity;
|
||||
float yOffset = ShakeRotationAmplitude.y * intensity;
|
||||
float zOffset = ShakeRotationAmplitude.z * intensity;
|
||||
float totalX = 0f;
|
||||
float totalY = 0f;
|
||||
float totalZ = 0f;
|
||||
|
||||
ApplyRotation(xOffset, yOffset, zOffset);
|
||||
// 倒序遍历列表
|
||||
for (int i = _activeShakes.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var shake = _activeShakes[i];
|
||||
|
||||
// 更新时间
|
||||
float deltaTime = (shake.TimescaleMode == TimescaleModes.Scaled) ? Time.deltaTime : Time.unscaledDeltaTime;
|
||||
shake.Timer += deltaTime;
|
||||
|
||||
// 计算当前强度
|
||||
float percent = Mathf.Clamp01(shake.Timer / shake.Duration);
|
||||
float curveValue = shake.Curve.Evaluate(percent);
|
||||
float currentIntensity = curveValue * shake.Intensity;
|
||||
|
||||
// 累加 Euler 角度
|
||||
totalX += shake.Amplitude.x * currentIntensity;
|
||||
totalY += shake.Amplitude.y * currentIntensity;
|
||||
totalZ += shake.Amplitude.z * currentIntensity;
|
||||
|
||||
// 移除过期震动
|
||||
if (shake.Timer >= shake.Duration)
|
||||
{
|
||||
_activeShakes.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
// 应用总偏移
|
||||
ApplyRotation(totalX, totalY, totalZ);
|
||||
|
||||
// 更新 Debug 计数
|
||||
ActiveShakesCount = _activeShakes.Count;
|
||||
|
||||
// 如果所有震动结束,强制归位
|
||||
if (_activeShakes.Count == 0)
|
||||
{
|
||||
ApplyRotation(0f, 0f, 0f);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void ApplyRotation(float x, float y, float z)
|
||||
protected virtual void ApplyRotation(float xOffset, float yOffset, float zOffset)
|
||||
{
|
||||
// Z -> Dutch
|
||||
// Z -> Dutch (直接加法)
|
||||
if (_targetCamera != null)
|
||||
{
|
||||
#if MM_CINEMACHINE
|
||||
_targetCamera.m_Lens.Dutch = _initialDutch + z;
|
||||
_targetCamera.m_Lens.Dutch = _initialDutch + zOffset;
|
||||
#elif MM_CINEMACHINE3
|
||||
_targetCamera.Lens.Dutch = _initialDutch + z;
|
||||
_targetCamera.Lens.Dutch = _initialDutch + zOffset;
|
||||
#endif
|
||||
}
|
||||
|
||||
// X/Y -> FollowTarget
|
||||
// X/Y -> FollowTarget (Quaternion 乘法)
|
||||
if (FollowTarget != null)
|
||||
{
|
||||
FollowTarget.localRotation = _initialTargetRotation * Quaternion.Euler(x, y, 0f);
|
||||
// 注意:这里我们将叠加后的 Euler 角度转换为 Quaternion,然后应用到初始旋转上
|
||||
FollowTarget.localRotation = _initialTargetRotation * Quaternion.Euler(xOffset, yOffset, 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 OnMMCinemachineRotationShakeEvent(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 virtual void OnMMCinemachineRotationShakeEvent(MMF_Feedback source,
|
||||
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;
|
||||
|
||||
@@ -153,27 +200,29 @@ namespace MoreMountains.FeedbacksForThirdParty
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Interruptible && Shaking) return;
|
||||
// 创建新实例并加入列表
|
||||
MMCinemachineRotationShakeInstance newShake = new MMCinemachineRotationShakeInstance(
|
||||
duration,
|
||||
rotationAmplitude, // 这里的 Amplitude 已经是外部传入的基准值,Intensity 在 Update 中计算
|
||||
shakeCurve,
|
||||
feedbacksIntensity,
|
||||
timescaleMode
|
||||
);
|
||||
|
||||
_resetShakerValuesAfterShake = resetShakerValuesAfterShake;
|
||||
_resetTargetValuesAfterShake = resetTargetValuesAfterShake;
|
||||
_activeShakes.Add(newShake);
|
||||
Play(source);
|
||||
}
|
||||
|
||||
if (resetShakerValuesAfterShake)
|
||||
{
|
||||
// 备份当前值
|
||||
_originalShakeDuration = ShakeDuration;
|
||||
_originalShakeRotationAmplitude = ShakeRotationAmplitude;
|
||||
_originalShakeCurve = ShakeCurve;
|
||||
}
|
||||
public override void Stop()
|
||||
{
|
||||
_activeShakes.Clear();
|
||||
ApplyRotation(0f, 0f, 0f);
|
||||
}
|
||||
|
||||
TimescaleMode = timescaleMode;
|
||||
ShakeDuration = duration;
|
||||
// 应用 Intensity
|
||||
ShakeRotationAmplitude = rotationAmplitude * feedbacksIntensity;
|
||||
ShakeCurve = shakeCurve;
|
||||
ForwardDirection = forwardDirection;
|
||||
|
||||
Play();
|
||||
protected override void ResetTargetValues()
|
||||
{
|
||||
base.ResetTargetValues();
|
||||
Stop();
|
||||
}
|
||||
|
||||
public override void StartListening()
|
||||
|
||||
Reference in New Issue
Block a user