后处理+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,8 @@
fileFormatVersion: 2
guid: 9b618aa6457357e4cbaea37bbf7a3197
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 633becd94b202e548862df56bf706a36
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,192 @@
using UnityEngine;
using MoreMountains.Feedbacks;
using MoreMountains.Tools;
using System.Linq; // 用于方便取 Max
namespace MoreMountains.FeedbacksForThirdParty.Cielonos
{
[AddComponentMenu("")]
[FeedbackPath("Cielonos/Time Scale Modifier")]
[FeedbackHelp("允许你同时控制 TimeManager 中的多个 TimeScale 通道。支持固定值模式和动态曲线模式。")]
public class CIF_TimeScaleModifier : MMF_Feedback
{
public static bool FeedbackTypeAuthorized = true;
#if UNITY_EDITOR
public override Color FeedbackColor { get { return MMFeedbacksInspectorColors.TimeColor; } }
public override bool EvaluateRequiresSetup() { return (GameObject.FindObjectOfType<CITimeScaleShaker>() == null); }
public override string RequiredTargetText { get { return "CITimeScaleShaker"; } }
public override string RequiresSetupText { get { return "This feedback requires a CITimeScaleShaker in the scene."; } }
#endif
[MMFInspectorGroup("General Settings", true, 10)]
[Tooltip("基础持续时间。如果没有勾选下方的 Override Duration所有通道都将使用此时间。")]
public float Duration = 1f;
// --- Global ---
[MMFInspectorGroup("Global Time Scale", true, 11)]
public bool ModifyGlobal = true;
// [新增] 覆盖 Duration 选项
[MMFCondition("ModifyGlobal", true)]
public bool GlobalOverrideDuration = false;
[MMFCondition("GlobalOverrideDuration", true)]
public float GlobalDuration = 0.5f;
[MMFCondition("ModifyGlobal", true)]
public TimeScaleShakeModes GlobalMode = TimeScaleShakeModes.Fixed;
[MMFCondition("ModifyGlobal", true)] [MMFEnumCondition("GlobalMode", (int)TimeScaleShakeModes.Fixed)]
public float GlobalFixedValue = 0f;
[MMFCondition("ModifyGlobal", true)] [MMFEnumCondition("GlobalMode", (int)TimeScaleShakeModes.Dynamic)]
public AnimationCurve GlobalCurve = new AnimationCurve(new Keyframe(0, 0), new Keyframe(0.5f, 1), new Keyframe(1, 0));
[MMFCondition("ModifyGlobal", true)] [MMFEnumCondition("GlobalMode", (int)TimeScaleShakeModes.Dynamic)]
public float GlobalRemapZero = 0f;
[MMFCondition("ModifyGlobal", true)] [MMFEnumCondition("GlobalMode", (int)TimeScaleShakeModes.Dynamic)]
public float GlobalRemapOne = 1f;
// --- Player ---
[MMFInspectorGroup("Player Time Scale", true, 12)]
public bool ModifyPlayer = false;
// [新增]
[MMFCondition("ModifyPlayer", true)]
public bool PlayerOverrideDuration = false;
[MMFCondition("PlayerOverrideDuration", true)]
public float PlayerDuration = 0.5f;
[MMFCondition("ModifyPlayer", true)]
public TimeScaleShakeModes PlayerMode = TimeScaleShakeModes.Dynamic;
[MMFCondition("ModifyPlayer", true)] [MMFEnumCondition("PlayerMode", (int)TimeScaleShakeModes.Fixed)]
public float PlayerFixedValue = 0.5f;
[MMFCondition("ModifyPlayer", true)] [MMFEnumCondition("PlayerMode", (int)TimeScaleShakeModes.Dynamic)]
public AnimationCurve PlayerCurve = new AnimationCurve(new Keyframe(0, 0), new Keyframe(0.5f, 1), new Keyframe(1, 0));
[MMFCondition("ModifyPlayer", true)] [MMFEnumCondition("PlayerMode", (int)TimeScaleShakeModes.Dynamic)]
public float PlayerRemapZero = 1f;
[MMFCondition("ModifyPlayer", true)] [MMFEnumCondition("PlayerMode", (int)TimeScaleShakeModes.Dynamic)]
public float PlayerRemapOne = 0.1f;
// --- Enemy ---
[MMFInspectorGroup("Enemy Time Scale", true, 13)]
public bool ModifyEnemy = false;
// [新增]
[MMFCondition("ModifyEnemy", true)]
public bool EnemyOverrideDuration = false;
[MMFCondition("EnemyOverrideDuration", true)]
public float EnemyDuration = 0.5f;
[MMFCondition("ModifyEnemy", true)]
public TimeScaleShakeModes EnemyMode = TimeScaleShakeModes.Fixed;
[MMFCondition("ModifyEnemy", true)] [MMFEnumCondition("EnemyMode", (int)TimeScaleShakeModes.Fixed)]
public float EnemyFixedValue = 0f;
[MMFCondition("ModifyEnemy", true)] [MMFEnumCondition("EnemyMode", (int)TimeScaleShakeModes.Dynamic)]
public AnimationCurve EnemyCurve = new AnimationCurve(new Keyframe(0, 0), new Keyframe(1, 1));
[MMFCondition("ModifyEnemy", true)] [MMFEnumCondition("EnemyMode", (int)TimeScaleShakeModes.Dynamic)]
public float EnemyRemapZero = 1f;
[MMFCondition("ModifyEnemy", true)] [MMFEnumCondition("EnemyMode", (int)TimeScaleShakeModes.Dynamic)]
public float EnemyRemapOne = 0f;
// --- NonPlayer ---
[MMFInspectorGroup("Non-Player Time Scale", true, 14)]
public bool ModifyNonPlayer = false;
// [新增]
[MMFCondition("ModifyNonPlayer", true)]
public bool NonPlayerOverrideDuration = false;
[MMFCondition("NonPlayerOverrideDuration", true)]
public float NonPlayerDuration = 0.5f;
[MMFCondition("ModifyNonPlayer", true)]
public TimeScaleShakeModes NonPlayerMode = TimeScaleShakeModes.Fixed;
[MMFCondition("ModifyNonPlayer", true)] [MMFEnumCondition("NonPlayerMode", (int)TimeScaleShakeModes.Fixed)]
public float NonPlayerFixedValue = 1f;
[MMFCondition("ModifyNonPlayer", true)] [MMFEnumCondition("NonPlayerMode", (int)TimeScaleShakeModes.Dynamic)]
public AnimationCurve NonPlayerCurve = new AnimationCurve(new Keyframe(0, 0), new Keyframe(1, 1));
[MMFCondition("ModifyNonPlayer", true)] [MMFEnumCondition("NonPlayerMode", (int)TimeScaleShakeModes.Dynamic)]
public float NonPlayerRemapZero = 0f;
[MMFCondition("ModifyNonPlayer", true)] [MMFEnumCondition("NonPlayerMode", (int)TimeScaleShakeModes.Dynamic)]
public float NonPlayerRemapOne = 1f;
// --- Allied ---
[MMFInspectorGroup("Allied Time Scale", true, 15)]
public bool ModifyAllied = false;
// [新增]
[MMFCondition("ModifyAllied", true)]
public bool AlliedOverrideDuration = false;
[MMFCondition("AlliedOverrideDuration", true)]
public float AlliedDuration = 0.5f;
[MMFCondition("ModifyAllied", true)]
public TimeScaleShakeModes AlliedMode = TimeScaleShakeModes.Fixed;
[MMFCondition("ModifyAllied", true)] [MMFEnumCondition("AlliedMode", (int)TimeScaleShakeModes.Fixed)]
public float AlliedFixedValue = 1f;
[MMFCondition("ModifyAllied", true)] [MMFEnumCondition("AlliedMode", (int)TimeScaleShakeModes.Dynamic)]
public AnimationCurve AlliedCurve = new AnimationCurve(new Keyframe(0, 0), new Keyframe(1, 1));
[MMFCondition("ModifyAllied", true)] [MMFEnumCondition("AlliedMode", (int)TimeScaleShakeModes.Dynamic)]
public float AlliedRemapZero = 0f;
[MMFCondition("ModifyAllied", true)] [MMFEnumCondition("AlliedMode", (int)TimeScaleShakeModes.Dynamic)]
public float AlliedRemapOne = 1f;
public override float FeedbackDuration { get { return ApplyTimeMultiplier(Duration); } set { Duration = value; } }
protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized) return;
// 1. 计算每个通道的实际时长
// 如果勾选了 Override则使用 OverrideDuration (需应用 ApplyTimeMultiplier 保持逻辑一致)
// 否则使用通用的 FeedbackDuration
float globalDur = (ModifyGlobal && GlobalOverrideDuration) ? ApplyTimeMultiplier(GlobalDuration) : FeedbackDuration;
float playerDur = (ModifyPlayer && PlayerOverrideDuration) ? ApplyTimeMultiplier(PlayerDuration) : FeedbackDuration;
float enemyDur = (ModifyEnemy && EnemyOverrideDuration) ? ApplyTimeMultiplier(EnemyDuration) : FeedbackDuration;
float alliedDur = (ModifyAllied && AlliedOverrideDuration) ? ApplyTimeMultiplier(AlliedDuration) : FeedbackDuration;
float nonPlayerDur = (ModifyNonPlayer && NonPlayerOverrideDuration) ? ApplyTimeMultiplier(NonPlayerDuration) : FeedbackDuration;
// 2. 找出最长的 Duration这将决定 Shaker 实例的存活时间
float maxDuration = FeedbackDuration;
if (ModifyGlobal) maxDuration = Mathf.Max(maxDuration, globalDur);
if (ModifyPlayer) maxDuration = Mathf.Max(maxDuration, playerDur);
if (ModifyEnemy) maxDuration = Mathf.Max(maxDuration, enemyDur);
if (ModifyAllied) maxDuration = Mathf.Max(maxDuration, alliedDur);
if (ModifyNonPlayer) maxDuration = Mathf.Max(maxDuration, nonPlayerDur);
// 3. 构建数据对象 (填入 Duration)
var globalData = new TimeScaleChannelData() { Active = ModifyGlobal, Duration = globalDur, Mode = GlobalMode, FixedValue = GlobalFixedValue, DynamicCurve = GlobalCurve, RemapZero = GlobalRemapZero, RemapOne = GlobalRemapOne };
var playerData = new TimeScaleChannelData() { Active = ModifyPlayer, Duration = playerDur, Mode = PlayerMode, FixedValue = PlayerFixedValue, DynamicCurve = PlayerCurve, RemapZero = PlayerRemapZero, RemapOne = PlayerRemapOne };
var enemyData = new TimeScaleChannelData() { Active = ModifyEnemy, Duration = enemyDur, Mode = EnemyMode, FixedValue = EnemyFixedValue, DynamicCurve = EnemyCurve, RemapZero = EnemyRemapZero, RemapOne = EnemyRemapOne };
var alliedData = new TimeScaleChannelData() { Active = ModifyAllied, Duration = alliedDur, Mode = AlliedMode, FixedValue = AlliedFixedValue, DynamicCurve = AlliedCurve, RemapZero = AlliedRemapZero, RemapOne = AlliedRemapOne };
var nonPlayerData = new TimeScaleChannelData() { Active = ModifyNonPlayer, Duration = nonPlayerDur, Mode = NonPlayerMode, FixedValue = NonPlayerFixedValue, DynamicCurve = NonPlayerCurve, RemapZero = NonPlayerRemapZero, RemapOne = NonPlayerRemapOne };
// 4. 触发事件
CITimeScaleShakeEvent.Trigger(
this,
maxDuration,
globalData,
playerData,
alliedData,
nonPlayerData,
enemyData,
feedbacksIntensity,
ChannelData
);
}
protected override void CustomStopFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized) return;
CITimeScaleShakeEvent.Trigger(this, 0f, null, null, null, null, null, stop: true);
}
protected override void CustomRestoreInitialValues()
{
// Do nothing
}
}
}

View File

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

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a2b104ac72ded2b44b7bfc167ad57a52
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,206 @@
using UnityEngine;
using MoreMountains.Feedbacks;
using MoreMountains.Tools;
using System.Collections.Generic;
using Cielonos.MainGame; // 保持你的引用
namespace MoreMountains.FeedbacksForThirdParty.Cielonos
{
public enum TimeScaleShakeModes { Fixed, Dynamic }
[System.Serializable]
public class TimeScaleChannelData
{
public bool Active = false;
public float Duration = 0f; // [新增] 存储该通道实际运行时长
public TimeScaleShakeModes Mode = TimeScaleShakeModes.Fixed;
public float FixedValue = 0f;
public AnimationCurve DynamicCurve;
public float RemapZero = 0f;
public float RemapOne = 1f;
public TimeScaleChannelData Copy()
{
return new TimeScaleChannelData()
{
Active = this.Active,
Duration = this.Duration, // [新增]
Mode = this.Mode,
FixedValue = this.FixedValue,
DynamicCurve = this.DynamicCurve,
RemapZero = this.RemapZero,
RemapOne = this.RemapOne
};
}
}
public class MMTimeScaleShakeInstance
{
public float TotalDuration; // 整个实例的总生命周期(等于最长的那个通道)
public float Timer;
public float IntensityMultiplier;
public TimescaleModes TimescaleMode;
public TimeScaleChannelData Global;
public TimeScaleChannelData Player;
public TimeScaleChannelData Allied;
public TimeScaleChannelData NonPlayer;
public TimeScaleChannelData Enemy;
public MMTimeScaleShakeInstance(float totalDuration, float intensity, TimescaleModes tsMode)
{
TotalDuration = totalDuration;
Timer = 0f;
IntensityMultiplier = intensity;
TimescaleMode = tsMode;
}
}
public struct CITimeScaleShakeEvent
{
public static void Register(Delegate callback) { OnEvent += callback; }
public static void Unregister(Delegate callback) { OnEvent -= callback; }
public delegate void Delegate(MMF_Feedback source, float maxDuration,
TimeScaleChannelData global, TimeScaleChannelData player, TimeScaleChannelData allied, TimeScaleChannelData nonPlayer, TimeScaleChannelData enemy,
float feedbacksIntensity = 1.0f, MMChannelData channelData = null, bool stop = false);
public static event Delegate OnEvent;
public static void Trigger(MMF_Feedback source, float maxDuration,
TimeScaleChannelData global, TimeScaleChannelData player, TimeScaleChannelData allied, TimeScaleChannelData nonPlayer, TimeScaleChannelData enemy,
float feedbacksIntensity = 1.0f, MMChannelData channelData = null, bool stop = false)
{
OnEvent?.Invoke(source, maxDuration, global, player, allied, nonPlayer, enemy, feedbacksIntensity, channelData, stop);
}
}
[AddComponentMenu("More Mountains/Feedbacks/Shakers/Cielonos/CI TimeScale Shaker")]
public class CITimeScaleShaker : MMShaker
{
[MMInspectorGroup("Debug Info", true, 44)]
[MMReadOnly]
public int ActiveShakesCount = 0;
protected List<MMTimeScaleShakeInstance> _activeShakes = new List<MMTimeScaleShakeInstance>();
protected override void Initialization()
{
if (TimeManager.Instance == null)
{
Debug.LogError("MMTimeScaleShaker: TimeManager Instance not found!");
}
}
protected override void Update()
{
if (TimeManager.Instance == null) return;
float finalGlobal = 1f;
float finalPlayer = 1f;
float finalAllied = 1f;
float finalNonPlayer = 1f;
float finalEnemy = 1f;
if (_activeShakes.Count > 0)
{
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;
// 计算每个通道的贡献 (注意:不再传入统一的 Progress而是传入当前 Timer)
ApplyChannel(shake.Global, ref finalGlobal, shake.Timer, shake.IntensityMultiplier);
ApplyChannel(shake.Player, ref finalPlayer, shake.Timer, shake.IntensityMultiplier);
ApplyChannel(shake.Allied, ref finalAllied, shake.Timer, shake.IntensityMultiplier);
ApplyChannel(shake.NonPlayer, ref finalNonPlayer, shake.Timer, shake.IntensityMultiplier);
ApplyChannel(shake.Enemy, ref finalEnemy, shake.Timer, shake.IntensityMultiplier);
// 移除过期 (使用 TotalDuration)
if (shake.Timer >= shake.TotalDuration)
{
_activeShakes.RemoveAt(i);
}
}
}
TimeManager.Instance.globalTimeScale.Value = finalGlobal;
TimeManager.Instance.playerTimeScale.Value = finalPlayer;
TimeManager.Instance.alliedMinionTimeScale.Value = finalAllied;
TimeManager.Instance.nonPlayerTimeScale.Value = finalNonPlayer;
TimeManager.Instance.enemyTimeScale.Value = finalEnemy;
ActiveShakesCount = _activeShakes.Count;
}
// 修改:传入 elapsedTime 而不是 normalized progress
protected void ApplyChannel(TimeScaleChannelData data, ref float totalScale, float elapsedTime, float intensityMultiplier)
{
if (!data.Active) return;
// [核心修改] 如果当前时间超过了该通道的 Duration则不再应用影响相当于 fade out 完成或结束)
if (elapsedTime > data.Duration) return;
// 归一化进度
float progress = Mathf.Clamp01(elapsedTime / data.Duration);
float currentValue = 1f;
if (data.Mode == TimeScaleShakeModes.Fixed)
{
currentValue = data.FixedValue;
}
else
{
float curveVal = data.DynamicCurve.Evaluate(progress);
currentValue = Mathf.LerpUnclamped(data.RemapZero, data.RemapOne, curveVal);
}
currentValue = Mathf.LerpUnclamped(1f, currentValue, intensityMultiplier);
totalScale *= currentValue;
}
public virtual void OnTimeScaleShakeEvent(MMF_Feedback source, float maxDuration,
TimeScaleChannelData global, TimeScaleChannelData player, TimeScaleChannelData allied, TimeScaleChannelData nonPlayer, TimeScaleChannelData enemy,
float feedbacksIntensity = 1.0f, MMChannelData channelData = null, bool stop = false)
{
if (!CheckEventAllowed(channelData)) return;
if (stop)
{
Stop();
return;
}
MMTimeScaleShakeInstance newShake = new MMTimeScaleShakeInstance(maxDuration, feedbacksIntensity, TimescaleModes.Unscaled);
newShake.Global = global.Copy();
newShake.Player = player.Copy();
newShake.Allied = allied.Copy();
newShake.NonPlayer = nonPlayer.Copy();
newShake.Enemy = enemy.Copy();
_activeShakes.Add(newShake);
// [用户要求] 必须调用 Play 才能让 Feedback 视为正在播放(用于 Duration 倒计时等)
Play(source);
}
public override void Stop()
{
_activeShakes.Clear();
}
public override void StartListening()
{
CITimeScaleShakeEvent.Register(OnTimeScaleShakeEvent);
}
public override void StopListening()
{
CITimeScaleShakeEvent.Unregister(OnTimeScaleShakeEvent);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 566c8a9b128b19f4ba1d4bf2cfb7b7f0

View File

@@ -0,0 +1,106 @@
using UnityEngine;
using MoreMountains.Feedbacks;
using MoreMountains.Tools;
namespace MoreMountains.FeedbacksForThirdParty
{
/// <summary>
/// 这个 Feedback 用于触发 MMCinemachineCameraDistanceShakeEvent
/// 进而控制挂载了 MMCinemachineCameraDistanceShaker 的相机距离。
/// </summary>
[AddComponentMenu("")]
[FeedbackHelp("This feedback allows you to control the Camera Distance of a Cinemachine Camera over time. You need a MMCinemachineCameraDistanceShaker on your camera.")]
[FeedbackPath("Camera/Cinemachine Camera Distance")]
public class MMF_CinemachineCameraDistance : MMF_Feedback
{
/// 用于禁用此类 Feedback 的静态开关
public static bool FeedbackTypeAuthorized = true;
/// 用于在 Inspector 列表中显示的颜色(这里使用了 Cinemachine 标志性的红色/橙色)
#if UNITY_EDITOR
public override Color FeedbackColor { get { return MMFeedbacksInspectorColors.CameraColor; } }
public override bool EvaluateRequiresSetup() { return (GameObject.FindObjectOfType<MMCinemachineCameraDistanceShaker>() == null); }
//public override string RequiredTargetText { get { return "MMCinemachineCameraDistanceShaker"; } }
public override string RequiresSetupText { get { return "This feedback requires that a MMCinemachineCameraDistanceShaker be present in your scene, typically on your Cinemachine Camera."; } }
#endif
[MMFInspectorGroup("Camera Distance", true, 72)]
[Tooltip("震动持续时间")]
public float ShakeDuration = 0.2f;
[Tooltip("是否使用相对值。如果勾选,将会在当前距离的基础上增加/减少;如果不勾选,则直接设置距离为绝对值。")]
public bool RelativeDistance = true;
[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 = -2f; // 默认 -2意味着产生“瞬间拉近”的效果非常适合打击感
[Tooltip("如果勾选Shake 结束后将重置 Shaker 的参数")]
public bool ResetShakerValuesAfterShake = true;
[Tooltip("如果勾选Shake 结束后相机的距离将恢复到初始值")]
public bool ResetTargetValuesAfterShake = true;
/// <summary>
/// 播放 Feedback
/// </summary>
protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
// 触发我们在上一步中定义的 Event
MMCinemachineCameraDistanceShakeEvent.Trigger(
ShakeDistance,
ShakeDuration,
RemapDistanceZero,
RemapDistanceOne,
RelativeDistance,
feedbacksIntensity,
ChannelData,
ResetShakerValuesAfterShake,
ResetTargetValuesAfterShake,
NormalPlayDirection,
ComputedTimescaleMode
);
}
/// <summary>
/// 停止 Feedback
/// </summary>
protected override void CustomStopFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
MMCinemachineCameraDistanceShakeEvent.Trigger(
ShakeDistance,
ShakeDuration,
RemapDistanceZero,
RemapDistanceOne,
RelativeDistance,
feedbacksIntensity,
ChannelData,
ResetShakerValuesAfterShake,
ResetTargetValuesAfterShake,
NormalPlayDirection,
ComputedTimescaleMode,
stop: true
);
}
protected override void CustomRestoreInitialValues()
{
MMCinemachineCameraDistanceShakeEvent.Trigger(ShakeDistance, FeedbackDuration, 0f, 1f, false, restore: true);
}
}
}

View File

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

View File

@@ -0,0 +1,126 @@
using MoreMountains.FeedbacksForThirdParty;
using MoreMountains.Tools;
using UnityEngine;
namespace MoreMountains.Feedbacks
{
public struct MMCinemachinePositionShakeEvent
{
static private event Delegate OnEvent;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
private static void RuntimeInitialization()
{
OnEvent = null;
}
public static void Register(Delegate callback)
{
OnEvent += callback;
}
public static void Unregister(Delegate callback)
{
OnEvent -= callback;
}
public delegate void Delegate(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);
public static void Trigger(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)
{
OnEvent?.Invoke(source, shakeCurve, duration, positionAmplitude, feedbacksIntensity, channelData, resetShakerValuesAfterShake,
resetTargetValuesAfterShake, forwardDirection, timescaleMode, stop);
}
}
[FeedbackPath("Camera/Cinemachine Position Shake")]
public class MMF_CinemachinePosition : MMF_Feedback
{
public static bool FeedbackTypeAuthorized = true;
public override float FeedbackDuration { get { return ApplyTimeMultiplier(Duration); } set { Duration = value; } }
public override bool HasChannel => true;
#if UNITY_EDITOR
public override Color FeedbackColor { get { return MMFeedbacksInspectorColors.CameraColor; } }
public override bool EvaluateRequiresSetup() { return (GameObject.FindObjectOfType<MMCinemachinePositionShaker>() == null); }
public override string RequiredTargetText { get { return "MMCinemachinePositionShaker"; } }
public override string RequiresSetupText { get { return "This feedback requires a MMCinemachinePositionShaker on your Camera."; } }
#endif
[MMFInspectorGroup("Position Shake", true, 39)]
public float Duration = 0.2f;
[Tooltip("The maximum amplitude of the shake.")]
public Vector3 PositionAmplitude = new Vector3(0.5f, 0.5f, 0f);
[Tooltip("The curve along which the shake will be animated.")]
public AnimationCurve ShakeCurve = new AnimationCurve(new Keyframe(0, 0), new Keyframe(0.2f, 1), new Keyframe(1, 0));
[MMFInspectorGroup("Distance Attenuation", true, 38)]
[Tooltip("如果勾选,抖动强度将根据摄像机与反馈位置的距离而衰减")]
public bool UseAttenuation = false;
[Tooltip("在这个范围内,抖动为全强度")]
public float AttenuationRange = 50f;
[Tooltip("定义强度随距离变化的曲线 (0代表近处/全强度, 1代表远处/无强度)")]
public AnimationCurve AttenuationCurve = new AnimationCurve(new Keyframe(0f, 1f), new Keyframe(1f, 0f));
[Header("Gizmos")]
public bool DrawGizmos = true;
protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized) return;
float intensityMultiplier = ComputeIntensity(feedbacksIntensity, position);
// 处理距离衰减
if (UseAttenuation && Camera.main != null)
{
float distance = Vector3.Distance(position, Camera.main.transform.position);
float normalizedDistance = Mathf.Clamp01(distance / AttenuationRange);
// 乘上衰减系数
intensityMultiplier *= AttenuationCurve.Evaluate(normalizedDistance);
}
// 触发事件
MMCinemachinePositionShakeEvent.Trigger(
this,
ShakeCurve,
FeedbackDuration,
PositionAmplitude,
intensityMultiplier,
ChannelData,
true, // resetShakerValues (在这种叠加模式下这个参数其实没用了,但保持签名一致)
true, // resetTargetValues (同上)
NormalPlayDirection,
ComputedTimescaleMode
);
}
protected override void CustomStopFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized) return;
MMCinemachinePositionShakeEvent.Trigger(
this, ShakeCurve, FeedbackDuration, PositionAmplitude,
0f, ChannelData, stop: true
);
}
public override void OnDrawGizmosSelectedHandler()
{
if (UseAttenuation && DrawGizmos)
{
Gizmos.color = MMColors.ReunoYellow;
Gizmos.DrawWireSphere(Owner.transform.position, AttenuationRange);
}
}
}
}

View File

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

View File

@@ -1,28 +1,21 @@
using MoreMountains.FeedbacksForThirdParty;
using MoreMountains.Feedbacks;
using MoreMountains.Tools;
using Sirenix.OdinInspector;
using UnityEngine;
using UnityEngine.Scripting.APIUpdating;
namespace MoreMountains.Feedbacks
namespace MoreMountains.FeedbacksForThirdParty
{
/// <summary>
/// 这个 Feedback 用于控制 Cinemachine 相机的旋转抖动。
/// X/Y 轴旋转将作用于 Shaker 上的 FollowTargetZ 轴旋转将作用于相机的 Dutch。
/// 需要在 Virtual Camera 上挂载 MMCinemachineRotationShaker。
/// </summary>
[AddComponentMenu("")]
[FeedbackPath("Camera/Cinemachine Rotation Shake")]
[FeedbackHelp("控制 Cinemachine 相机的旋转抖动。X/Y 轴作用于 Shaker 指定的 FollowTargetZ 轴作用于相机的 Dutch。需要在 Virtual Camera 上挂载 MMCinemachineRotationShaker。")]
[FeedbackHelp("控制 Cinemachine 相机的旋转抖动。X/Y 轴作用于 Shaker 指定的 FollowTargetZ 轴作用于相机的 Dutch。支持多个 Feedback 混合叠加。")]
public class MMF_CinemachineRotation : MMF_Feedback
{
/// 用于禁用此类 Feedback 的静态开关
public static bool FeedbackTypeAuthorized = true;
#if UNITY_EDITOR
public override Color FeedbackColor => MMFeedbacksInspectorColors.CameraColor;
public override bool HasCustomInspectors => true;
public override bool HasAutomaticShakerSetup => true;
public override bool EvaluateRequiresSetup() { return (GameObject.FindObjectOfType<MMCinemachineRotationShaker>() == null); }
public override string RequiredTargetText { get { return "MMCinemachineRotationShaker"; } }
public override string RequiresSetupText { get { return "This feedback requires a MMCinemachineRotationShaker on your Camera."; } }
#endif
public override float FeedbackDuration { get { return ApplyTimeMultiplier(Duration); } set { Duration = value; } }
@@ -39,7 +32,7 @@ namespace MoreMountains.Feedbacks
[Tooltip("定义抖动随时间变化的曲线")]
public AnimationCurve ShakeCurve = new AnimationCurve(new Keyframe(0, 0), new Keyframe(0.2f, 1), new Keyframe(1, 0));
[MMFInspectorGroup("Distance Attenuation (距离衰减)", true, 38)]
[MMFInspectorGroup("Distance Attenuation", true, 38)]
[Tooltip("如果勾选,抖动强度将根据摄像机与反馈位置的距离而衰减")]
public bool UseAttenuation = false;
[Tooltip("在这个范围内,抖动为全强度")]
@@ -47,12 +40,6 @@ namespace MoreMountains.Feedbacks
[Tooltip("定义强度随距离变化的曲线 (0代表近处/全强度, 1代表远处/无强度)")]
public AnimationCurve AttenuationCurve = new AnimationCurve(new Keyframe(0f, 1f), new Keyframe(1f, 0f));
[Space]
[Tooltip("抖动结束后是否重置 Shaker 的值为默认值")]
public bool ResetShakerValuesAfterShake = true;
[Tooltip("抖动结束后是否将目标的旋转归零")]
public bool ResetTargetValuesAfterShake = true;
[Header("Gizmos")]
public bool DrawGizmos = true;
@@ -66,20 +53,22 @@ namespace MoreMountains.Feedbacks
if (UseAttenuation && Camera.main != null)
{
float distance = Vector3.Distance(position, Camera.main.transform.position);
// 简单的线性映射,或者使用曲线
float normalizedDistance = Mathf.Clamp01(distance / AttenuationRange);
// 乘上衰减系数
intensityMultiplier *= AttenuationCurve.Evaluate(normalizedDistance);
}
// 触发事件 (叠加模式下ResetShakerValuesAfterShake 和 ResetTargetValuesAfterShake 不再起主要作用,但保留参数)
MMCinemachineRotationShakeEvent.Trigger(
this,
ShakeCurve,
FeedbackDuration,
RotationAmplitude,
0f, 1f, false, // RemapMin/Max 和 Relative 暂时不用,保留接口
0f, 1f, false,
intensityMultiplier,
ChannelData,
ResetShakerValuesAfterShake,
ResetTargetValuesAfterShake,
true, // resetShaker
true, // resetTarget
NormalPlayDirection,
ComputedTimescaleMode
);
@@ -88,14 +77,14 @@ namespace MoreMountains.Feedbacks
protected override void CustomStopFeedback(Vector3 position, float feedbacksIntensity = 1)
{
if (!Active || !FeedbackTypeAuthorized) return;
base.CustomStopFeedback(position, feedbacksIntensity);
MMCinemachineRotationShakeEvent.Trigger(ShakeCurve, FeedbackDuration, RotationAmplitude, 0f, 1f, false, stop: true);
// 发送 Stop 指令,这会清除 Shaker 中的所有列表
MMCinemachineRotationShakeEvent.Trigger(this, ShakeCurve, FeedbackDuration, RotationAmplitude, 0f, 1f, false, stop: true);
}
protected override void CustomRestoreInitialValues()
{
if (!Active || !FeedbackTypeAuthorized) return;
MMCinemachineRotationShakeEvent.Trigger(ShakeCurve, FeedbackDuration, RotationAmplitude, 0f, 1f, false, restore: true);
MMCinemachineRotationShakeEvent.Trigger(this, ShakeCurve, FeedbackDuration, RotationAmplitude, 0f, 1f, false, restore: true);
}
public override void OnDrawGizmosSelectedHandler()
@@ -106,20 +95,5 @@ namespace MoreMountains.Feedbacks
Gizmos.DrawWireSphere(Owner.transform.position, AttenuationRange);
}
}
public override void AutomaticShakerSetup()
{
// 自动查找并添加 Shaker
#if MM_CINEMACHINE
Cinemachine.CinemachineVirtualCamera vcam = Object.FindObjectOfType<Cinemachine.CinemachineVirtualCamera>();
if (vcam != null)
{
if (vcam.GetComponent<MMCinemachineRotationShaker>() == null)
{
vcam.gameObject.AddComponent<MMCinemachineRotationShaker>();
}
}
#endif
}
}
}

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

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c60f94c54a2b98a44bc13f707781de71
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 02db0b2b0ecd9de4ebd314f53da5198c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,112 @@
using UnityEngine;
using MoreMountains.Feedbacks;
using MoreMountains.Tools;
namespace MoreMountains.FeedbacksForThirdParty
{
[AddComponentMenu("")]
[FeedbackHelp("控制 Advanced Chromatic Aberration 效果。Intensity 支持曲线动画Center 和其他高级参数Extras支持在效果期间覆盖。")]
[FeedbackPath("PostProcess/Advanced Chromatic Aberration")]
public class MMF_AdvancedChromaticAberration : MMF_Feedback
{
public static bool FeedbackTypeAuthorized = true;
#if UNITY_EDITOR
public override Color FeedbackColor { get { return MMFeedbacksInspectorColors.PostProcessColor; } }
public override bool EvaluateRequiresSetup() { return (GameObject.FindObjectOfType<MMAdvancedChromaticAberrationShaker>() == null); }
public override string RequiredTargetText { get { return "MMAdvancedChromaticAberrationShaker"; } }
public override string RequiresSetupText { get { return "This feedback requires that a MMAdvancedChromaticAberrationShaker be present in your scene, typically on a Global Volume."; } }
#endif
[MMFInspectorGroup("Intensity Shake", true, 54)]
public float Duration = 0.2f;
public bool RelativeIntensity = false;
public AnimationCurve ShakeIntensity = new AnimationCurve(new Keyframe(0, 0), new Keyframe(0.5f, 1), new Keyframe(1, 0));
public float RemapIntensityZero = 0f;
public float RemapIntensityOne = 0.05f;
[MMFInspectorGroup("Center Settings", true, 55)]
[Tooltip("是否修改扩散中心点")]
public bool ModifyCenter = false;
[MMFCondition("ModifyCenter", true)]
[Tooltip("新的扩散中心点 (0.5, 0.5) 为屏幕中心")]
public Vector2 Center = new Vector2(0.5f, 0.5f);
[MMFInspectorGroup("Extra Settings", true, 56)]
[Tooltip("是否修改高级参数 (Split, Dispersion, Jitter, Mask)")]
public bool ModifyExtra = false;
[MMFCondition("ModifyExtra", true)]
[Tooltip("RGB 分离权重")]
public Vector3 ChannelSplit = new Vector3(1f, 0f, -1f);
[MMFCondition("ModifyExtra", true)]
[Tooltip("色散方向打乱强度")]
public float DispersionStrength = 0f;
[MMFCondition("ModifyExtra", true)]
[Tooltip("UV 抖动强度 (Temporal Instability)")]
public float JitterIntensity = 0f;
[MMFCondition("ModifyExtra", true)]
[Tooltip("中心遮罩半径")]
public float MaskRadius = 0.2f;
[MMFCondition("ModifyExtra", true)]
[Tooltip("遮罩边缘硬度")]
public float MaskHardness = 0.2f;
[MMFInspectorGroup("General", true, 57)]
public bool ResetShakerValuesAfterShake = true;
public bool ResetTargetValuesAfterShake = true;
public override float FeedbackDuration { get { return ApplyTimeMultiplier(Duration); } set { Duration = value; } }
protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized) return;
MMAdvancedChromaticAberrationShakeEvent.Trigger(
this,
ShakeIntensity,
FeedbackDuration,
RemapIntensityZero,
RemapIntensityOne,
RelativeIntensity,
feedbacksIntensity,
ChannelData,
ResetShakerValuesAfterShake,
ResetTargetValuesAfterShake,
NormalPlayDirection,
ComputedTimescaleMode,
false, // stop
false, // restore
// Center
ModifyCenter,
Center,
// Extras
ModifyExtra,
ChannelSplit,
DispersionStrength,
JitterIntensity,
MaskRadius,
MaskHardness
);
}
protected override void CustomStopFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized) return;
MMAdvancedChromaticAberrationShakeEvent.Trigger(this, ShakeIntensity, FeedbackDuration, RemapIntensityZero, RemapIntensityOne, RelativeIntensity, stop: true);
}
protected override void CustomRestoreInitialValues()
{
if (!Active || !FeedbackTypeAuthorized) return;
MMAdvancedChromaticAberrationShakeEvent.Trigger(this, ShakeIntensity, FeedbackDuration, RemapIntensityZero, RemapIntensityOne, RelativeIntensity, restore: true);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 979b72b70fd22c643a59ff6453baa3f3

View File

@@ -0,0 +1,110 @@
using UnityEngine;
using MoreMountains.Feedbacks;
using MoreMountains.Tools;
namespace MoreMountains.FeedbacksForThirdParty
{
[AddComponentMenu("")]
[FeedbackHelp("控制 Advanced Vignette 效果。用于制作受击暗角、环境压抑效果等。")]
[FeedbackPath("PostProcess/Advanced Vignette")]
public class MMF_AdvancedVignette : MMF_Feedback
{
public static bool FeedbackTypeAuthorized = true;
#if UNITY_EDITOR
public override Color FeedbackColor { get { return MMFeedbacksInspectorColors.PostProcessColor; } }
public override bool EvaluateRequiresSetup() { return (GameObject.FindObjectOfType<MMAdvancedVignetteShaker>() == null); }
public override string RequiredTargetText { get { return "MMAdvancedVignetteShaker"; } }
public override string RequiresSetupText { get { return "This feedback requires a MMAdvancedVignetteShaker on your Volume."; } }
#endif
[MMFInspectorGroup("Intensity Shake", true, 54)]
public float Duration = 0.2f;
public bool RelativeIntensity = false;
public AnimationCurve ShakeIntensity = new AnimationCurve(new Keyframe(0, 0), new Keyframe(0.5f, 1), new Keyframe(1, 0));
public float RemapIntensityZero = 0f;
public float RemapIntensityOne = 1f;
[MMFInspectorGroup("Center Settings", true, 55)]
public bool ModifyCenter = false;
[MMFCondition("ModifyCenter", true)]
public Vector2 Center = new Vector2(0.5f, 0.5f);
[MMFInspectorGroup("Color Settings", true, 56)]
public bool ModifyColors = false;
[MMFCondition("ModifyColors", true)]
[Tooltip("边缘最暗处的颜色")]
public Color ColorOuter = Color.black;
[MMFCondition("ModifyColors", true)]
[Tooltip("暗角过渡区的颜色")]
public Color ColorInner = Color.black;
[MMFInspectorGroup("Extra Settings", true, 57)]
public bool ModifyExtra = false;
[MMFCondition("ModifyExtra", true)]
[Tooltip("柔和度 (0.01 - 1)")]
public float Smoothness = 0.5f;
[MMFCondition("ModifyExtra", true)]
[Tooltip("圆度 (0 = 方形, 1 = 圆形)")]
public float Roundness = 1f;
[MMFInspectorGroup("General", true, 58)]
public bool ResetShakerValuesAfterShake = true;
public bool ResetTargetValuesAfterShake = true;
public override float FeedbackDuration { get { return ApplyTimeMultiplier(Duration); } set { Duration = value; } }
protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized) return;
MMAdvancedVignetteShakeEvent.Trigger(
this,
ShakeIntensity,
FeedbackDuration,
RemapIntensityZero,
RemapIntensityOne,
RelativeIntensity,
feedbacksIntensity,
ChannelData,
ResetShakerValuesAfterShake,
ResetTargetValuesAfterShake,
NormalPlayDirection,
ComputedTimescaleMode,
false, // stop
false, // restore
// Center
ModifyCenter,
Center,
// Colors
ModifyColors,
ColorOuter,
ColorInner,
// Extras
ModifyExtra,
Smoothness,
Roundness
);
}
protected override void CustomStopFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized) return;
MMAdvancedVignetteShakeEvent.Trigger(this, ShakeIntensity, FeedbackDuration, RemapIntensityZero, RemapIntensityOne, RelativeIntensity, stop: true);
}
protected override void CustomRestoreInitialValues()
{
if (!Active || !FeedbackTypeAuthorized) return;
MMAdvancedVignetteShakeEvent.Trigger(this, ShakeIntensity, FeedbackDuration, RemapIntensityZero, RemapIntensityOne, RelativeIntensity, restore: true);
}
}
}

View File

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

View File

@@ -0,0 +1,100 @@
using UnityEngine;
using MoreMountains.Feedbacks;
namespace MoreMountains.FeedbacksForThirdParty
{
[AddComponentMenu("")]
[FeedbackHelp("This feedback allows you to control the Blur Radius of your custom Radial Blur effect over time, and optionally set the Blur Center.")]
[FeedbackPath("PostProcess/Radial Blur")]
public class MMF_RadialBlur : MMF_Feedback
{
public static bool FeedbackTypeAuthorized = true;
#if UNITY_EDITOR
public override Color FeedbackColor { get { return MMFeedbacksInspectorColors.PostProcessColor; } }
public override bool EvaluateRequiresSetup() { return (GameObject.FindObjectOfType<MMRadialBlurShaker>() == null); }
public override string RequiredTargetText { get { return "MMRadialBlurShaker"; } }
public override string RequiresSetupText { get { return "This feedback requires that a MMRadialBlurShaker be present in your scene, typically on a Global Volume."; } }
#endif
[MMFInspectorGroup("Radial Blur Intensity", true, 45)]
[Tooltip("震动持续时间")]
public float ShakeDuration = 0.2f;
[Tooltip("是否使用相对值")]
public bool RelativeIntensity = false;
[Tooltip("震动曲线")]
public AnimationCurve ShakeIntensity = new AnimationCurve(new Keyframe(0, 0), new Keyframe(0.5f, 1), new Keyframe(1, 0));
[Tooltip("曲线 0 对应的模糊半径")]
public float RemapIntensityZero = 0f;
[Tooltip("曲线 1 对应的模糊半径")]
public float RemapIntensityOne = 0.5f;
// --- 新增部分:中心点控制 ---
[MMFInspectorGroup("Radial Center", true, 46)]
[Tooltip("是否修改模糊中心。如果关闭,将使用当前 Volume 的设置(通常为 0.5, 0.5)。")]
public bool ModifyCenter = true; // 默认开启
[Tooltip("模糊中心的屏幕坐标 (0-1)。(0.5, 0.5) 为屏幕正中心。")]
[MMFCondition("ModifyCenter", true)]
public Vector2 TargetCenter = new Vector2(0.5f, 0.5f);
// ---------------------------
[MMFInspectorGroup("Settings", true, 47)]
[Tooltip("结束后重置 Shaker")]
public bool ResetShakerValuesAfterShake = true;
[Tooltip("结束后重置目标值 (Blur Radius 和 Center)")]
public bool ResetTargetValuesAfterShake = true;
protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized) return;
MMRadialBlurShakeEvent.Trigger(
this,
ShakeIntensity,
ShakeDuration,
RemapIntensityZero,
RemapIntensityOne,
RelativeIntensity,
feedbacksIntensity,
ChannelData,
ResetShakerValuesAfterShake,
ResetTargetValuesAfterShake,
NormalPlayDirection,
ComputedTimescaleMode,
false, // stop
false, // restore
ModifyCenter, // 传递 modifyCenter
TargetCenter // 传递 Vector2 center
);
}
protected override void CustomStopFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized) return;
MMRadialBlurShakeEvent.Trigger(
this, ShakeIntensity, ShakeDuration, RemapIntensityZero, RemapIntensityOne, RelativeIntensity,
feedbacksIntensity, ChannelData, ResetShakerValuesAfterShake, ResetTargetValuesAfterShake,
NormalPlayDirection, ComputedTimescaleMode, stop: true
);
}
protected override void CustomRestoreInitialValues()
{
if (!Active || !FeedbackTypeAuthorized) return;
MMRadialBlurShakeEvent.Trigger(
this, ShakeIntensity, ShakeDuration, RemapIntensityZero, RemapIntensityOne, RelativeIntensity,
1.0f, ChannelData, ResetShakerValuesAfterShake, ResetTargetValuesAfterShake,
NormalPlayDirection, ComputedTimescaleMode, restore: true
);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 6fb5a79c3eeee014d871040588e4abc9

View File

@@ -0,0 +1,83 @@
using UnityEngine;
using MoreMountains.Feedbacks;
using MoreMountains.Tools;
namespace MoreMountains.FeedbacksForThirdParty
{
[AddComponentMenu("")]
[FeedbackHelp("控制 Strobe Flash (黑白闪) 效果。在 Duration 期间会自动开启 Auto Flash结束后关闭。")]
[FeedbackPath("PostProcess/Strobe Flash")]
public class MMF_StrobeFlash : MMF_Feedback
{
public static bool FeedbackTypeAuthorized = true;
#if UNITY_EDITOR
public override Color FeedbackColor { get { return MMFeedbacksInspectorColors.PostProcessColor; } }
public override bool EvaluateRequiresSetup() { return (GameObject.FindObjectOfType<MMStrobeFlashShaker>() == null); }
public override string RequiredTargetText { get { return "MMStrobeFlashShaker"; } }
public override string RequiresSetupText { get { return "This feedback requires a MMStrobeFlashShaker on your Volume."; } }
#endif
[MMFInspectorGroup("Strobe Settings", true, 54)]
[Tooltip("闪烁持续时间")]
public float Duration = 0.5f;
[MMFInspectorGroup("Extra Settings", true, 55)]
[Tooltip("是否修改频率和颜色")]
public bool ModifyExtra = false;
[MMFCondition("ModifyExtra", true)]
[Tooltip("闪烁频率")]
public float Frequency = 15f;
[MMFCondition("ModifyExtra", true)]
[Tooltip("高亮颜色 (通常为白色)")]
public Color ColorHigh = Color.white;
[MMFCondition("ModifyExtra", true)]
[Tooltip("暗部颜色 (通常为黑色)")]
public Color ColorLow = Color.black;
[MMFInspectorGroup("General", true, 56)]
public bool ResetShakerValuesAfterShake = true;
public bool ResetTargetValuesAfterShake = true;
public override float FeedbackDuration { get { return ApplyTimeMultiplier(Duration); } set { Duration = value; } }
protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized) return;
MMStrobeFlashShakeEvent.Trigger(
this,
FeedbackDuration,
feedbacksIntensity,
ChannelData,
ResetShakerValuesAfterShake,
ResetTargetValuesAfterShake,
NormalPlayDirection,
ComputedTimescaleMode,
false, // stop
false, // restore
// Extra Params
ModifyExtra,
Frequency,
ColorHigh,
ColorLow
);
}
protected override void CustomStopFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized) return;
MMStrobeFlashShakeEvent.Trigger(this, Duration, stop: true);
}
protected override void CustomRestoreInitialValues()
{
if (!Active || !FeedbackTypeAuthorized) return;
MMStrobeFlashShakeEvent.Trigger(this, Duration, restore: true);
}
}
}

View File

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

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b5e239d71a98e5c41b4a3f96adb1c3b1
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,219 @@
using UnityEngine;
using MoreMountains.Feedbacks;
using MoreMountains.Tools;
using UnityEngine.Rendering;
// 引入你的 PostProcess 命名空间
using SLSFramework.Rendering.PostProcessing;
namespace MoreMountains.FeedbacksForThirdParty
{
/// <summary>
/// 事件定义:携带所有必要的参数
/// </summary>
public struct MMAdvancedChromaticAberrationShakeEvent
{
public static void Register(Delegate callback) { OnEvent += callback; }
public static void Unregister(Delegate callback) { OnEvent -= callback; }
public delegate void Delegate(MMF_Feedback source, AnimationCurve intensityCurve, float duration, float remapMin, float remapMax, bool relativeIntensity = 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,
// Center
bool modifyCenter = false, Vector2 center = default,
// Extras
bool modifyExtra = false, Vector3 channelSplit = default, float dispersionStrength = 0f, float jitterIntensity = 0f, float maskRadius = 0.2f, float maskHardness = 0.2f);
public static event Delegate OnEvent;
public static void Trigger(MMF_Feedback source, AnimationCurve intensityCurve, float duration, float remapMin, float remapMax, bool relativeIntensity = 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,
bool modifyCenter = false, Vector2 center = default,
bool modifyExtra = false, Vector3 channelSplit = default, float dispersionStrength = 0f, float jitterIntensity = 0f, float maskRadius = 0.2f, float maskHardness = 0.2f)
{
OnEvent?.Invoke(source, intensityCurve, duration, remapMin, remapMax, relativeIntensity, feedbacksIntensity, channelData, resetShakerValuesAfterShake, resetTargetValuesAfterShake, forwardDirection, timescaleMode, stop, restore,
modifyCenter, center, modifyExtra, channelSplit, dispersionStrength, jitterIntensity, maskRadius, maskHardness);
}
}
/// <summary>
/// Shaker: 控制 Advanced Chromatic Aberration
/// </summary>
[AddComponentMenu("More Mountains/Feedbacks/Shakers/PostProcessing/MM Advanced Chromatic Aberration Shaker")]
[RequireComponent(typeof(Volume))]
public class MMAdvancedChromaticAberrationShaker : MMShaker
{
[MMInspectorGroup("Intensity", true, 53)]
[Tooltip("是否在现有 Intensity 基础上叠加")]
public bool RelativeIntensity = false;
[Tooltip("Intensity 的震动曲线")]
public AnimationCurve ShakeIntensity = new AnimationCurve(new Keyframe(0, 0), new Keyframe(0.5f, 1), new Keyframe(1, 0));
[Tooltip("曲线 0 对应的值")]
public float RemapIntensityZero = 0f;
[Tooltip("曲线 1 对应的值")]
public float RemapIntensityOne = 1f;
protected Volume _volume;
protected AdvancedChromaticAberration _aca;
// 初始值存储
protected float _initialIntensity;
protected Vector2 _initialCenter;
protected Vector3 _initialSplit;
protected float _initialDispersion;
protected float _initialJitter;
protected float _initialMaskRadius;
protected float _initialMaskHardness;
// 运行时目标值存储
protected bool _modifyCenter;
protected Vector2 _targetCenter;
protected bool _modifyExtra;
protected Vector3 _targetSplit;
protected float _targetDispersion;
protected float _targetJitter;
protected float _targetMaskRadius;
protected float _targetMaskHardness;
// Shaker 复位备份
protected float _originalShakeDuration;
protected bool _originalRelativeIntensity;
protected AnimationCurve _originalShakeIntensity;
protected float _originalRemapIntensityZero;
protected float _originalRemapIntensityOne;
protected override void Initialization()
{
base.Initialization();
_volume = GetComponent<Volume>();
if (!_volume.profile.TryGet(out _aca))
{
Debug.LogWarning("MMAdvancedChromaticAberrationShaker : No AdvancedChromaticAberration found in Volume on " + name);
}
}
protected override void GrabInitialValues()
{
if (_aca != null)
{
_initialIntensity = _aca.intensity.value;
_initialCenter = _aca.center.value;
_initialSplit = _aca.channelSplit.value;
_initialDispersion = _aca.dispersionStrength.value;
_initialJitter = _aca.jitterIntensity.value;
_initialMaskRadius = _aca.maskRadius.value;
_initialMaskHardness = _aca.maskHardness.value;
}
}
protected override void Shake()
{
if (_aca == null) return;
// 1. 驱动 Intensity (带有 Curve 动画)
float newIntensity = ShakeFloat(ShakeIntensity, RemapIntensityZero, RemapIntensityOne, RelativeIntensity, _initialIntensity);
_aca.intensity.value = newIntensity;
// 2. 驱动 Center (如果启用,强制设为目标值)
if (_modifyCenter)
{
_aca.center.value = _targetCenter;
}
// 3. 驱动 Extras (如果启用,强制设为目标值)
if (_modifyExtra)
{
_aca.channelSplit.value = _targetSplit;
_aca.dispersionStrength.value = _targetDispersion;
_aca.jitterIntensity.value = _targetJitter;
_aca.maskRadius.value = _targetMaskRadius;
_aca.maskHardness.value = _targetMaskHardness;
}
}
protected override void ResetTargetValues()
{
base.ResetTargetValues();
if (_aca != null)
{
_aca.intensity.value = _initialIntensity;
_aca.center.value = _initialCenter;
_aca.channelSplit.value = _initialSplit;
_aca.dispersionStrength.value = _initialDispersion;
_aca.jitterIntensity.value = _initialJitter;
_aca.maskRadius.value = _initialMaskRadius;
_aca.maskHardness.value = _initialMaskHardness;
}
}
protected override void ResetShakerValues()
{
base.ResetShakerValues();
ShakeDuration = _originalShakeDuration;
ShakeIntensity = _originalShakeIntensity;
RemapIntensityZero = _originalRemapIntensityZero;
RemapIntensityOne = _originalRemapIntensityOne;
RelativeIntensity = _originalRelativeIntensity;
_modifyCenter = false;
_modifyExtra = false;
}
public virtual void OnEvent(MMF_Feedback source, AnimationCurve intensityCurve, float duration, float remapMin, float remapMax, bool relativeIntensity = 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,
bool modifyCenter = false, Vector2 center = default,
bool modifyExtra = false, Vector3 channelSplit = default, float dispersionStrength = 0f, float jitterIntensity = 0f, float maskRadius = 0.2f, float maskHardness = 0.2f)
{
if (!CheckEventAllowed(channelData)) return;
if (stop) { Stop(); return; }
if (restore) { ResetTargetValues(); return; }
if (resetShakerValuesAfterShake)
{
_originalShakeDuration = ShakeDuration;
_originalShakeIntensity = ShakeIntensity;
_originalRemapIntensityZero = RemapIntensityZero;
_originalRemapIntensityOne = RemapIntensityOne;
_originalRelativeIntensity = RelativeIntensity;
}
if (!OnlyUseShakerValues)
{
TimescaleMode = timescaleMode;
ShakeDuration = duration;
ShakeIntensity = intensityCurve;
RemapIntensityZero = remapMin * feedbacksIntensity;
RemapIntensityOne = remapMax * feedbacksIntensity;
RelativeIntensity = relativeIntensity;
ForwardDirection = forwardDirection;
// 接收额外参数
_modifyCenter = modifyCenter;
_targetCenter = center;
_modifyExtra = modifyExtra;
_targetSplit = channelSplit;
_targetDispersion = dispersionStrength;
_targetJitter = jitterIntensity;
_targetMaskRadius = maskRadius;
_targetMaskHardness = maskHardness;
}
Play(source);
}
public override void StartListening()
{
base.StartListening();
MMAdvancedChromaticAberrationShakeEvent.Register(OnEvent);
}
public override void StopListening()
{
base.StopListening();
MMAdvancedChromaticAberrationShakeEvent.Unregister(OnEvent);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 83e1b594d698f9449ac7adafb9976fec

View File

@@ -0,0 +1,224 @@
using UnityEngine;
using MoreMountains.Feedbacks;
using MoreMountains.Tools;
using UnityEngine.Rendering;
// 引入你的命名空间
using SLSFramework.Rendering.PostProcessing;
namespace MoreMountains.FeedbacksForThirdParty
{
/// <summary>
/// 事件定义:携带 Advanced Vignette 所需的所有参数
/// </summary>
public struct MMAdvancedVignetteShakeEvent
{
public static void Register(Delegate callback) { OnEvent += callback; }
public static void Unregister(Delegate callback) { OnEvent -= callback; }
public delegate void Delegate(MMF_Feedback source, AnimationCurve intensityCurve, float duration, float remapMin, float remapMax, bool relativeIntensity = 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,
// Custom Params
bool modifyCenter = false, Vector2 center = default,
bool modifyColors = false, Color colorOuter = default, Color colorInner = default,
bool modifyExtra = false, float smoothness = 0.5f, float roundness = 1f);
public static event Delegate OnEvent;
public static void Trigger(MMF_Feedback source, AnimationCurve intensityCurve, float duration, float remapMin, float remapMax, bool relativeIntensity = 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,
bool modifyCenter = false, Vector2 center = default,
bool modifyColors = false, Color colorOuter = default, Color colorInner = default,
bool modifyExtra = false, float smoothness = 0.5f, float roundness = 1f)
{
OnEvent?.Invoke(source, intensityCurve, duration, remapMin, remapMax, relativeIntensity, feedbacksIntensity, channelData, resetShakerValuesAfterShake, resetTargetValuesAfterShake, forwardDirection, timescaleMode, stop, restore,
modifyCenter, center, modifyColors, colorOuter, colorInner, modifyExtra, smoothness, roundness);
}
}
/// <summary>
/// Shaker: 控制 Advanced Vignette 效果
/// </summary>
[AddComponentMenu("More Mountains/Feedbacks/Shakers/PostProcessing/MM Advanced Vignette Shaker")]
[RequireComponent(typeof(Volume))]
public class MMAdvancedVignetteShaker : MMShaker
{
[MMInspectorGroup("Intensity", true, 53)]
[Tooltip("是否在现有 Intensity 基础上叠加")]
public bool RelativeIntensity = false;
[Tooltip("Intensity 的震动曲线")]
public AnimationCurve ShakeIntensity = new AnimationCurve(new Keyframe(0, 0), new Keyframe(0.5f, 1), new Keyframe(1, 0));
[Tooltip("曲线 0 对应的值")]
public float RemapIntensityZero = 0f;
[Tooltip("曲线 1 对应的值")]
public float RemapIntensityOne = 1f;
protected Volume _volume;
protected AdvancedVignette _vignette;
// 初始值存储
protected float _initialIntensity;
protected Vector2 _initialCenter;
protected Color _initialColorOuter;
protected Color _initialColorInner;
protected float _initialSmoothness;
protected float _initialRoundness;
// 运行时目标值
protected bool _modifyCenter;
protected Vector2 _targetCenter;
protected bool _modifyColors;
protected Color _targetColorOuter;
protected Color _targetColorInner;
protected bool _modifyExtra;
protected float _targetSmoothness;
protected float _targetRoundness;
// Shaker 状态备份
protected float _originalShakeDuration;
protected bool _originalRelativeIntensity;
protected AnimationCurve _originalShakeIntensity;
protected float _originalRemapIntensityZero;
protected float _originalRemapIntensityOne;
protected override void Initialization()
{
base.Initialization();
_volume = GetComponent<Volume>();
if (!_volume.profile.TryGet(out _vignette))
{
Debug.LogWarning("MMAdvancedVignetteShaker : No AdvancedVignette found in Volume on " + name);
}
}
protected override void GrabInitialValues()
{
if (_vignette != null)
{
_initialIntensity = _vignette.intensity.value;
_initialCenter = _vignette.center.value;
_initialColorOuter = _vignette.colorOuter.value;
_initialColorInner = _vignette.colorInner.value;
_initialSmoothness = _vignette.smoothness.value;
_initialRoundness = _vignette.roundness.value;
}
}
protected override void Shake()
{
if (_vignette == null) return;
// 1. 驱动 Intensity
float newIntensity = ShakeFloat(ShakeIntensity, RemapIntensityZero, RemapIntensityOne, RelativeIntensity, _initialIntensity);
_vignette.intensity.value = newIntensity;
// 2. 驱动 Center
if (_modifyCenter)
{
_vignette.center.value = _targetCenter;
}
// 3. 驱动 Colors
if (_modifyColors)
{
_vignette.colorOuter.value = _targetColorOuter;
_vignette.colorInner.value = _targetColorInner;
}
// 4. 驱动 Extra (Smoothness, Roundness)
if (_modifyExtra)
{
_vignette.smoothness.value = _targetSmoothness;
_vignette.roundness.value = _targetRoundness;
}
}
protected override void ResetTargetValues()
{
base.ResetTargetValues();
if (_vignette != null)
{
_vignette.intensity.value = _initialIntensity;
_vignette.center.value = _initialCenter;
_vignette.colorOuter.value = _initialColorOuter;
_vignette.colorInner.value = _initialColorInner;
_vignette.smoothness.value = _initialSmoothness;
_vignette.roundness.value = _initialRoundness;
}
}
protected override void ResetShakerValues()
{
base.ResetShakerValues();
ShakeDuration = _originalShakeDuration;
ShakeIntensity = _originalShakeIntensity;
RemapIntensityZero = _originalRemapIntensityZero;
RemapIntensityOne = _originalRemapIntensityOne;
RelativeIntensity = _originalRelativeIntensity;
_modifyCenter = false;
_modifyColors = false;
_modifyExtra = false;
}
public virtual void OnEvent(MMF_Feedback source, AnimationCurve intensityCurve, float duration, float remapMin, float remapMax, bool relativeIntensity = 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,
bool modifyCenter = false, Vector2 center = default,
bool modifyColors = false, Color colorOuter = default, Color colorInner = default,
bool modifyExtra = false, float smoothness = 0.5f, float roundness = 1f)
{
if (!CheckEventAllowed(channelData)) return;
if (stop) { Stop(); return; }
if (restore) { ResetTargetValues(); return; }
if (resetShakerValuesAfterShake)
{
_originalShakeDuration = ShakeDuration;
_originalShakeIntensity = ShakeIntensity;
_originalRemapIntensityZero = RemapIntensityZero;
_originalRemapIntensityOne = RemapIntensityOne;
_originalRelativeIntensity = RelativeIntensity;
}
if (!OnlyUseShakerValues)
{
TimescaleMode = timescaleMode;
ShakeDuration = duration;
ShakeIntensity = intensityCurve;
RemapIntensityZero = remapMin * feedbacksIntensity;
RemapIntensityOne = remapMax * feedbacksIntensity;
RelativeIntensity = relativeIntensity;
ForwardDirection = forwardDirection;
_modifyCenter = modifyCenter;
_targetCenter = center;
_modifyColors = modifyColors;
_targetColorOuter = colorOuter;
_targetColorInner = colorInner;
_modifyExtra = modifyExtra;
_targetSmoothness = smoothness;
_targetRoundness = roundness;
}
Play(source);
}
public override void StartListening()
{
base.StartListening();
MMAdvancedVignetteShakeEvent.Register(OnEvent);
}
public override void StopListening()
{
base.StopListening();
MMAdvancedVignetteShakeEvent.Unregister(OnEvent);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 11b930e92331e8c48b320c5d04808814

View File

@@ -0,0 +1,187 @@
using UnityEngine;
using MoreMountains.Feedbacks;
using MoreMountains.Tools;
using UnityEngine.Rendering;
using SLSFramework.Rendering.PostProcessing;
namespace MoreMountains.FeedbacksForThirdParty
{
public struct MMRadialBlurShakeEvent
{
public static void Register(Delegate callback) { OnEvent += callback; }
public static void Unregister(Delegate callback) { OnEvent -= callback; }
// 修改点:在参数列表中增加了 modifyCenter 和 center
public delegate void Delegate(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,
bool modifyCenter = false, Vector2 center = default); // 新增参数放在最后,带默认值以保持兼容性
public static event Delegate OnEvent;
public static void Trigger(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,
bool modifyCenter = false, Vector2 center = default)
{
OnEvent?.Invoke(source, distortionCurve, duration, remapMin, remapMax, relativeDistortion, feedbacksIntensity, channelData, resetShakerValuesAfterShake, resetTargetValuesAfterShake, forwardDirection, timescaleMode, stop, restore, modifyCenter, center);
}
}
[AddComponentMenu("More Mountains/Feedbacks/Shakers/PostProcessing/MM Radial Blur Shaker")]
[RequireComponent(typeof(Volume))]
public class MMRadialBlurShaker : MMShaker
{
[MMInspectorGroup("Radial Blur", true, 52)]
[Tooltip("是否在现有值的基础上叠加")]
public bool RelativeIntensity = false;
[Tooltip("模糊强度的震动曲线")]
public AnimationCurve ShakeIntensity = new AnimationCurve(new Keyframe(0, 0), new Keyframe(0.5f, 1), new Keyframe(1, 0));
[Tooltip("曲线 0 对应的 Blur Radius 值")]
public float RemapIntensityZero = 0f;
[Tooltip("曲线 1 对应的 Blur Radius 值")]
public float RemapIntensityOne = 1f;
protected Volume _volume;
protected RadialBlur _radialBlur;
// 初始值记录
protected float _initialIntensity;
protected float _initialCenterX;
protected float _initialCenterY;
// 震动时的临时变量
protected bool _modifyCenter;
protected Vector2 _targetCenter;
protected float _originalShakeDuration;
protected bool _originalRelativeIntensity;
protected AnimationCurve _originalShakeIntensity;
protected float _originalRemapIntensityZero;
protected float _originalRemapIntensityOne;
protected override void Initialization()
{
base.Initialization();
_volume = this.gameObject.GetComponent<Volume>();
if (_volume.profile.TryGet<RadialBlur>(out _radialBlur))
{
// 获取成功
}
else
{
Debug.LogWarning("MMRadialBlurShaker : No RadialBlur Override found in the Volume on " + this.name);
}
}
protected override void GrabInitialValues()
{
if (_radialBlur != null)
{
_initialIntensity = _radialBlur.blurRadius.value;
_initialCenterX = _radialBlur.radialCenterX.value;
_initialCenterY = _radialBlur.radialCenterY.value;
}
}
protected override void Shake()
{
if (_radialBlur == null) return;
// 1. 处理模糊强度 (Radius)
float newIntensity = ShakeFloat(ShakeIntensity, RemapIntensityZero, RemapIntensityOne, RelativeIntensity, _initialIntensity);
_radialBlur.blurRadius.value = newIntensity;
// 2. 处理模糊中心 (Center) - 新增逻辑
// 只有当 Feedback 要求修改中心时才覆盖,否则保持原样 (通常是 0.5)
if (_modifyCenter)
{
_radialBlur.radialCenterX.value = _targetCenter.x;
_radialBlur.radialCenterY.value = _targetCenter.y;
}
else
{
// 如果不修改,我们强制设为默认中心(0.5, 0.5)或者初始值?
// 根据你的描述:如果不开启,默认中心为(0.5,0.5)。
// 为了保险这里可以不做操作保留Volume当前值也可以强制复位。
// 建议不做操作让ResetTargetValues去负责恢复。
}
}
protected override void ResetTargetValues()
{
base.ResetTargetValues();
if (_radialBlur != null)
{
_radialBlur.blurRadius.value = _initialIntensity;
// 复位中心点
_radialBlur.radialCenterX.value = _initialCenterX;
_radialBlur.radialCenterY.value = _initialCenterY;
}
}
protected override void ResetShakerValues()
{
base.ResetShakerValues();
ShakeDuration = _originalShakeDuration;
ShakeIntensity = _originalShakeIntensity;
RemapIntensityZero = _originalRemapIntensityZero;
RemapIntensityOne = _originalRemapIntensityOne;
RelativeIntensity = _originalRelativeIntensity;
// 震动结束,重置 modifyCenter 标记,防止后续影响
_modifyCenter = false;
}
public virtual void OnMMRadialBlurShakeEvent(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,
bool modifyCenter = false, Vector2 center = default)
{
if (!CheckEventAllowed(channelData)) return;
if (stop) { Stop(); return; }
if (restore) { ResetTargetValues(); return; }
if (!Interruptible && Shaking) return;
_resetShakerValuesAfterShake = resetShakerValuesAfterShake;
_resetTargetValuesAfterShake = resetTargetValuesAfterShake;
if (resetShakerValuesAfterShake)
{
_originalShakeDuration = ShakeDuration;
_originalShakeIntensity = ShakeIntensity;
_originalRemapIntensityZero = RemapIntensityZero;
_originalRemapIntensityOne = RemapIntensityOne;
_originalRelativeIntensity = RelativeIntensity;
}
if (!OnlyUseShakerValues)
{
TimescaleMode = timescaleMode;
ShakeDuration = duration;
ShakeIntensity = distortionCurve;
RemapIntensityZero = remapMin * feedbacksIntensity;
RemapIntensityOne = remapMax * feedbacksIntensity;
RelativeIntensity = relativeDistortion;
ForwardDirection = forwardDirection;
// 接收并存储中心点参数
_modifyCenter = modifyCenter;
_targetCenter = center;
}
Play(source);
}
public override void StartListening()
{
base.StartListening();
MMRadialBlurShakeEvent.Register(OnMMRadialBlurShakeEvent);
}
public override void StopListening()
{
base.StopListening();
MMRadialBlurShakeEvent.Unregister(OnMMRadialBlurShakeEvent);
}
}
}

View File

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

View File

@@ -0,0 +1,188 @@
using UnityEngine;
using MoreMountains.Feedbacks;
using MoreMountains.Tools;
using UnityEngine.Rendering;
using SLSFramework.Rendering.PostProcessing;
namespace MoreMountains.FeedbacksForThirdParty
{
public struct MMStrobeFlashShakeEvent
{
public static void Register(Delegate callback) { OnEvent += callback; }
public static void Unregister(Delegate callback) { OnEvent -= callback; }
public delegate void Delegate(MMF_Feedback source, float duration,
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,
bool modifyExtra = false, float frequency = 15f, Color colorHigh = default, Color colorLow = default);
public static event Delegate OnEvent;
public static void Trigger(MMF_Feedback source, float duration,
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,
bool modifyExtra = false, float frequency = 15f, Color colorHigh = default, Color colorLow = default)
{
OnEvent?.Invoke(source, duration, feedbacksIntensity, channelData, resetShakerValuesAfterShake, resetTargetValuesAfterShake, forwardDirection, timescaleMode, stop, restore,
modifyExtra, frequency, colorHigh, colorLow);
}
}
[AddComponentMenu("More Mountains/Feedbacks/Shakers/PostProcessing/MM Strobe Flash Shaker")]
[RequireComponent(typeof(Volume))]
public class MMStrobeFlashShaker : MMShaker
{
[MMInspectorGroup("Strobe Settings", true, 53)]
[Tooltip("如果勾选,震动结束后会强制关闭 Effect无论初始状态是什么。建议勾选。")]
public bool ForceOffAfterShake = true;
[MMInspectorGroup("Debug Info", true, 54)]
[MMReadOnly]
public bool IsActive = false;
protected Volume _volume;
protected StrobeFlash _strobe;
protected bool _initialEnableEffect;
protected bool _initialAutoFlash;
protected float _initialFrequency;
protected Color _initialColorHigh;
protected Color _initialColorLow;
protected bool _modifyExtra;
protected float _targetFrequency;
protected Color _targetColorHigh;
protected Color _targetColorLow;
protected float _originalShakeDuration;
protected override void Initialization()
{
base.Initialization();
_volume = GetComponent<Volume>();
if (!_volume.profile.TryGet(out _strobe))
{
Debug.LogWarning("MMStrobeFlashShaker : No StrobeFlash found in Volume on " + name);
}
}
protected override void GrabInitialValues()
{
if (_strobe != null)
{
_initialEnableEffect = _strobe.enableEffect.value;
_initialAutoFlash = _strobe.autoFlash.value;
_initialFrequency = _strobe.frequency.value;
_initialColorHigh = _strobe.colorHigh.value;
_initialColorLow = _strobe.colorLow.value;
}
}
protected override void Shake()
{
if (_strobe == null) return;
// 强制开启
_strobe.enableEffect.value = true;
_strobe.autoFlash.value = true;
IsActive = true;
if (_modifyExtra)
{
_strobe.frequency.value = _targetFrequency;
_strobe.colorHigh.value = _targetColorHigh;
_strobe.colorLow.value = _targetColorLow;
}
}
// 确保 Stop 被调用时执行复位
public override void Stop()
{
base.Stop();
// base.Stop() 会调用 ResetTargetValues但为了保险再次确保状态
IsActive = false;
}
protected override void ResetTargetValues()
{
base.ResetTargetValues();
IsActive = false;
if (_strobe != null)
{
// [关键修改] 如果开启了强制关闭,直接设为 false否则恢复初始值
if (ForceOffAfterShake)
{
_strobe.enableEffect.value = false;
_strobe.autoFlash.value = false;
}
else
{
_strobe.enableEffect.value = _initialEnableEffect;
_strobe.autoFlash.value = _initialAutoFlash;
}
_strobe.frequency.value = _initialFrequency;
_strobe.colorHigh.value = _initialColorHigh;
_strobe.colorLow.value = _initialColorLow;
}
}
protected override void ResetShakerValues()
{
base.ResetShakerValues();
ShakeDuration = _originalShakeDuration;
_modifyExtra = false;
}
// 增加 OnDisable 处理,防止游戏物体被禁用时状态残留
protected virtual void OnDisable()
{
if (IsActive)
{
ResetTargetValues();
}
}
public virtual void OnEvent(MMF_Feedback source, float duration,
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,
bool modifyExtra = false, float frequency = 15f, Color colorHigh = default, Color colorLow = default)
{
if (!CheckEventAllowed(channelData)) return;
if (stop) { Stop(); return; }
if (restore) { ResetTargetValues(); return; }
if (resetShakerValuesAfterShake)
{
_originalShakeDuration = ShakeDuration;
}
if (!OnlyUseShakerValues)
{
TimescaleMode = timescaleMode;
ShakeDuration = duration;
_modifyExtra = modifyExtra;
_targetFrequency = frequency;
_targetColorHigh = colorHigh;
_targetColorLow = colorLow;
}
// 你的框架修改:传入 source
Play(source);
}
public override void StartListening()
{
base.StartListening();
MMStrobeFlashShakeEvent.Register(OnEvent);
}
public override void StopListening()
{
base.StopListening();
MMStrobeFlashShakeEvent.Unregister(OnEvent);
}
}
}

View File

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

View File

@@ -74,7 +74,7 @@ namespace MoreMountains.FeedbacksForThirdParty
}
float intensityMultiplier = ComputeIntensity(feedbacksIntensity, position);
MMChromaticAberrationShakeEvent_URP.Trigger(Intensity, FeedbackDuration, RemapIntensityZero, RemapIntensityOne, RelativeIntensity, intensityMultiplier,
MMChromaticAberrationShakeEvent_URP.Trigger(this, Intensity, FeedbackDuration, RemapIntensityZero, RemapIntensityOne, RelativeIntensity, intensityMultiplier,
ChannelData, ResetShakerValuesAfterShake, ResetTargetValuesAfterShake, NormalPlayDirection, ComputedTimescaleMode);
}
@@ -91,7 +91,7 @@ namespace MoreMountains.FeedbacksForThirdParty
}
base.CustomStopFeedback(position, feedbacksIntensity);
MMChromaticAberrationShakeEvent_URP.Trigger(Intensity, FeedbackDuration, RemapIntensityZero, RemapIntensityOne, RelativeIntensity, channelData:ChannelData, stop:true);
MMChromaticAberrationShakeEvent_URP.Trigger(this, Intensity, FeedbackDuration, RemapIntensityZero, RemapIntensityOne, RelativeIntensity, channelData:ChannelData, stop:true);
}
/// <summary>
@@ -104,7 +104,7 @@ namespace MoreMountains.FeedbacksForThirdParty
return;
}
MMChromaticAberrationShakeEvent_URP.Trigger(Intensity, FeedbackDuration, RemapIntensityZero, RemapIntensityOne, RelativeIntensity, channelData:ChannelData, restore:true);
MMChromaticAberrationShakeEvent_URP.Trigger(this, Intensity, FeedbackDuration, RemapIntensityZero, RemapIntensityOne, RelativeIntensity, channelData:ChannelData, restore:true);
}
/// <summary>

View File

@@ -137,7 +137,7 @@ namespace MoreMountains.FeedbacksForThirdParty
}
float intensityMultiplier = ComputeIntensity(feedbacksIntensity, position);
MMColorAdjustmentsShakeEvent_URP.Trigger(ShakePostExposure, RemapPostExposureZero, RemapPostExposureOne,
MMColorAdjustmentsShakeEvent_URP.Trigger(this, ShakePostExposure, RemapPostExposureZero, RemapPostExposureOne,
ShakeHueShift, RemapHueShiftZero, RemapHueShiftOne,
ShakeSaturation, RemapSaturationZero, RemapSaturationOne,
ShakeContrast, RemapContrastZero, RemapContrastOne,
@@ -160,7 +160,7 @@ namespace MoreMountains.FeedbacksForThirdParty
}
base.CustomStopFeedback(position, feedbacksIntensity);
MMColorAdjustmentsShakeEvent_URP.Trigger(ShakePostExposure, RemapPostExposureZero, RemapPostExposureOne,
MMColorAdjustmentsShakeEvent_URP.Trigger(this, ShakePostExposure, RemapPostExposureZero, RemapPostExposureOne,
ShakeHueShift, RemapHueShiftZero, RemapHueShiftOne,
ShakeSaturation, RemapSaturationZero, RemapSaturationOne,
ShakeContrast, RemapContrastZero, RemapContrastOne,
@@ -179,7 +179,7 @@ namespace MoreMountains.FeedbacksForThirdParty
return;
}
MMColorAdjustmentsShakeEvent_URP.Trigger(ShakePostExposure, RemapPostExposureZero, RemapPostExposureOne,
MMColorAdjustmentsShakeEvent_URP.Trigger(this, ShakePostExposure, RemapPostExposureZero, RemapPostExposureOne,
ShakeHueShift, RemapHueShiftZero, RemapHueShiftOne,
ShakeSaturation, RemapSaturationZero, RemapSaturationOne,
ShakeContrast, RemapContrastZero, RemapContrastOne,

View File

@@ -85,7 +85,7 @@ namespace MoreMountains.FeedbacksForThirdParty
}
float intensityMultiplier = ComputeIntensity(feedbacksIntensity, position);
MMLensDistortionShakeEvent_URP.Trigger(Intensity, FeedbackDuration, RemapIntensityZero, RemapIntensityOne, RelativeIntensity, intensityMultiplier,
MMLensDistortionShakeEvent_URP.Trigger(this, Intensity, FeedbackDuration, RemapIntensityZero, RemapIntensityOne, RelativeIntensity, intensityMultiplier,
ChannelData, ResetShakerValuesAfterShake, ResetTargetValuesAfterShake, NormalPlayDirection, ComputedTimescaleMode);
}
@@ -102,7 +102,7 @@ namespace MoreMountains.FeedbacksForThirdParty
return;
}
base.CustomStopFeedback(position, feedbacksIntensity);
MMLensDistortionShakeEvent_URP.Trigger(Intensity, FeedbackDuration, RemapIntensityZero, RemapIntensityOne, RelativeIntensity, stop:true, channelData: ChannelData);
MMLensDistortionShakeEvent_URP.Trigger(this, Intensity, FeedbackDuration, RemapIntensityZero, RemapIntensityOne, RelativeIntensity, stop:true, channelData: ChannelData);
}
/// <summary>
@@ -115,7 +115,7 @@ namespace MoreMountains.FeedbacksForThirdParty
return;
}
MMLensDistortionShakeEvent_URP.Trigger(Intensity, FeedbackDuration, RemapIntensityZero, RemapIntensityOne, RelativeIntensity, restore:true, channelData: ChannelData);
MMLensDistortionShakeEvent_URP.Trigger(this, Intensity, FeedbackDuration, RemapIntensityZero, RemapIntensityOne, RelativeIntensity, restore:true, channelData: ChannelData);
}
/// <summary>

View File

@@ -76,7 +76,7 @@ namespace MoreMountains.FeedbacksForThirdParty
}
float intensityMultiplier = ComputeIntensity(feedbacksIntensity, position);
MMMotionBlurShakeEvent_URP.Trigger(Intensity, FeedbackDuration, RemapIntensityZero, RemapIntensityOne, RelativeIntensity, intensityMultiplier,
MMMotionBlurShakeEvent_URP.Trigger(this, Intensity, FeedbackDuration, RemapIntensityZero, RemapIntensityOne, RelativeIntensity, intensityMultiplier,
ChannelData, ResetShakerValuesAfterShake, ResetTargetValuesAfterShake, NormalPlayDirection, ComputedTimescaleMode);
}
@@ -93,7 +93,7 @@ namespace MoreMountains.FeedbacksForThirdParty
return;
}
base.CustomStopFeedback(position, feedbacksIntensity);
MMMotionBlurShakeEvent_URP.Trigger(Intensity, FeedbackDuration, RemapIntensityZero, RemapIntensityOne, RelativeIntensity, stop: true, channelData: ChannelData);
MMMotionBlurShakeEvent_URP.Trigger(this, Intensity, FeedbackDuration, RemapIntensityZero, RemapIntensityOne, RelativeIntensity, stop: true, channelData: ChannelData);
}
/// <summary>
@@ -106,7 +106,7 @@ namespace MoreMountains.FeedbacksForThirdParty
return;
}
MMMotionBlurShakeEvent_URP.Trigger(Intensity, FeedbackDuration, RemapIntensityZero, RemapIntensityOne, RelativeIntensity, restore: true, channelData: ChannelData);
MMMotionBlurShakeEvent_URP.Trigger(this, Intensity, FeedbackDuration, RemapIntensityZero, RemapIntensityOne, RelativeIntensity, restore: true, channelData: ChannelData);
}
/// <summary>

View File

@@ -79,7 +79,7 @@ namespace MoreMountains.FeedbacksForThirdParty
/// <param name="relativeIntensity"></param>
/// <param name="attenuation"></param>
/// <param name="channel"></param>
public virtual void OnMMChromaticAberrationShakeEvent(AnimationCurve intensity, float duration, float remapMin, float remapMax, bool relativeIntensity = false,
public virtual void OnMMChromaticAberrationShakeEvent(MMF_Feedback source, AnimationCurve intensity, float duration, float remapMin, float remapMax, bool relativeIntensity = false,
float attenuation = 1.0f, MMChannelData channelData = null, bool resetShakerValuesAfterShake = true, bool resetTargetValuesAfterShake = true,
bool forwardDirection = true, TimescaleModes timescaleMode = TimescaleModes.Scaled, bool stop = false, bool restore = false)
{
@@ -123,7 +123,7 @@ namespace MoreMountains.FeedbacksForThirdParty
ForwardDirection = forwardDirection;
}
Play();
Play(source);
}
/// <summary>
@@ -178,15 +178,15 @@ namespace MoreMountains.FeedbacksForThirdParty
static public void Register(Delegate callback) { OnEvent += callback; }
static public void Unregister(Delegate callback) { OnEvent -= callback; }
public delegate void Delegate(AnimationCurve intensity, float duration, float remapMin, float remapMax, bool relativeIntensity = false,
public delegate void Delegate(MMF_Feedback source, AnimationCurve intensity, float duration, float remapMin, float remapMax, bool relativeIntensity = false,
float attenuation = 1.0f, MMChannelData channelData = null, bool resetShakerValuesAfterShake = true, bool resetTargetValuesAfterShake = true,
bool forwardDirection = true, TimescaleModes timescaleMode = TimescaleModes.Scaled, bool stop = false, bool restore = false);
static public void Trigger(AnimationCurve intensity, float duration, float remapMin, float remapMax, bool relativeIntensity = false,
static public void Trigger(MMF_Feedback source, AnimationCurve intensity, float duration, float remapMin, float remapMax, bool relativeIntensity = false,
float attenuation = 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(intensity, duration, remapMin, remapMax, relativeIntensity, attenuation, channelData,
OnEvent?.Invoke(source, intensity, duration, remapMin, remapMax, relativeIntensity, attenuation, channelData,
resetShakerValuesAfterShake, resetTargetValuesAfterShake, forwardDirection, timescaleMode, stop, restore);
}
}

View File

@@ -185,7 +185,7 @@ namespace MoreMountains.FeedbacksForThirdParty
/// <param name="relativeIntensity"></param>
/// <param name="attenuation"></param>
/// <param name="channel"></param>
public virtual void OnMMColorGradingShakeEvent(AnimationCurve shakePostExposure, float remapPostExposureZero, float remapPostExposureOne,
public virtual void OnMMColorGradingShakeEvent(MMF_Feedback source, AnimationCurve shakePostExposure, float remapPostExposureZero, float remapPostExposureOne,
AnimationCurve shakeHueShift, float remapHueShiftZero, float remapHueShiftOne,
AnimationCurve shakeSaturation, float remapSaturationZero, float remapSaturationOne,
AnimationCurve shakeContrast, float remapContrastZero, float remapContrastOne,
@@ -260,7 +260,7 @@ namespace MoreMountains.FeedbacksForThirdParty
ForwardDirection = forwardDirection;
}
Play();
Play(source);
}
/// <summary>
@@ -332,7 +332,7 @@ namespace MoreMountains.FeedbacksForThirdParty
static public void Register(Delegate callback) { OnEvent += callback; }
static public void Unregister(Delegate callback) { OnEvent -= callback; }
public delegate void Delegate(AnimationCurve shakePostExposure, float remapPostExposureZero, float remapPostExposureOne,
public delegate void Delegate(MMF_Feedback source, AnimationCurve shakePostExposure, float remapPostExposureZero, float remapPostExposureOne,
AnimationCurve shakeHueShift, float remapHueShiftZero, float remapHueShiftOne,
AnimationCurve shakeSaturation, float remapSaturationZero, float remapSaturationOne,
AnimationCurve shakeContrast, float remapContrastZero, float remapContrastOne,
@@ -341,7 +341,7 @@ namespace MoreMountains.FeedbacksForThirdParty
float attenuation = 1.0f, MMChannelData channelData = null, bool resetShakerValuesAfterShake = true, bool resetTargetValuesAfterShake = true,
bool forwardDirection = true, TimescaleModes timescaleMode = TimescaleModes.Scaled, bool stop = false, bool restore = false);
static public void Trigger(AnimationCurve shakePostExposure, float remapPostExposureZero, float remapPostExposureOne,
static public void Trigger(MMF_Feedback source, AnimationCurve shakePostExposure, float remapPostExposureZero, float remapPostExposureOne,
AnimationCurve shakeHueShift, float remapHueShiftZero, float remapHueShiftOne,
AnimationCurve shakeSaturation, float remapSaturationZero, float remapSaturationOne,
AnimationCurve shakeContrast, float remapContrastZero, float remapContrastOne,
@@ -350,7 +350,7 @@ namespace MoreMountains.FeedbacksForThirdParty
float attenuation = 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(shakePostExposure, remapPostExposureZero, remapPostExposureOne,
OnEvent?.Invoke(source, shakePostExposure, remapPostExposureZero, remapPostExposureOne,
shakeHueShift, remapHueShiftZero, remapHueShiftOne,
shakeSaturation, remapSaturationZero, remapSaturationOne,
shakeContrast, remapContrastZero, remapContrastOne,

View File

@@ -98,7 +98,7 @@ namespace MoreMountains.FeedbacksForThirdParty
/// <param name="relativeIntensity"></param>
/// <param name="attenuation"></param>
/// <param name="channel"></param>
public virtual void OnMMLensDistortionShakeEvent(AnimationCurve intensity, float duration, float remapMin, float remapMax, bool relativeIntensity = false,
public virtual void OnMMLensDistortionShakeEvent(MMF_Feedback source, AnimationCurve intensity, float duration, float remapMin, float remapMax, bool relativeIntensity = false,
float attenuation = 1.0f, MMChannelData channelData = null, bool resetShakerValuesAfterShake = true, bool resetTargetValuesAfterShake = true,
bool forwardDirection = true, TimescaleModes timescaleMode = TimescaleModes.Scaled, bool stop = false, bool restore = false)
{
@@ -142,7 +142,7 @@ namespace MoreMountains.FeedbacksForThirdParty
ForwardDirection = forwardDirection;
}
Play();
Play(source);
}
/// <summary>
@@ -197,15 +197,15 @@ namespace MoreMountains.FeedbacksForThirdParty
static public void Register(Delegate callback) { OnEvent += callback; }
static public void Unregister(Delegate callback) { OnEvent -= callback; }
public delegate void Delegate(AnimationCurve intensity, float duration, float remapMin, float remapMax, bool relativeIntensity = false,
public delegate void Delegate(MMF_Feedback source, AnimationCurve intensity, float duration, float remapMin, float remapMax, bool relativeIntensity = false,
float attenuation = 1.0f, MMChannelData channelData = null, bool resetShakerValuesAfterShake = true, bool resetTargetValuesAfterShake = true,
bool forwardDirection = true, TimescaleModes timescaleMode = TimescaleModes.Scaled, bool stop = false, bool restore = false);
static public void Trigger(AnimationCurve intensity, float duration, float remapMin, float remapMax, bool relativeIntensity = false,
static public void Trigger(MMF_Feedback source, AnimationCurve intensity, float duration, float remapMin, float remapMax, bool relativeIntensity = false,
float attenuation = 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(intensity, duration, remapMin, remapMax, relativeIntensity, attenuation, channelData,
OnEvent?.Invoke(source, intensity, duration, remapMin, remapMax, relativeIntensity, attenuation, channelData,
resetShakerValuesAfterShake, resetTargetValuesAfterShake, forwardDirection, timescaleMode, stop, restore);
}
}

View File

@@ -81,7 +81,7 @@ namespace MoreMountains.FeedbacksForThirdParty
/// <param name="relativeIntensity"></param>
/// <param name="attenuation"></param>
/// <param name="channel"></param>
public virtual void OnMotionBlurShakeEvent(AnimationCurve intensity, float duration, float remapMin, float remapMax, bool relativeIntensity = false,
public virtual void OnMotionBlurShakeEvent(MMF_Feedback source, AnimationCurve intensity, float duration, float remapMin, float remapMax, bool relativeIntensity = false,
float attenuation = 1.0f, MMChannelData channelData = null, bool resetShakerValuesAfterShake = true, bool resetTargetValuesAfterShake = true,
bool forwardDirection = true, TimescaleModes timescaleMode = TimescaleModes.Scaled, bool stop = false, bool restore = false)
{
@@ -125,7 +125,7 @@ namespace MoreMountains.FeedbacksForThirdParty
ForwardDirection = forwardDirection;
}
Play();
Play(source);
}
/// <summary>
@@ -180,15 +180,15 @@ namespace MoreMountains.FeedbacksForThirdParty
static public void Register(Delegate callback) { OnEvent += callback; }
static public void Unregister(Delegate callback) { OnEvent -= callback; }
public delegate void Delegate(AnimationCurve intensity, float duration, float remapMin, float remapMax, bool relativeIntensity = false,
public delegate void Delegate(MMF_Feedback source, AnimationCurve intensity, float duration, float remapMin, float remapMax, bool relativeIntensity = false,
float attenuation = 1.0f, MMChannelData channelData = null, bool resetShakerValuesAfterShake = true, bool resetTargetValuesAfterShake = true,
bool forwardDirection = true, TimescaleModes timescaleMode = TimescaleModes.Scaled, bool stop = false, bool restore = false);
static public void Trigger(AnimationCurve intensity, float duration, float remapMin, float remapMax, bool relativeIntensity = false,
static public void Trigger(MMF_Feedback source, AnimationCurve intensity, float duration, float remapMin, float remapMax, bool relativeIntensity = false,
float attenuation = 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(intensity, duration, remapMin, remapMax, relativeIntensity, attenuation, channelData,
OnEvent?.Invoke(source, intensity, duration, remapMin, remapMax, relativeIntensity, attenuation, channelData,
resetShakerValuesAfterShake, resetTargetValuesAfterShake, forwardDirection, timescaleMode, stop, restore);
}
}