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

175 lines
6.2 KiB
C#

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);
}
}
}