后处理+FEEL完全改进

This commit is contained in:
SoulliesOfficial
2025-12-22 18:36:29 -05:00
parent c3914da4ac
commit a2052bfe16
1427 changed files with 193092 additions and 374110 deletions

View File

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

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: ed0f8ba8298344842a1de7e54165b68e

View File

@@ -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>

View File

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

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: a6732be1ae6977e40bb682d19bca778e

View File

@@ -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()