Added Feel plugin

This commit is contained in:
journaliciouz
2025-12-11 14:49:16 +01:00
parent 97dce4aaf6
commit 1942a531d4
2820 changed files with 257786 additions and 9 deletions

View File

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

View File

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

View File

@@ -0,0 +1,598 @@
using System;
using System.Collections;
using System.Collections.Generic;
using MoreMountains.Tools;
using UnityEngine;
using Random = UnityEngine.Random;
namespace MoreMountains.Feedbacks
{
/// <summary>
/// A base class, meant to be extended, defining a Feedback. A Feedback is an action triggered by a MMFeedbacks, usually in reaction to the player's input or actions,
/// to help communicate both emotion and legibility, improving game feel.
/// To create a new feedback, extend this class and override its Custom methods, declared at the end of this class. You can look at the many examples for reference.
/// </summary>
[AddComponentMenu("")]
[System.Serializable]
[ExecuteAlways]
public abstract class MMFeedback : MonoBehaviour
{
/// whether or not this feedback is active
[Tooltip("whether or not this feedback is active")]
public bool Active = true;
/// the name of this feedback to display in the inspector
[Tooltip("the name of this feedback to display in the inspector")]
public string Label = "MMFeedback";
/// the chance of this feedback happening (in percent : 100 : happens all the time, 0 : never happens, 50 : happens once every two calls, etc)
[Tooltip("the chance of this feedback happening (in percent : 100 : happens all the time, 0 : never happens, 50 : happens once every two calls, etc)")]
[Range(0,100)]
public float Chance = 100f;
/// a number of timing-related values (delay, repeat, etc)
[Tooltip("a number of timing-related values (delay, repeat, etc)")]
public MMFeedbackTiming Timing;
/// the Owner of the feedback, as defined when calling the Initialization method
public GameObject Owner { get; set; }
[HideInInspector]
/// whether or not this feedback is in debug mode
public bool DebugActive = false;
/// set this to true if your feedback should pause the execution of the feedback sequence
public virtual IEnumerator Pause { get { return null; } }
/// if this is true, this feedback will wait until all previous feedbacks have run
public virtual bool HoldingPause { get { return false; } }
/// if this is true, this feedback will wait until all previous feedbacks have run, then run all previous feedbacks again
public virtual bool LooperPause { get { return false; } }
/// if this is true, this feedback will pause and wait until Resume() is called on its parent MMFeedbacks to resume execution
public virtual bool ScriptDrivenPause { get; set; }
/// if this is a positive value, the feedback will auto resume after that duration if it hasn't been resumed via script already
public virtual float ScriptDrivenPauseAutoResume { get; set; }
/// if this is true, this feedback will wait until all previous feedbacks have run, then run all previous feedbacks again
public virtual bool LooperStart { get { return false; } }
/// an overridable color for your feedback, that can be redefined per feedback. White is the only reserved color, and the feedback will revert to
/// normal (light or dark skin) when left to White
#if UNITY_EDITOR
public virtual Color FeedbackColor { get { return Color.white; } }
#endif
/// returns true if this feedback is in cooldown at this time (and thus can't play), false otherwise
public virtual bool InCooldown { get { return (Timing.CooldownDuration > 0f) && (FeedbackTime - _lastPlayTimestamp < Timing.CooldownDuration); } }
/// if this is true, this feedback is currently playing
public virtual bool IsPlaying { get; set; }
/// the time (or unscaled time) based on the selected Timing settings
public float FeedbackTime
{
get
{
if (Timing.TimescaleMode == TimescaleModes.Scaled)
{
return Time.time;
}
else
{
return Time.unscaledTime;
}
}
}
/// the delta time (or unscaled delta time) based on the selected Timing settings
public float FeedbackDeltaTime
{
get
{
if (Timing.TimescaleMode == TimescaleModes.Scaled)
{
return Time.deltaTime;
}
else
{
return Time.unscaledDeltaTime;
}
}
}
/// <summary>
/// The total duration of this feedback :
/// total = initial delay + duration * (number of repeats + delay between repeats)
/// </summary>
public float TotalDuration
{
get
{
if ((Timing != null) && (!Timing.ContributeToTotalDuration))
{
return 0f;
}
float totalTime = 0f;
if (Timing == null)
{
return 0f;
}
if (Timing.InitialDelay != 0)
{
totalTime += ApplyTimeMultiplier(Timing.InitialDelay);
}
totalTime += FeedbackDuration;
if (Timing.NumberOfRepeats > 0)
{
float delayBetweenRepeats = ApplyTimeMultiplier(Timing.DelayBetweenRepeats);
totalTime += (Timing.NumberOfRepeats * FeedbackDuration) + (Timing.NumberOfRepeats * delayBetweenRepeats);
}
return totalTime;
}
}
// the timestamp at which this feedback was last played
public virtual float FeedbackStartedAt { get { return _lastPlayTimestamp; } }
// the perceived duration of the feedback, to be used to display its progress bar, meant to be overridden with meaningful data by each feedback
public virtual float FeedbackDuration { get { return 0f; } set { } }
/// whether or not this feedback is playing right now
public virtual bool FeedbackPlaying { get { return ((FeedbackStartedAt > 0f) && (Time.time - FeedbackStartedAt < FeedbackDuration)); } }
public virtual MMChannelData ChannelData(int channel) => _channelData.Set(MMChannelModes.Int, channel, null);
protected float _lastPlayTimestamp = -1f;
protected int _playsLeft;
protected bool _initialized = false;
protected Coroutine _playCoroutine;
protected Coroutine _infinitePlayCoroutine;
protected Coroutine _sequenceCoroutine;
protected Coroutine _repeatedPlayCoroutine;
protected int _sequenceTrackID = 0;
protected MMFeedbacks _hostMMFeedbacks;
protected float _beatInterval;
protected bool BeatThisFrame = false;
protected int LastBeatIndex = 0;
protected int CurrentSequenceIndex = 0;
protected float LastBeatTimestamp = 0f;
protected bool _isHostMMFeedbacksNotNull;
protected MMChannelData _channelData;
protected virtual void OnEnable()
{
_hostMMFeedbacks = this.gameObject.GetComponent<MMFeedbacks>();
_isHostMMFeedbacksNotNull = _hostMMFeedbacks != null;
}
/// <summary>
/// Initializes the feedback and its timing related variables
/// </summary>
/// <param name="owner"></param>
public virtual void Initialization(GameObject owner)
{
_initialized = true;
Owner = owner;
_playsLeft = Timing.NumberOfRepeats + 1;
_hostMMFeedbacks = this.gameObject.GetComponent<MMFeedbacks>();
_channelData = new MMChannelData(MMChannelModes.Int, 0, null);
SetInitialDelay(Timing.InitialDelay);
SetDelayBetweenRepeats(Timing.DelayBetweenRepeats);
SetSequence(Timing.Sequence);
CustomInitialization(owner);
}
/// <summary>
/// Plays the feedback
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
public virtual void Play(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active)
{
return;
}
if (!_initialized)
{
Debug.LogWarning("The " + this + " feedback is being played without having been initialized. Call Initialization() first.");
}
// we check the cooldown
if (InCooldown)
{
return;
}
if (Timing.InitialDelay > 0f)
{
_playCoroutine = StartCoroutine(PlayCoroutine(position, feedbacksIntensity));
}
else
{
_lastPlayTimestamp = FeedbackTime;
RegularPlay(position, feedbacksIntensity);
}
}
/// <summary>
/// An internal coroutine delaying the initial play of the feedback
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
/// <returns></returns>
protected virtual IEnumerator PlayCoroutine(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (Timing.TimescaleMode == TimescaleModes.Scaled)
{
yield return MMFeedbacksCoroutine.WaitFor(Timing.InitialDelay);
}
else
{
yield return MMFeedbacksCoroutine.WaitForUnscaled(Timing.InitialDelay);
}
_lastPlayTimestamp = FeedbackTime;
RegularPlay(position, feedbacksIntensity);
}
/// <summary>
/// Triggers delaying coroutines if needed
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected virtual void RegularPlay(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (Chance == 0f)
{
return;
}
if (Chance != 100f)
{
// determine the odds
float random = Random.Range(0f, 100f);
if (random > Chance)
{
return;
}
}
if (Timing.UseIntensityInterval)
{
if ((feedbacksIntensity < Timing.IntensityIntervalMin) || (feedbacksIntensity >= Timing.IntensityIntervalMax))
{
return;
}
}
if (Timing.RepeatForever)
{
_infinitePlayCoroutine = StartCoroutine(InfinitePlay(position, feedbacksIntensity));
return;
}
if (Timing.NumberOfRepeats > 0)
{
_repeatedPlayCoroutine = StartCoroutine(RepeatedPlay(position, feedbacksIntensity));
return;
}
if (Timing.Sequence == null)
{
CustomPlayFeedback(position, feedbacksIntensity);
}
else
{
_sequenceCoroutine = StartCoroutine(SequenceCoroutine(position, feedbacksIntensity));
}
}
/// <summary>
/// Internal coroutine used for repeated play without end
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
/// <returns></returns>
protected virtual IEnumerator InfinitePlay(Vector3 position, float feedbacksIntensity = 1.0f)
{
while (true)
{
_lastPlayTimestamp = FeedbackTime;
if (Timing.Sequence == null)
{
CustomPlayFeedback(position, feedbacksIntensity);
if (Timing.TimescaleMode == TimescaleModes.Scaled)
{
yield return MMFeedbacksCoroutine.WaitFor(Timing.DelayBetweenRepeats);
}
else
{
yield return MMFeedbacksCoroutine.WaitForUnscaled(Timing.DelayBetweenRepeats);
}
}
else
{
_sequenceCoroutine = StartCoroutine(SequenceCoroutine(position, feedbacksIntensity));
float delay = ApplyTimeMultiplier(Timing.DelayBetweenRepeats) + Timing.Sequence.Length;
if (Timing.TimescaleMode == TimescaleModes.Scaled)
{
yield return MMFeedbacksCoroutine.WaitFor(delay);
}
else
{
yield return MMFeedbacksCoroutine.WaitForUnscaled(delay);
}
}
}
}
/// <summary>
/// Internal coroutine used for repeated play
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
/// <returns></returns>
protected virtual IEnumerator RepeatedPlay(Vector3 position, float feedbacksIntensity = 1.0f)
{
while (_playsLeft > 0)
{
_lastPlayTimestamp = FeedbackTime;
_playsLeft--;
if (Timing.Sequence == null)
{
CustomPlayFeedback(position, feedbacksIntensity);
if (Timing.TimescaleMode == TimescaleModes.Scaled)
{
yield return MMFeedbacksCoroutine.WaitFor(Timing.DelayBetweenRepeats);
}
else
{
yield return MMFeedbacksCoroutine.WaitForUnscaled(Timing.DelayBetweenRepeats);
}
}
else
{
_sequenceCoroutine = StartCoroutine(SequenceCoroutine(position, feedbacksIntensity));
float delay = ApplyTimeMultiplier(Timing.DelayBetweenRepeats) + Timing.Sequence.Length;
if (Timing.TimescaleMode == TimescaleModes.Scaled)
{
yield return MMFeedbacksCoroutine.WaitFor(delay);
}
else
{
yield return MMFeedbacksCoroutine.WaitForUnscaled(delay);
}
}
}
_playsLeft = Timing.NumberOfRepeats + 1;
}
/// <summary>
/// A coroutine used to play this feedback on a sequence
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
/// <returns></returns>
protected virtual IEnumerator SequenceCoroutine(Vector3 position, float feedbacksIntensity = 1.0f)
{
yield return null;
float timeStartedAt = FeedbackTime;
float lastFrame = FeedbackTime;
BeatThisFrame = false;
LastBeatIndex = 0;
CurrentSequenceIndex = 0;
LastBeatTimestamp = 0f;
if (Timing.Quantized)
{
while (CurrentSequenceIndex < Timing.Sequence.QuantizedSequence[0].Line.Count)
{
_beatInterval = 60f / Timing.TargetBPM;
if ((FeedbackTime - LastBeatTimestamp >= _beatInterval) || (LastBeatTimestamp == 0f))
{
BeatThisFrame = true;
LastBeatIndex = CurrentSequenceIndex;
LastBeatTimestamp = FeedbackTime;
for (int i = 0; i < Timing.Sequence.SequenceTracks.Count; i++)
{
if (Timing.Sequence.QuantizedSequence[i].Line[CurrentSequenceIndex].ID == Timing.TrackID)
{
CustomPlayFeedback(position, feedbacksIntensity);
}
}
CurrentSequenceIndex++;
}
yield return null;
}
}
else
{
while (FeedbackTime - timeStartedAt < Timing.Sequence.Length)
{
foreach (MMSequenceNote item in Timing.Sequence.OriginalSequence.Line)
{
if ((item.ID == Timing.TrackID) && (item.Timestamp >= lastFrame) && (item.Timestamp <= FeedbackTime - timeStartedAt))
{
CustomPlayFeedback(position, feedbacksIntensity);
}
}
lastFrame = FeedbackTime - timeStartedAt;
yield return null;
}
}
}
/// <summary>
/// Stops all feedbacks from playing. Will stop repeating feedbacks, and call custom stop implementations
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
public virtual void Stop(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (_playCoroutine != null) { StopCoroutine(_playCoroutine); }
if (_infinitePlayCoroutine != null) { StopCoroutine(_infinitePlayCoroutine); }
if (_repeatedPlayCoroutine != null) { StopCoroutine(_repeatedPlayCoroutine); }
if (_sequenceCoroutine != null) { StopCoroutine(_sequenceCoroutine); }
_lastPlayTimestamp = 0f;
_playsLeft = Timing.NumberOfRepeats + 1;
if (Timing.InterruptsOnStop)
{
CustomStopFeedback(position, feedbacksIntensity);
}
}
/// <summary>
/// Calls this feedback's custom reset
/// </summary>
public virtual void ResetFeedback()
{
_playsLeft = Timing.NumberOfRepeats + 1;
CustomReset();
}
/// <summary>
/// Use this method to change this feedback's sequence at runtime
/// </summary>
/// <param name="newSequence"></param>
public virtual void SetSequence(MMSequence newSequence)
{
Timing.Sequence = newSequence;
if (Timing.Sequence != null)
{
for (int i = 0; i < Timing.Sequence.SequenceTracks.Count; i++)
{
if (Timing.Sequence.SequenceTracks[i].ID == Timing.TrackID)
{
_sequenceTrackID = i;
}
}
}
}
/// <summary>
/// Use this method to specify a new delay between repeats at runtime
/// </summary>
/// <param name="delay"></param>
public virtual void SetDelayBetweenRepeats(float delay)
{
Timing.DelayBetweenRepeats = delay;
}
/// <summary>
/// Use this method to specify a new initial delay at runtime
/// </summary>
/// <param name="delay"></param>
public virtual void SetInitialDelay(float delay)
{
Timing.InitialDelay = delay;
}
/// <summary>
/// Returns a new value of the normalized time based on the current play direction of this feedback
/// </summary>
/// <param name="normalizedTime"></param>
/// <returns></returns>
protected virtual float ApplyDirection(float normalizedTime)
{
return NormalPlayDirection ? normalizedTime : 1 - normalizedTime;
}
/// <summary>
/// Returns true if this feedback should play normally, or false if it should play in rewind
/// </summary>
public virtual bool NormalPlayDirection
{
get
{
switch (Timing.PlayDirection)
{
case MMFeedbackTiming.PlayDirections.FollowMMFeedbacksDirection:
return (_hostMMFeedbacks.Direction == MMFeedbacks.Directions.TopToBottom);
case MMFeedbackTiming.PlayDirections.AlwaysNormal:
return true;
case MMFeedbackTiming.PlayDirections.AlwaysRewind:
return false;
case MMFeedbackTiming.PlayDirections.OppositeMMFeedbacksDirection:
return !(_hostMMFeedbacks.Direction == MMFeedbacks.Directions.TopToBottom);
}
return true;
}
}
/// <summary>
/// Returns true if this feedback should play in the current parent MMFeedbacks direction, according to its MMFeedbacksDirectionCondition setting
/// </summary>
public virtual bool ShouldPlayInThisSequenceDirection
{
get
{
switch (Timing.MMFeedbacksDirectionCondition)
{
case MMFeedbackTiming.MMFeedbacksDirectionConditions.Always:
return true;
case MMFeedbackTiming.MMFeedbacksDirectionConditions.OnlyWhenForwards:
return (_hostMMFeedbacks.Direction == MMFeedbacks.Directions.TopToBottom);
case MMFeedbackTiming.MMFeedbacksDirectionConditions.OnlyWhenBackwards:
return (_hostMMFeedbacks.Direction == MMFeedbacks.Directions.BottomToTop);
}
return true;
}
}
/// <summary>
/// Returns the t value at which to evaluate a curve at the end of this feedback's play time
/// </summary>
protected virtual float FinalNormalizedTime
{
get
{
return NormalPlayDirection ? 1f : 0f;
}
}
/// <summary>
/// Applies the host MMFeedbacks' time multiplier to this feedback
/// </summary>
/// <param name="duration"></param>
/// <returns></returns>
protected virtual float ApplyTimeMultiplier(float duration)
{
if (_isHostMMFeedbacksNotNull)
{
return _hostMMFeedbacks.ApplyTimeMultiplier(duration);
}
return duration;
}
/// <summary>
/// This method describes all custom initialization processes the feedback requires, in addition to the main Initialization method
/// </summary>
/// <param name="owner"></param>
protected virtual void CustomInitialization(GameObject owner) { }
/// <summary>
/// This method describes what happens when the feedback gets played
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected abstract void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f);
/// <summary>
/// This method describes what happens when the feedback gets stopped
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected virtual void CustomStopFeedback(Vector3 position, float feedbacksIntensity = 1.0f) { }
/// <summary>
/// This method describes what happens when the feedback gets reset
/// </summary>
protected virtual void CustomReset() { }
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 1b1d3a32ffe67b94187272c15134cae5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Core/Legacy/MMFeedback.cs
uploadId: 830868

View File

@@ -0,0 +1,925 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using MoreMountains.Feedbacks;
using System.Linq;
using MoreMountains.Tools;
using UnityEditor.Experimental;
using UnityEngine.Events;
using Random = UnityEngine.Random;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace MoreMountains.Feedbacks
{
/// <summary>
/// A collection of MMFeedback, meant to be played altogether.
/// This class provides a custom inspector to add and customize feedbacks, and public methods to trigger them, stop them, etc.
/// You can either use it on its own, or bind it from another class and trigger it from there.
/// </summary>
[AddComponentMenu("")]
public class MMFeedbacks : MonoBehaviour
{
/// the possible directions MMFeedbacks can be played
public enum Directions { TopToBottom, BottomToTop }
/// the possible SafeModes (will perform checks to make sure no serialization error has damaged them)
/// - nope : no safety
/// - editor only : performs checks on enable
/// - runtime only : performs checks on Awake
/// - full : performs both editor and runtime checks, recommended setting
public enum SafeModes { Nope, EditorOnly, RuntimeOnly, Full }
/// a list of MMFeedback to trigger
public List<MMFeedback> Feedbacks = new List<MMFeedback>();
/// the possible initialization modes. If you use Script, you'll have to initialize manually by calling the Initialization method and passing it an owner
/// Otherwise, you can have this component initialize itself at Awake or Start, and in this case the owner will be the MMFeedbacks itself
public enum InitializationModes { Script, Awake, Start, OnEnable }
/// the chosen initialization mode
[Tooltip("the chosen initialization modes. If you use Script, you'll have to initialize manually by calling the " +
"Initialization method and passing it an owner. Otherwise, you can have this component initialize " +
"itself at Awake or Start, and in this case the owner will be the MMFeedbacks itself")]
public InitializationModes InitializationMode = InitializationModes.Start;
/// if you set this to true, the system will make changes to ensure that initialization always happens before play
[Tooltip("if you set this to true, the system will make changes to ensure that initialization always happens before play")]
public bool AutoInitialization = true;
/// the selected safe mode
[Tooltip("the selected safe mode")]
public SafeModes SafeMode = SafeModes.Full;
/// the selected direction
[Tooltip("the selected direction these feedbacks should play in")]
public Directions Direction = Directions.TopToBottom;
/// whether or not this MMFeedbacks should invert its direction when all feedbacks have played
[Tooltip("whether or not this MMFeedbacks should invert its direction when all feedbacks have played")]
public bool AutoChangeDirectionOnEnd = false;
/// whether or not to play this feedbacks automatically on Start
[Tooltip("whether or not to play this feedbacks automatically on Start")]
public bool AutoPlayOnStart = false;
/// whether or not to play this feedbacks automatically on Enable
[Tooltip("whether or not to play this feedbacks automatically on Enable")]
public bool AutoPlayOnEnable = false;
/// if this is true, all feedbacks within that player will work on the specified ForcedTimescaleMode, regardless of their individual settings
[Tooltip("if this is true, all feedbacks within that player will work on the specified ForcedTimescaleMode, regardless of their individual settings")]
public bool ForceTimescaleMode = false;
/// the time scale mode all feedbacks on this player should work on, if ForceTimescaleMode is true
[Tooltip("the time scale mode all feedbacks on this player should work on, if ForceTimescaleMode is true")]
[MMFCondition("ForceTimescaleMode", true)]
public TimescaleModes ForcedTimescaleMode = TimescaleModes.Unscaled;
/// a time multiplier that will be applied to all feedback durations (initial delay, duration, delay between repeats...)
[Tooltip("a time multiplier that will be applied to all feedback durations (initial delay, duration, delay between repeats...)")]
public float DurationMultiplier = 1f;
/// a multiplier to apply to all timescale operations (1: normal, less than 1: slower operations, higher than 1: faster operations)
[Tooltip("a multiplier to apply to all timescale operations (1: normal, less than 1: slower operations, higher than 1: faster operations)")]
public float TimescaleMultiplier = 1f;
/// if this is true, will expose a RandomDurationMultiplier. The final duration of each feedback will be : their base duration * DurationMultiplier * a random value between RandomDurationMultiplier.x and RandomDurationMultiplier.y
[Tooltip("if this is true, will expose a RandomDurationMultiplier. The final duration of each feedback will be : their base duration * DurationMultiplier * a random value between RandomDurationMultiplier.x and RandomDurationMultiplier.y")]
public bool RandomizeDuration = false;
/// if RandomizeDuration is true, the min (x) and max (y) values for the random duration multiplier
[Tooltip("if RandomizeDuration is true, the min (x) and max (y) values for the random duration multiplier")]
[MMCondition("RandomizeDuration", true)]
public Vector2 RandomDurationMultiplier = new Vector2(0.5f, 1.5f);
/// if this is true, more editor-only, detailed info will be displayed per feedback in the duration slot
[Tooltip("if this is true, more editor-only, detailed info will be displayed per feedback in the duration slot")]
public bool DisplayFullDurationDetails = false;
/// the timescale at which the player itself will operate. This notably impacts sequencing and pauses duration evaluation.
[Tooltip("the timescale at which the player itself will operate. This notably impacts sequencing and pauses duration evaluation.")]
public TimescaleModes PlayerTimescaleMode = TimescaleModes.Scaled;
/// if this is true, this feedback will only play if its distance to RangeCenter is lower or equal to RangeDistance
[Tooltip("if this is true, this feedback will only play if its distance to RangeCenter is lower or equal to RangeDistance")]
public bool OnlyPlayIfWithinRange = false;
/// when in OnlyPlayIfWithinRange mode, the transform to consider as the center of the range
[Tooltip("when in OnlyPlayIfWithinRange mode, the transform to consider as the center of the range")]
public Transform RangeCenter;
/// when in OnlyPlayIfWithinRange mode, the distance to the center within which the feedback will play
[Tooltip("when in OnlyPlayIfWithinRange mode, the distance to the center within which the feedback will play")]
public float RangeDistance = 5f;
/// when in OnlyPlayIfWithinRange mode, whether or not to modify the intensity of feedbacks based on the RangeFallOff curve
[Tooltip("when in OnlyPlayIfWithinRange mode, whether or not to modify the intensity of feedbacks based on the RangeFallOff curve")]
public bool UseRangeFalloff = false;
/// the animation curve to use to define falloff (on the x 0 represents the range center, 1 represents the max distance to it)
[Tooltip("the animation curve to use to define falloff (on the x 0 represents the range center, 1 represents the max distance to it)")]
[MMFCondition("UseRangeFalloff", true)]
public AnimationCurve RangeFalloff = new AnimationCurve(new Keyframe(0f, 1f), new Keyframe(1f, 0f));
/// the values to remap the falloff curve's y axis' 0 and 1
[Tooltip("the values to remap the falloff curve's y axis' 0 and 1")]
[MMFVector("Zero","One")]
public Vector2 RemapRangeFalloff = new Vector2(0f, 1f);
/// whether or not to ignore MMSetFeedbackRangeCenterEvent, used to set the RangeCenter from anywhere
[Tooltip("whether or not to ignore MMSetFeedbackRangeCenterEvent, used to set the RangeCenter from anywhere")]
public bool IgnoreRangeEvents = false;
/// a duration, in seconds, during which triggering a new play of this MMFeedbacks after it's been played once will be impossible
[Tooltip("a duration, in seconds, during which triggering a new play of this MMFeedbacks after it's been played once will be impossible")]
public float CooldownDuration = 0f;
/// a duration, in seconds, to delay the start of this MMFeedbacks' contents play
[Tooltip("a duration, in seconds, to delay the start of this MMFeedbacks' contents play")]
public float InitialDelay = 0f;
/// whether this player can be played or not, useful to temporarily prevent play from another class, for example
[Tooltip("whether this player can be played or not, useful to temporarily prevent play from another class, for example")]
public bool CanPlay = true;
/// if this is true, you'll be able to trigger a new Play while this feedback is already playing, otherwise you won't be able to
[Tooltip("if this is true, you'll be able to trigger a new Play while this feedback is already playing, otherwise you won't be able to")]
public bool CanPlayWhileAlreadyPlaying = true;
/// the chance of this sequence happening (in percent : 100 : happens all the time, 0 : never happens, 50 : happens once every two calls, etc)
[Tooltip("the chance of this sequence happening (in percent : 100 : happens all the time, 0 : never happens, 50 : happens once every two calls, etc)")]
[Range(0,100)]
public float ChanceToPlay = 100f;
/// the intensity at which to play this feedback. That value will be used by most feedbacks to tune their amplitude. 1 is normal, 0.5 is half power, 0 is no effect.
/// Note that what this value controls depends from feedback to feedback, don't hesitate to check the code to see what it does exactly.
[Tooltip("the intensity at which to play this feedback. That value will be used by most feedbacks to tune their amplitude. 1 is normal, 0.5 is half power, 0 is no effect." +
"Note that what this value controls depends from feedback to feedback, don't hesitate to check the code to see what it does exactly.")]
public float FeedbacksIntensity = 1f;
/// a number of UnityEvents that can be triggered at the various stages of this MMFeedbacks
[Tooltip("a number of UnityEvents that can be triggered at the various stages of this MMFeedbacks")]
public MMFeedbacksEvents Events;
/// a global switch used to turn all feedbacks on or off globally
[Tooltip("a global switch used to turn all feedbacks on or off globally")]
public static bool GlobalMMFeedbacksActive = true;
[HideInInspector]
/// whether or not this MMFeedbacks is in debug mode
public bool DebugActive = false;
/// whether or not this MMFeedbacks is playing right now - meaning it hasn't been stopped yet.
/// if you don't stop your MMFeedbacks it'll remain true of course
public bool IsPlaying { get; protected set; }
/// if this MMFeedbacks is playing the time since it started playing
public virtual float ElapsedTime => IsPlaying ? GetTime() - _lastStartAt : 0f;
/// the amount of times this MMFeedbacks has been played
public int TimesPlayed { get; protected set; }
/// whether or not the execution of this MMFeedbacks' sequence is being prevented and waiting for a Resume() call
public bool InScriptDrivenPause;
/// true if this MMFeedbacks contains at least one loop
public bool ContainsLoop { get; set; }
/// true if this feedback should change play direction next time it's played
public bool ShouldChangeDirectionOnNextPlay { get; set; }
/// true if this player is forcing unscaled mode
public bool ForcingUnscaledTimescaleMode { get { return (ForceTimescaleMode && ForcedTimescaleMode == TimescaleModes.Unscaled); } }
/// The total duration (in seconds) of all the active feedbacks in this MMFeedbacks
public virtual float TotalDuration
{
get
{
float total = 0f;
foreach (MMFeedback feedback in Feedbacks)
{
if ((feedback != null) && (feedback.Active))
{
if (total < feedback.TotalDuration)
{
total = feedback.TotalDuration;
}
}
}
return ComputedInitialDelay + total;
}
}
public virtual float GetTime() { return (PlayerTimescaleMode == TimescaleModes.Scaled) ? Time.time : Time.unscaledTime; }
public virtual float GetDeltaTime() { return (PlayerTimescaleMode == TimescaleModes.Scaled) ? Time.deltaTime : Time.unscaledDeltaTime; }
public virtual float ComputedInitialDelay => ApplyTimeMultiplier(InitialDelay);
protected float _startTime = 0f;
protected float _holdingMax = 0f;
protected float _lastStartAt = -float.MaxValue;
protected int _lastStartFrame = -1;
protected bool _pauseFound = false;
protected float _totalDuration = 0f;
protected bool _shouldStop = false;
protected const float _smallValue = 0.001f;
protected float _randomDurationMultiplier = 1f;
protected float _lastOnEnableFrame = -1;
#region INITIALIZATION
/// <summary>
/// On Awake we initialize our feedbacks if we're in auto mode
/// </summary>
protected virtual void Awake()
{
// if our MMFeedbacks is in AutoPlayOnEnable mode, we add a little helper to it that will re-enable it if needed if the parent game object gets turned off and on again
if (AutoPlayOnEnable)
{
MMFeedbacksEnabler enabler = GetComponent<MMFeedbacksEnabler>();
if (enabler == null)
{
enabler = this.gameObject.AddComponent<MMFeedbacksEnabler>();
}
enabler.TargetMMFeedbacks = this;
}
if ((InitializationMode == InitializationModes.Awake) && (Application.isPlaying))
{
Initialization(this.gameObject);
}
CheckForLoops();
}
/// <summary>
/// On Start we initialize our feedbacks if we're in auto mode
/// </summary>
protected virtual void Start()
{
if ((InitializationMode == InitializationModes.Start) && (Application.isPlaying))
{
Initialization(this.gameObject);
}
if (AutoPlayOnStart && Application.isPlaying)
{
PlayFeedbacks();
}
CheckForLoops();
}
/// <summary>
/// On Enable we initialize our feedbacks if we're in auto mode
/// </summary>
protected virtual void OnEnable()
{
if (AutoPlayOnEnable && Application.isPlaying)
{
PlayFeedbacks();
}
}
/// <summary>
/// Initializes the MMFeedbacks, setting this MMFeedbacks as the owner
/// </summary>
public virtual void Initialization(bool forceInitIfPlaying = false)
{
Initialization(this.gameObject);
}
/// <summary>
/// A public method to initialize the feedback, specifying an owner that will be used as the reference for position and hierarchy by feedbacks
/// </summary>
/// <param name="owner"></param>
/// <param name="feedbacksOwner"></param>
public virtual void Initialization(GameObject owner)
{
if ((SafeMode == MMFeedbacks.SafeModes.RuntimeOnly) || (SafeMode == MMFeedbacks.SafeModes.Full))
{
AutoRepair();
}
IsPlaying = false;
TimesPlayed = 0;
_lastStartAt = -float.MaxValue;
for (int i = 0; i < Feedbacks.Count; i++)
{
if (Feedbacks[i] != null)
{
Feedbacks[i].Initialization(owner);
}
}
}
#endregion
#region PLAY
/// <summary>
/// Plays all feedbacks using the MMFeedbacks' position as reference, and no attenuation
/// </summary>
public virtual void PlayFeedbacks()
{
PlayFeedbacksInternal(this.transform.position, FeedbacksIntensity);
}
/// <summary>
/// Plays all feedbacks and awaits until completion
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
/// <param name="forceChangeDirection"></param>
public virtual async System.Threading.Tasks.Task PlayFeedbacksTask(Vector3 position, float feedbacksIntensity = 1.0f, bool forceChangeDirection = false)
{
PlayFeedbacks(position, feedbacksIntensity, forceChangeDirection);
while (IsPlaying)
{
await System.Threading.Tasks.Task.Yield();
}
}
/// <summary>
/// Plays all feedbacks and awaits until completion
/// </summary>
public virtual async System.Threading.Tasks.Task PlayFeedbacksTask()
{
PlayFeedbacks();
while (IsPlaying)
{
await System.Threading.Tasks.Task.Yield();
}
}
/// <summary>
/// Plays all feedbacks, specifying a position and intensity. The position may be used by each Feedback and taken into account to spark a particle or play a sound for example.
/// The feedbacks intensity is a factor that can be used by each Feedback to lower its intensity, usually you'll want to define that attenuation based on time or distance (using a lower
/// intensity value for feedbacks happening further away from the Player).
/// Additionally you can force the feedback to play in reverse, ignoring its current condition
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksOwner"></param>
/// <param name="feedbacksIntensity"></param>
public virtual void PlayFeedbacks(Vector3 position, float feedbacksIntensity = 1.0f, bool forceChangeDirection = false)
{
PlayFeedbacksInternal(position, feedbacksIntensity, forceChangeDirection);
}
/// <summary>
/// Changes the player's direction (inverting it - top to bottom becomes bottom to top, top to bottom becomes bottom to top) then plays all feedbacks using the MMFeedbacks' position as reference, and no attenuation
/// </summary>
public virtual void PlayFeedbacksInReverse()
{
PlayFeedbacksInternal(this.transform.position, FeedbacksIntensity, true);
}
/// <summary>
/// Changes the player's direction (inverting it - top to bottom becomes bottom to top, top to bottom becomes bottom to top) then plays all feedbacks
/// </summary>
public virtual void PlayFeedbacksInReverse(Vector3 position, float feedbacksIntensity = 1.0f, bool forceChangeDirection = false)
{
PlayFeedbacksInternal(position, feedbacksIntensity, forceChangeDirection);
}
/// <summary>
/// Plays all feedbacks in the sequence, but only if this MMFeedbacks is playing in reverse order
/// </summary>
public virtual void PlayFeedbacksOnlyIfReversed()
{
if ( (Direction == Directions.BottomToTop && !ShouldChangeDirectionOnNextPlay)
|| ((Direction == Directions.TopToBottom) && ShouldChangeDirectionOnNextPlay) )
{
PlayFeedbacks();
}
}
/// <summary>
/// Plays all feedbacks in the sequence, but only if this MMFeedbacks is playing in reverse order
/// </summary>
public virtual void PlayFeedbacksOnlyIfReversed(Vector3 position, float feedbacksIntensity = 1.0f, bool forceChangeDirection = false)
{
if ( (Direction == Directions.BottomToTop && !ShouldChangeDirectionOnNextPlay)
|| ((Direction == Directions.TopToBottom) && ShouldChangeDirectionOnNextPlay) )
{
PlayFeedbacks(position, feedbacksIntensity, forceChangeDirection);
}
}
/// <summary>
/// Plays all feedbacks in the sequence, but only if this MMFeedbacks is playing in normal order
/// </summary>
public virtual void PlayFeedbacksOnlyIfNormalDirection()
{
if (Direction == Directions.TopToBottom)
{
PlayFeedbacks();
}
}
/// <summary>
/// Plays all feedbacks in the sequence, but only if this MMFeedbacks is playing in normal order
/// </summary>
public virtual void PlayFeedbacksOnlyIfNormalDirection(Vector3 position, float feedbacksIntensity = 1.0f, bool forceChangeDirection = false)
{
if (Direction == Directions.TopToBottom)
{
PlayFeedbacks(position, feedbacksIntensity, forceChangeDirection);
}
}
/// <summary>
/// A public coroutine you can call externally when you want to yield in a coroutine of yours until the MMFeedbacks has stopped playing
/// typically : yield return myFeedback.PlayFeedbacksCoroutine(this.transform.position, 1.0f, false);
/// </summary>
/// <param name="position">The position at which the MMFeedbacks should play</param>
/// <param name="feedbacksIntensity">The intensity of the feedback</param>
/// <param name="forceChangeDirection">Whether or not the MMFeedbacks should play in reverse or not</param>
/// <returns></returns>
public virtual IEnumerator PlayFeedbacksCoroutine(Vector3 position, float feedbacksIntensity = 1.0f, bool forceChangeDirection = false)
{
PlayFeedbacks(position, feedbacksIntensity, forceChangeDirection);
while (IsPlaying)
{
yield return null;
}
}
#endregion
#region SEQUENCE
/// <summary>
/// An internal method used to play feedbacks, shouldn't be called externally
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected virtual void PlayFeedbacksInternal(Vector3 position, float feedbacksIntensity, bool forceChangeDirection = false)
{
if (!CanPlay)
{
return;
}
if (IsPlaying && !CanPlayWhileAlreadyPlaying)
{
return;
}
if (!EvaluateChance())
{
return;
}
// if we have a cooldown we prevent execution if needed
if (CooldownDuration > 0f)
{
if (GetTime() - _lastStartAt < CooldownDuration)
{
return;
}
}
// if all MMFeedbacks are disabled globally, we stop and don't play
if (!GlobalMMFeedbacksActive)
{
return;
}
if (!this.gameObject.activeInHierarchy)
{
return;
}
if (ShouldChangeDirectionOnNextPlay)
{
ChangeDirection();
ShouldChangeDirectionOnNextPlay = false;
}
if (forceChangeDirection)
{
Direction = (Direction == Directions.BottomToTop) ? Directions.TopToBottom : Directions.BottomToTop;
}
ResetFeedbacks();
this.enabled = true;
TimesPlayed++;
IsPlaying = true;
_startTime = GetTime();
_lastStartAt = _startTime;
_totalDuration = TotalDuration;
CheckForPauses();
if (ComputedInitialDelay > 0f)
{
StartCoroutine(HandleInitialDelayCo(position, feedbacksIntensity, forceChangeDirection));
}
else
{
PreparePlay(position, feedbacksIntensity, forceChangeDirection);
}
}
protected virtual void PreparePlay(Vector3 position, float feedbacksIntensity, bool forceChangeDirection = false)
{
Events.TriggerOnPlay(this);
_holdingMax = 0f;
CheckForPauses();
if (!_pauseFound)
{
PlayAllFeedbacks(position, feedbacksIntensity, forceChangeDirection);
}
else
{
// if at least one pause was found
StartCoroutine(PausedFeedbacksCo(position, feedbacksIntensity));
}
}
protected virtual void CheckForPauses()
{
_pauseFound = false;
for (int i = 0; i < Feedbacks.Count; i++)
{
if (Feedbacks[i] != null)
{
if ((Feedbacks[i].Pause != null) && (Feedbacks[i].Active) && (Feedbacks[i].ShouldPlayInThisSequenceDirection))
{
_pauseFound = true;
}
if ((Feedbacks[i].HoldingPause == true) && (Feedbacks[i].Active) && (Feedbacks[i].ShouldPlayInThisSequenceDirection))
{
_pauseFound = true;
}
}
}
}
protected virtual void PlayAllFeedbacks(Vector3 position, float feedbacksIntensity, bool forceChangeDirection = false)
{
// if no pause was found, we just play all feedbacks at once
for (int i = 0; i < Feedbacks.Count; i++)
{
if (FeedbackCanPlay(Feedbacks[i]))
{
Feedbacks[i].Play(position, feedbacksIntensity);
}
}
}
protected virtual IEnumerator HandleInitialDelayCo(Vector3 position, float feedbacksIntensity, bool forceChangeDirection = false)
{
IsPlaying = true;
yield return MMFeedbacksCoroutine.WaitFor(ComputedInitialDelay);
PreparePlay(position, feedbacksIntensity, forceChangeDirection);
}
protected virtual void Update()
{
if (_shouldStop)
{
if (HasFeedbackStillPlaying())
{
return;
}
IsPlaying = false;
Events.TriggerOnComplete(this);
ApplyAutoChangeDirection();
this.enabled = false;
_shouldStop = false;
}
if (IsPlaying)
{
if (!_pauseFound)
{
if (GetTime() - _startTime > _totalDuration)
{
_shouldStop = true;
}
}
}
else
{
this.enabled = false;
}
}
/// <summary>
/// Returns true if feedbacks are still playing
/// </summary>
/// <returns></returns>
public virtual bool HasFeedbackStillPlaying()
{
int count = Feedbacks.Count;
for (int i = 0; i < count; i++)
{
if ((Feedbacks[i] != null) && (Feedbacks[i].IsPlaying))
{
return true;
}
}
return false;
}
/// <summary>
/// A coroutine used to handle the sequence of feedbacks if pauses are involved
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
/// <returns></returns>
protected virtual IEnumerator PausedFeedbacksCo(Vector3 position, float feedbacksIntensity)
{
yield return null;
}
#endregion
#region STOP
/// <summary>
/// Stops all further feedbacks from playing, without stopping individual feedbacks
/// </summary>
public virtual void StopFeedbacks()
{
StopFeedbacks(true);
}
/// <summary>
/// Stops all feedbacks from playing, with an option to also stop individual feedbacks
/// </summary>
public virtual void StopFeedbacks(bool stopAllFeedbacks = true)
{
StopFeedbacks(this.transform.position, 1.0f, stopAllFeedbacks);
}
/// <summary>
/// Stops all feedbacks from playing, specifying a position and intensity that can be used by the Feedbacks
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
public virtual void StopFeedbacks(Vector3 position, float feedbacksIntensity = 1.0f, bool stopAllFeedbacks = true)
{
if (stopAllFeedbacks)
{
for (int i = 0; i < Feedbacks.Count; i++)
{
if (Feedbacks[i] != null)
{
Feedbacks[i].Stop(position, feedbacksIntensity);
}
}
}
IsPlaying = false;
StopAllCoroutines();
}
#endregion
#region CONTROLS
/// <summary>
/// Calls each feedback's Reset method if they've defined one. An example of that can be resetting the initial color of a flickering renderer.
/// </summary>
public virtual void ResetFeedbacks()
{
for (int i = 0; i < Feedbacks.Count; i++)
{
if ((Feedbacks[i] != null) && (Feedbacks[i].Active))
{
Feedbacks[i].ResetFeedback();
}
}
IsPlaying = false;
}
/// <summary>
/// Changes the direction of this MMFeedbacks
/// </summary>
public virtual void ChangeDirection()
{
Events.TriggerOnChangeDirection(this);
Direction = (Direction == Directions.BottomToTop) ? Directions.TopToBottom : Directions.BottomToTop;
}
/// <summary>
/// Use this method to authorize or prevent this player from being played
/// </summary>
/// <param name="newState"></param>
public virtual void SetCanPlay(bool newState)
{
CanPlay = newState;
}
/// <summary>
/// Pauses execution of a sequence, which can then be resumed by calling ResumeFeedbacks()
/// </summary>
public virtual void PauseFeedbacks()
{
Events.TriggerOnPause(this);
InScriptDrivenPause = true;
}
/// <summary>
/// Resumes execution of a sequence if a script driven pause is in progress
/// </summary>
public virtual void ResumeFeedbacks()
{
Events.TriggerOnResume(this);
InScriptDrivenPause = false;
}
#endregion
#region MODIFICATION
public virtual MMFeedback AddFeedback(System.Type feedbackType, bool add = true)
{
MMFeedback newFeedback;
#if UNITY_EDITOR
if (!Application.isPlaying)
{
newFeedback = Undo.AddComponent(this.gameObject, feedbackType) as MMFeedback;
}
else
{
newFeedback = this.gameObject.AddComponent(feedbackType) as MMFeedback;
}
#else
newFeedback = this.gameObject.AddComponent(feedbackType) as MMFeedback;
#endif
newFeedback.hideFlags = HideFlags.HideInInspector;
newFeedback.Label = FeedbackPathAttribute.GetFeedbackDefaultName(feedbackType);
AutoRepair();
return newFeedback;
}
public virtual void RemoveFeedback(int id)
{
#if UNITY_EDITOR
if (!Application.isPlaying)
{
Undo.DestroyObjectImmediate(Feedbacks[id]);
}
else
{
DestroyImmediate(Feedbacks[id]);
}
#else
DestroyImmediate(Feedbacks[id]);
#endif
Feedbacks.RemoveAt(id);
AutoRepair();
}
#endregion MODIFICATION
#region HELPERS
/// <summary>
/// Evaluates the chance of this feedback to play, and returns true if this feedback can play, false otherwise
/// </summary>
/// <returns></returns>
protected virtual bool EvaluateChance()
{
if (ChanceToPlay == 0f)
{
return false;
}
if (ChanceToPlay != 100f)
{
// determine the odds
float random = Random.Range(0f, 100f);
if (random > ChanceToPlay)
{
return false;
}
}
return true;
}
/// <summary>
/// Checks whether or not this MMFeedbacks contains one or more looper feedbacks
/// </summary>
protected virtual void CheckForLoops()
{
ContainsLoop = false;
for (int i = 0; i < Feedbacks.Count; i++)
{
if (Feedbacks[i] != null)
{
if (Feedbacks[i].LooperPause && Feedbacks[i].Active)
{
ContainsLoop = true;
return;
}
}
}
}
/// <summary>
/// This will return true if the conditions defined in the specified feedback's Timing section allow it to play in the current play direction of this MMFeedbacks
/// </summary>
/// <param name="feedback"></param>
/// <returns></returns>
protected bool FeedbackCanPlay(MMFeedback feedback)
{
if (feedback == null)
{
return false;
}
if (feedback.Timing == null)
{
return false;
}
if (feedback.Timing.MMFeedbacksDirectionCondition == MMFeedbackTiming.MMFeedbacksDirectionConditions.Always)
{
return true;
}
else if (((Direction == Directions.TopToBottom) && (feedback.Timing.MMFeedbacksDirectionCondition == MMFeedbackTiming.MMFeedbacksDirectionConditions.OnlyWhenForwards))
|| ((Direction == Directions.BottomToTop) && (feedback.Timing.MMFeedbacksDirectionCondition == MMFeedbackTiming.MMFeedbacksDirectionConditions.OnlyWhenBackwards)))
{
return true;
}
return false;
}
/// <summary>
/// Readies the MMFeedbacks to change direction on the next play
/// </summary>
protected virtual void ApplyAutoChangeDirection()
{
if (AutoChangeDirectionOnEnd)
{
ShouldChangeDirectionOnNextPlay = true;
}
}
/// <summary>
/// Applies this feedback's time multiplier to a duration (in seconds)
/// </summary>
/// <param name="duration"></param>
/// <returns></returns>
public virtual float ApplyTimeMultiplier(float duration)
{
return duration * Mathf.Clamp(DurationMultiplier, _smallValue, Single.MaxValue);
}
/// <summary>
/// Unity sometimes has serialization issues.
/// This method fixes that by fixing any bad sync that could happen.
/// </summary>
public virtual void AutoRepair()
{
List<Component> components = components = new List<Component>();
components = this.gameObject.GetComponents<Component>().ToList();
foreach (Component component in components)
{
if (component is MMFeedback)
{
bool found = false;
for (int i = 0; i < Feedbacks.Count; i++)
{
if (Feedbacks[i] == (MMFeedback)component)
{
found = true;
break;
}
}
if (!found)
{
Feedbacks.Add((MMFeedback)component);
}
}
}
}
#endregion
#region EVENTS
/// <summary>
/// On Disable we stop all feedbacks
/// </summary>
protected virtual void OnDisable()
{
/*if (IsPlaying)
{
StopFeedbacks();
StopAllCoroutines();
}*/
}
/// <summary>
/// On validate, we make sure our DurationMultiplier remains positive
/// </summary>
protected virtual void OnValidate()
{
DurationMultiplier = Mathf.Clamp(DurationMultiplier, _smallValue, Single.MaxValue);
}
/// <summary>
/// On Destroy, removes all feedbacks from this MMFeedbacks to avoid any leftovers
/// </summary>
protected virtual void OnDestroy()
{
IsPlaying = false;
#if UNITY_EDITOR
if (!Application.isPlaying)
{
// we remove all binders
foreach (MMFeedback feedback in Feedbacks)
{
EditorApplication.delayCall += () =>
{
DestroyImmediate(feedback);
};
}
}
#endif
}
#endregion EVENTS
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 841b72de2996c5c40bfb394f3d0e0a98
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Core/Legacy/MMFeedbacks.cs
uploadId: 830868

View File

@@ -0,0 +1,28 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace MoreMountains.Feedbacks
{
/// <summary>
/// A helper class added automatically by MMFeedbacks if they're in AutoPlayOnEnable mode
/// This lets them play again should their parent game object be disabled/enabled
/// </summary>
[AddComponentMenu("")]
public class MMFeedbacksEnabler : MonoBehaviour
{
/// the MMFeedbacks to pilot
public MMFeedbacks TargetMMFeedbacks { get; set; }
/// <summary>
/// On enable, we re-enable (and thus play) our MMFeedbacks if needed
/// </summary>
protected virtual void OnEnable()
{
if ((TargetMMFeedbacks != null) && !TargetMMFeedbacks.enabled && TargetMMFeedbacks.AutoPlayOnEnable)
{
TargetMMFeedbacks.enabled = true;
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: dd5c9de2e9b0d6540b318450df3fb297
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Core/Legacy/MMFeedbacksEnabler.cs
uploadId: 830868

View File

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

View File

@@ -0,0 +1,14 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 09e29c2242d13d64480d58af86fcb50f, type: 3}
m_Name: ChannelA
m_EditorClassIdentifier:

View File

@@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: 6ba165fd91edb434aa2f1cd6f6b05885
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Core/MMChannels/ChannelA.asset
uploadId: 830868

View File

@@ -0,0 +1,14 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 09e29c2242d13d64480d58af86fcb50f, type: 3}
m_Name: ChannelB
m_EditorClassIdentifier:

View File

@@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: 7471a7ccb4c5bdb4e9c9d5b51f6db888
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Core/MMChannels/ChannelB.asset
uploadId: 830868

View File

@@ -0,0 +1,14 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 09e29c2242d13d64480d58af86fcb50f, type: 3}
m_Name: ChannelC
m_EditorClassIdentifier:

View File

@@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: 277be439bdc9329468f9e6d0799d54be
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Core/MMChannels/ChannelC.asset
uploadId: 830868

View File

@@ -0,0 +1,92 @@
using System;
using UnityEngine;
namespace MoreMountains.Feedbacks
{
/// <summary>
/// The possible modes used to identify a channel, either via an int or a MMChannel scriptable object
/// </summary>
public enum MMChannelModes
{
Int,
MMChannel
}
/// <summary>
/// A data structure used to pass channel information
/// </summary>
[Serializable]
public class MMChannelData
{
public MMChannelModes MMChannelMode;
public int Channel;
public MMChannel MMChannelDefinition;
public MMChannelData(MMChannelModes mode, int channel, MMChannel channelDefinition)
{
MMChannelMode = mode;
Channel = channel;
MMChannelDefinition = channelDefinition;
}
}
/// <summary>
/// Extensions class for MMChannelData
/// </summary>
public static class MMChannelDataExtensions
{
public static MMChannelData Set(this MMChannelData data, MMChannelModes mode, int channel, MMChannel channelDefinition)
{
data.MMChannelMode = mode;
data.Channel = channel;
data.MMChannelDefinition = channelDefinition;
return data;
}
}
/// <summary>
/// A scriptable object you can create assets from, to identify Channels, used mostly (but not only) in feedbacks and shakers,
/// to determine a channel of communication, usually between emitters and receivers
/// </summary>
[CreateAssetMenu(menuName = "MoreMountains/MMChannel", fileName = "MMChannel")]
public class MMChannel : ScriptableObject
{
public static bool Match(MMChannelData dataA, MMChannelData dataB)
{
if (dataA.MMChannelMode != dataB.MMChannelMode)
{
return false;
}
if (dataA.MMChannelMode == MMChannelModes.Int)
{
return dataA.Channel == dataB.Channel;
}
else
{
return dataA.MMChannelDefinition == dataB.MMChannelDefinition;
}
}
public static bool Match(MMChannelData dataA, MMChannelModes modeB, int channelB, MMChannel channelDefinitionB)
{
if (dataA == null)
{
return true;
}
if (dataA.MMChannelMode != modeB)
{
return false;
}
if (dataA.MMChannelMode == MMChannelModes.Int)
{
return dataA.Channel == channelB;
}
else
{
return dataA.MMChannelDefinition == channelDefinitionB;
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 09e29c2242d13d64480d58af86fcb50f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Core/MMChannels/MMChannel.cs
uploadId: 830868

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 1466e386bacf73e428d7e19707b9e185
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Core/MMF_Player/MMF_Feedback.cs
uploadId: 830868

View File

@@ -0,0 +1,22 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace MoreMountains.Feedbacks
{
[Serializable]
public class MMF_Button
{
public delegate void ButtonMethod();
public string ButtonText;
public ButtonMethod TargetMethod;
public MMF_Button(string buttonText, ButtonMethod method)
{
ButtonText = buttonText;
TargetMethod = method;
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: ecda383e35cc53e4ca2b9d5857dbd8f4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Core/MMF_Player/MMF_FeedbackAttributes.cs
uploadId: 830868

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 6da43522623d4704e979466dc7650b65
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Core/MMF_Player/MMF_Player.cs
uploadId: 830868

View File

@@ -0,0 +1,54 @@
using System.Collections;
using System.Collections.Generic;
using MoreMountains.Feedbacks;
using UnityEngine;
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
using UnityEngine.InputSystem;
#endif
namespace MoreMountains.Feedbacks
{
/// <summary>
/// Add this debug component to a MMF Player, and you'll be able to play it at runtime at the press of a (customisable) key, useful when tweaking or debugging your feedbacks
/// </summary>
public class MMF_PlayerDebugInput : MonoBehaviour
{
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
/// the button used to cause a debug play of this feedback
public Key PlayKey = Key.P;
#else
/// the button used to cause a debug play of this feedback
public KeyCode PlayButton = KeyCode.P;
#endif
protected MMF_Player _player;
/// <summary>
/// On Awake we store our MMF Player
/// </summary>
protected virtual void Awake()
{
_player = this.gameObject.GetComponent<MMF_Player>();
}
/// <summary>
/// On Update, we play our feedback if the right button is pressed
/// </summary>
protected virtual void Update()
{
bool keyPressed = false;
#if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER
keyPressed = Keyboard.current[PlayKey].wasPressedThisFrame;
#else
keyPressed = Input.GetKeyDown(PlayButton);
#endif
if (keyPressed)
{
_player.PlayFeedbacks();
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 4474026fd06a48748b3ac7eef71e802d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Core/MMF_Player/MMF_PlayerDebugInput.cs
uploadId: 830868

View File

@@ -0,0 +1,28 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace MoreMountains.Feedbacks
{
/// <summary>
/// A helper class added automatically by MMF_Player if they're in AutoPlayOnEnable mode
/// This lets them play again should their parent game object be disabled/enabled
/// </summary>
[AddComponentMenu("")]
public class MMF_PlayerEnabler : MonoBehaviour
{
/// the MMF_Player to pilot
public virtual MMF_Player TargetMmfPlayer { get; set; }
/// <summary>
/// On enable, we re-enable (and thus play) our MMF_Player if needed
/// </summary>
protected virtual void OnEnable()
{
if ((TargetMmfPlayer != null) && !TargetMmfPlayer.enabled && TargetMmfPlayer.AutoPlayOnEnable)
{
TargetMmfPlayer.enabled = true;
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 109f4af2c917dc74aa07733bafe2f548
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Core/MMF_Player/MMF_PlayerEnabler.cs
uploadId: 830868

View File

@@ -0,0 +1,123 @@
using System.Collections;
using System.Collections.Generic;
using MoreMountains.Tools;
using UnityEngine;
namespace MoreMountains.Feedbacks
{
/// <summary>
/// A class collecting target acquisition settings
/// </summary>
[System.Serializable]
public class MMFeedbackTargetAcquisition
{
public enum Modes { None, Self, AnyChild, ChildAtIndex, Parent, FirstReferenceHolder, PreviousReferenceHolder, ClosestReferenceHolder, NextReferenceHolder, LastReferenceHolder }
/// the selected mode for target acquisition
/// None : nothing will happen
/// Self : the target will be picked on the MMF Player's game object
/// AnyChild : the target will be picked on any of the MMF Player's child objects
/// ChildAtIndex : the target will be picked on the child at index X of the MMF Player
/// Parent : the target will be picked on the first parent where a matching target is found
/// Various reference holders : the target will be picked on the specified reference holder in the list (either the first one, previous : first one found before this feedback in the list, closest in any direction from this feedback, the next one found, or the last one in the list)
[Tooltip("the selected mode for target acquisition\n"+
"None : nothing will happen\n"+
"Self : the target will be picked on the MMF Player's game object\n"+
"AnyChild : the target will be picked on any of the MMF Player's child objects\n"+
"ChildAtIndex : the target will be picked on the child at index X of the MMF Player\n"+
"Parent : the target will be picked on the first parent where a matching target is found\n"+
"Various reference holders : the target will be picked on the specified reference holder in the list " +
"(either the first one, previous : first one found before this feedback in the list, closest in any direction from this feedback, the next one found, or the last one in the list)")]
public Modes Mode = Modes.None;
[MMFEnumCondition("Mode", (int)Modes.ChildAtIndex)]
public int ChildIndex = 0;
private static MMF_ReferenceHolder _referenceHolder;
public static MMF_ReferenceHolder GetReferenceHolder(MMFeedbackTargetAcquisition settings, MMF_Player owner, int currentFeedbackIndex)
{
switch (settings.Mode)
{
case Modes.FirstReferenceHolder:
return owner.GetFeedbackOfType<MMF_ReferenceHolder>(MMF_Player.AccessMethods.First, currentFeedbackIndex);
case Modes.PreviousReferenceHolder:
return owner.GetFeedbackOfType<MMF_ReferenceHolder>(MMF_Player.AccessMethods.Previous, currentFeedbackIndex);
case Modes.ClosestReferenceHolder:
return owner.GetFeedbackOfType<MMF_ReferenceHolder>(MMF_Player.AccessMethods.Closest, currentFeedbackIndex);
case Modes.NextReferenceHolder:
return owner.GetFeedbackOfType<MMF_ReferenceHolder>(MMF_Player.AccessMethods.Next, currentFeedbackIndex);
case Modes.LastReferenceHolder:
return owner.GetFeedbackOfType<MMF_ReferenceHolder>(MMF_Player.AccessMethods.Last, currentFeedbackIndex);
}
return null;
}
public static GameObject FindAutomatedTargetGameObject(MMFeedbackTargetAcquisition settings, MMF_Player owner, int currentFeedbackIndex)
{
if (owner.FeedbacksList[currentFeedbackIndex].ForcedReferenceHolder != null)
{
return owner.FeedbacksList[currentFeedbackIndex].ForcedReferenceHolder.GameObjectReference;
}
_referenceHolder = GetReferenceHolder(settings, owner, currentFeedbackIndex);
switch (settings.Mode)
{
case Modes.Self:
return owner.gameObject;
case Modes.ChildAtIndex:
return owner.transform.GetChild(settings.ChildIndex).gameObject;
case Modes.AnyChild:
return owner.transform.GetChild(0).gameObject;
case Modes.Parent:
return owner.transform.parent.gameObject;
case Modes.FirstReferenceHolder:
case Modes.PreviousReferenceHolder:
case Modes.ClosestReferenceHolder:
case Modes.NextReferenceHolder:
case Modes.LastReferenceHolder:
return _referenceHolder?.GameObjectReference;
}
return null;
}
public static T FindAutomatedTarget<T>(MMFeedbackTargetAcquisition settings, MMF_Player owner, int currentFeedbackIndex)
{
if (owner.FeedbacksList[currentFeedbackIndex].ForcedReferenceHolder != null)
{
return owner.FeedbacksList[currentFeedbackIndex].ForcedReferenceHolder.GameObjectReference.GetComponent<T>();
}
_referenceHolder = GetReferenceHolder(settings, owner, currentFeedbackIndex);
switch (settings.Mode)
{
case Modes.Self:
return owner.GetComponent<T>();
case Modes.ChildAtIndex:
return owner.transform.GetChild(settings.ChildIndex).gameObject.GetComponent<T>();
case Modes.AnyChild:
for (int i = 0; i < owner.transform.childCount; i++)
{
if (owner.transform.GetChild(i).GetComponent<T>() != null)
{
return owner.transform.GetChild(i).GetComponent<T>();
}
}
return owner.GetComponentInChildren<T>();
case Modes.Parent:
return owner.transform.parent.GetComponentInParent<T>();
case Modes.FirstReferenceHolder:
case Modes.PreviousReferenceHolder:
case Modes.ClosestReferenceHolder:
case Modes.NextReferenceHolder:
case Modes.LastReferenceHolder:
return (_referenceHolder != null)
? _referenceHolder.GameObjectReference.GetComponent<T>()
: default(T);
}
return default(T);
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: a40118e4d239fe146bb900366085611f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Core/MMFeedbackTargetAcquisition.cs
uploadId: 830868

View File

@@ -0,0 +1,137 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace MoreMountains.Feedbacks
{
/// the possible modes for the timescale
public enum TimescaleModes { Scaled, Unscaled }
/// <summary>
/// A class collecting delay, cooldown and repeat values, to be used to define the behaviour of each MMFeedback
/// </summary>
[System.Serializable]
public class MMFeedbackTiming
{
/// the possible ways this feedback can play based on the host MMFeedbacks' directions
public enum MMFeedbacksDirectionConditions { Always, OnlyWhenForwards, OnlyWhenBackwards };
/// the possible ways this feedback can play
public enum PlayDirections { FollowMMFeedbacksDirection, OppositeMMFeedbacksDirection, AlwaysNormal, AlwaysRewind }
[Header("Timescale")]
/// whether we're working on scaled or unscaled time
[Tooltip("whether we're working on scaled or unscaled time")]
public TimescaleModes TimescaleMode = TimescaleModes.Scaled;
[Header("Exceptions")]
/// if this is true, holding pauses won't wait for this feedback to finish
[Tooltip("if this is true, holding pauses won't wait for this feedback to finish")]
public bool ExcludeFromHoldingPauses = false;
/// whether to count this feedback in the parent MMFeedbacks(Player) total duration or not
[Tooltip("whether to count this feedback in the parent MMFeedbacks(Player) total duration or not")]
public bool ContributeToTotalDuration = true;
[Header("Delays")]
/// the initial delay to apply before playing the delay (in seconds)
[Tooltip("the initial delay to apply before playing the delay (in seconds)")]
public float InitialDelay = 0f;
/// the cooldown duration mandatory between two plays
[Tooltip("the cooldown duration mandatory between two plays")]
public float CooldownDuration = 0f;
[Header("Stop")]
/// if this is true, this feedback will interrupt itself when Stop is called on its parent MMFeedbacks, otherwise it'll keep running
[Tooltip("if this is true, this feedback will interrupt itself when Stop is called on its parent MMFeedbacks, otherwise it'll keep running")]
public bool InterruptsOnStop = true;
[Header("Repeat")]
/// the repeat mode, whether the feedback should be played once, multiple times, or forever
[Tooltip("the repeat mode, whether the feedback should be played once, multiple times, or forever")]
public int NumberOfRepeats = 0;
/// if this is true, the feedback will be repeated forever
[Tooltip("if this is true, the feedback will be repeated forever")]
public bool RepeatForever = false;
/// the delay (in seconds) between two firings of this feedback. This doesn't include the duration of the feedback.
[Tooltip("the delay (in seconds) between two firings of this feedback. This doesn't include the duration of the feedback.")]
public float DelayBetweenRepeats = 1f;
[Header("PlayCount")]
/// the number of times this feedback's been played since its initialization (or last reset if SetPlayCountToZeroOnReset is true)
[Tooltip("the number of times this feedback's been played since its initialization (or last reset if SetPlayCountToZeroOnReset is true)")]
[MMFReadOnly]
public int PlayCount = 0;
/// whether or not to limit the amount of times this feedback can be played. beyond that amount, it won't play anymore
[Tooltip("whether or not to limit the amount of times this feedback can be played. beyond that amount, it won't play anymore")]
public bool LimitPlayCount = false;
/// if LimitPlayCount is true, the maximum amount of times this feedback can be played
[Tooltip("if LimitPlayCount is true, the maximum amount of times this feedback can be played")]
[MMFCondition("LimitPlayCount", true)]
public int MaxPlayCount = 3;
/// if LimitPlayCount is true, whether or not to reset the play count to zero when the feedback is reset
[Tooltip("if LimitPlayCount is true, whether or not to reset the play count to zero when the feedback is reset")]
[MMFCondition("LimitPlayCount", true)]
public bool SetPlayCountToZeroOnReset = false;
[Header("Play Direction")]
/// this defines how this feedback should play when the host MMFeedbacks is played :
/// - always (default) : this feedback will always play
/// - OnlyWhenForwards : this feedback will only play if the host MMFeedbacks is played in the top to bottom direction (forwards)
/// - OnlyWhenBackwards : this feedback will only play if the host MMFeedbacks is played in the bottom to top direction (backwards)
[Tooltip("this defines how this feedback should play when the host MMFeedbacks is played :" +
"- always (default) : this feedback will always play" +
"- OnlyWhenForwards : this feedback will only play if the host MMFeedbacks is played in the top to bottom direction (forwards)" +
"- OnlyWhenBackwards : this feedback will only play if the host MMFeedbacks is played in the bottom to top direction (backwards)")]
public MMFeedbacksDirectionConditions MMFeedbacksDirectionCondition = MMFeedbacksDirectionConditions.Always;
/// this defines the way this feedback will play. It can play in its normal direction, or in rewind (a sound will play backwards,
/// an object normally scaling up will scale down, a curve will be evaluated from right to left, etc)
/// - BasedOnMMFeedbacksDirection : will play normally when the host MMFeedbacks is played forwards, in rewind when it's played backwards
/// - OppositeMMFeedbacksDirection : will play in rewind when the host MMFeedbacks is played forwards, and normally when played backwards
/// - Always Normal : will always play normally, regardless of the direction of the host MMFeedbacks
/// - Always Rewind : will always play in rewind, regardless of the direction of the host MMFeedbacks
[Tooltip("this defines the way this feedback will play. It can play in its normal direction, or in rewind (a sound will play backwards," +
" an object normally scaling up will scale down, a curve will be evaluated from right to left, etc)" +
"- BasedOnMMFeedbacksDirection : will play normally when the host MMFeedbacks is played forwards, in rewind when it's played backwards" +
"- OppositeMMFeedbacksDirection : will play in rewind when the host MMFeedbacks is played forwards, and normally when played backwards" +
"- Always Normal : will always play normally, regardless of the direction of the host MMFeedbacks" +
"- Always Rewind : will always play in rewind, regardless of the direction of the host MMFeedbacks")]
public PlayDirections PlayDirection = PlayDirections.FollowMMFeedbacksDirection;
[Header("Intensity")]
/// if this is true, intensity will be constant, even if the parent MMFeedbacks is played at a lower intensity
[Tooltip("if this is true, intensity will be constant, even if the parent MMFeedbacks is played at a lower intensity")]
public bool ConstantIntensity = false;
/// if this is true, this feedback will only play if its intensity is higher or equal to IntensityIntervalMin and lower than IntensityIntervalMax
[Tooltip("if this is true, this feedback will only play if its intensity is higher or equal to IntensityIntervalMin and lower than IntensityIntervalMax")]
public bool UseIntensityInterval = false;
/// the minimum intensity required for this feedback to play
[Tooltip("the minimum intensity required for this feedback to play")]
[MMFCondition("UseIntensityInterval", true)]
public float IntensityIntervalMin = 0f;
/// the maximum intensity required for this feedback to play
[Tooltip("the maximum intensity required for this feedback to play")]
[MMFCondition("UseIntensityInterval", true)]
public float IntensityIntervalMax = 0f;
[Header("Sequence")]
/// A MMSequence to use to play these feedbacks on
[Tooltip("A MMSequence to use to play these feedbacks on")]
public MMSequence Sequence;
/// The MMSequence's TrackID to consider
[Tooltip("The MMSequence's TrackID to consider")]
public int TrackID = 0;
/// whether or not to use the quantized version of the target sequence
[Tooltip("whether or not to use the quantized version of the target sequence")]
public bool Quantized = false;
/// if using the quantized version of the target sequence, the BPM to apply to the sequence when playing it
[Tooltip("if using the quantized version of the target sequence, the BPM to apply to the sequence when playing it")]
[MMFCondition("Quantized", true)]
public int TargetBPM = 120;
/// from any class, you can set UseScriptDrivenTimescale:true, from there, instead of looking at Time.time, Time.deltaTime (or their unscaled equivalents), this feedback will compute time based on the values you feed them via ScriptDrivenDeltaTime and ScriptDrivenTime
public virtual bool UseScriptDrivenTimescale { get; set; }
/// the value this feedback should use for delta time
public virtual float ScriptDrivenDeltaTime { get; set; }
/// the value this feedback should use for time
public virtual float ScriptDrivenTime { get; set; }
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 293c62544284dea419e338a8524a7fb4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Core/MMFeedbackTiming.cs
uploadId: 830868

View File

@@ -0,0 +1,55 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace MoreMountains.Feedbacks
{
/// <summary>
/// Coroutine helpers
/// </summary>
public static class MMFeedbacksCoroutine
{
/// <summary>
/// Waits for the specified amount of frames
/// use : yield return MMCoroutine.WaitFor(1);
/// </summary>
/// <param name="frameCount"></param>
/// <returns></returns>
public static IEnumerator WaitForFrames(int frameCount)
{
while (frameCount > 0)
{
frameCount--;
yield return null;
}
}
/// <summary>
/// Waits for the specified amount of seconds (using regular time)
/// use : yield return MMCoroutine.WaitFor(1f);
/// </summary>
/// <param name="seconds"></param>
/// <returns></returns>
public static IEnumerator WaitFor(float seconds)
{
for (float timer = 0f; timer < seconds; timer += Time.deltaTime)
{
yield return null;
}
}
/// <summary>
/// Waits for the specified amount of seconds (using unscaled time)
/// use : yield return MMCoroutine.WaitForUnscaled(1f);
/// </summary>
/// <param name="seconds"></param>
/// <returns></returns>
public static IEnumerator WaitForUnscaled(float seconds)
{
for (float timer = 0f; timer < seconds; timer += Time.unscaledDeltaTime)
{
yield return null;
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: fff95d1eb5038764b9fdf57b6818aa6f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Core/MMFeedbacksCoroutine.cs
uploadId: 830868

View File

@@ -0,0 +1,330 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Serialization;
namespace MoreMountains.Feedbacks
{
/// <summary>
/// Events triggered by a MMFeedbacks when playing a series of feedbacks
/// - play : when a MMFeedbacks starts playing
/// - pause : when a holding pause is met
/// - resume : after a holding pause resumes
/// - changeDirection : when a MMFeedbacks changes its play direction
/// - complete : when a MMFeedbacks has played its last feedback
///
/// to listen to these events :
///
/// public virtual void OnMMFeedbacksEvent(MMFeedbacks source, EventTypes type)
/// {
/// // do something
/// }
///
/// protected virtual void OnEnable()
/// {
/// MMFeedbacksEvent.Register(OnMMFeedbacksEvent);
/// }
///
/// protected virtual void OnDisable()
/// {
/// MMFeedbacksEvent.Unregister(OnMMFeedbacksEvent);
/// }
///
/// </summary>
public struct MMFeedbacksEvent
{
static private event Delegate OnEvent;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] private static void RuntimeInitialization() { OnEvent = null; }
static public void Register(Delegate callback) { OnEvent += callback; }
static public void Unregister(Delegate callback) { OnEvent -= callback; }
public enum EventTypes { Play, Pause, Resume, ChangeDirection, Complete, SkipToTheEnd, RestoreInitialValues, Loop, Enable, Disable, InitializationComplete, Stop }
public delegate void Delegate(MMFeedbacks source, EventTypes type);
static public void Trigger(MMFeedbacks source, EventTypes type)
{
OnEvent?.Invoke(source, type);
}
}
/// <summary>
/// An event used to set the RangeCenter on all feedbacks that listen for it
/// </summary>
public struct MMSetFeedbackRangeCenterEvent
{
static private event Delegate OnEvent;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] private static void RuntimeInitialization() { OnEvent = null; }
static public void Register(Delegate callback) { OnEvent += callback; }
static public void Unregister(Delegate callback) { OnEvent -= callback; }
public delegate void Delegate(Transform newCenter);
static public void Trigger(Transform newCenter)
{
OnEvent?.Invoke(newCenter);
}
}
/// <summary>
/// A subclass of MMFeedbacks, contains UnityEvents that can be played,
/// </summary>
[Serializable]
public class MMFeedbacksEvents
{
/// whether or not this MMFeedbacks should fire MMFeedbacksEvents
[Tooltip("whether or not this MMFeedbacks should fire MMFeedbacksEvents")]
public bool TriggerMMFeedbacksEvents = false;
/// whether or not this MMFeedbacks should fire Unity Events
[Tooltip("whether or not this MMFeedbacks should fire Unity Events")]
public bool TriggerUnityEvents = true;
/// This event will fire every time this MMFeedbacks gets played
[Tooltip("This event will fire every time this MMFeedbacks gets played")]
public UnityEvent OnPlay;
/// This event will fire every time this MMFeedbacks starts a holding pause
[Tooltip("This event will fire every time this MMFeedbacks starts a holding pause")]
public UnityEvent OnPause;
/// This event will fire every time this MMFeedbacks gets stopped via a call to the StopFeedbacks method
[Tooltip("This event will fire every time this MMFeedbacks gets stopped via a call to the StopFeedbacks method")]
public UnityEvent OnStop;
/// This event will fire every time this MMFeedbacks resumes after a holding pause
[Tooltip("This event will fire every time this MMFeedbacks resumes after a holding pause")]
public UnityEvent OnResume;
/// This event will fire every time this MMFeedbacks changes its play direction
[FormerlySerializedAs("OnRevert")]
[Tooltip("This event will fire every time this MMFeedbacks changes its play direction")]
public UnityEvent OnChangeDirection;
/// This event will fire every time this MMFeedbacks plays its last MMFeedback
[Tooltip("This event will fire every time this MMFeedbacks plays its last MMFeedback")]
public UnityEvent OnComplete;
/// This event will fire every time this MMFeedbacks gets restored to its initial values
[Tooltip("This event will fire every time this MMFeedbacks gets restored to its initial values")]
public UnityEvent OnRestoreInitialValues;
/// This event will fire every time this MMFeedbacks gets skipped to the end
[Tooltip("This event will fire every time this MMFeedbacks gets skipped to the end")]
public UnityEvent OnSkipToTheEnd;
/// This event will fire after the MMF Player is done initializing
[Tooltip("This event will fire after the MMF Player is done initializing")]
public UnityEvent OnInitializationComplete;
/// This event will fire every time this MMFeedbacks' game object gets enabled
[Tooltip("This event will fire every time this MMFeedbacks' game object gets enabled")]
public UnityEvent OnEnable;
/// This event will fire every time this MMFeedbacks' game object gets disabled
[Tooltip("This event will fire every time this MMFeedbacks' game object gets disabled")]
public UnityEvent OnDisable;
public virtual bool OnPlayIsNull { get; protected set; }
public virtual bool OnPauseIsNull { get; protected set; }
public virtual bool OnResumeIsNull { get; protected set; }
public virtual bool OnChangeDirectionIsNull { get; protected set; }
public virtual bool OnCompleteIsNull { get; protected set; }
public virtual bool OnRestoreInitialValuesIsNull { get; protected set; }
public virtual bool OnSkipToTheEndIsNull { get; protected set; }
public virtual bool OnInitializationCompleteIsNull { get; protected set; }
public virtual bool OnEnableIsNull { get; protected set; }
public virtual bool OnDisableIsNull { get; protected set; }
public virtual bool OnStopIsNull { get; protected set; }
/// <summary>
/// On init we store for each event whether or not we have one to invoke
/// </summary>
public virtual void Initialization()
{
OnPlayIsNull = OnPlay == null;
OnPauseIsNull = OnPause == null;
OnResumeIsNull = OnResume == null;
OnChangeDirectionIsNull = OnChangeDirection == null;
OnCompleteIsNull = OnComplete == null;
OnRestoreInitialValuesIsNull = OnRestoreInitialValues == null;
OnSkipToTheEndIsNull = OnSkipToTheEnd == null;
OnInitializationCompleteIsNull = OnInitializationComplete == null;
OnEnableIsNull = OnEnable == null;
OnDisableIsNull = OnDisable == null;
OnStopIsNull = OnStop == null;
}
/// <summary>
/// Fires Play events if needed
/// </summary>
/// <param name="source"></param>
public virtual void TriggerOnPlay(MMFeedbacks source)
{
if (!OnPlayIsNull && TriggerUnityEvents)
{
OnPlay.Invoke();
}
if (TriggerMMFeedbacksEvents)
{
MMFeedbacksEvent.Trigger(source, MMFeedbacksEvent.EventTypes.Play);
}
}
/// <summary>
/// Fires pause events if needed
/// </summary>
/// <param name="source"></param>
public virtual void TriggerOnPause(MMFeedbacks source)
{
if (!OnPauseIsNull && TriggerUnityEvents)
{
OnPause.Invoke();
}
if (TriggerMMFeedbacksEvents)
{
MMFeedbacksEvent.Trigger(source, MMFeedbacksEvent.EventTypes.Pause);
}
}
/// <summary>
/// Fires resume events if needed
/// </summary>
/// <param name="source"></param>
public virtual void TriggerOnResume(MMFeedbacks source)
{
if (!OnResumeIsNull && TriggerUnityEvents)
{
OnResume.Invoke();
}
if (TriggerMMFeedbacksEvents)
{
MMFeedbacksEvent.Trigger(source, MMFeedbacksEvent.EventTypes.Resume);
}
}
/// <summary>
/// Fires change direction events if needed
/// </summary>
/// <param name="source"></param>
public virtual void TriggerOnChangeDirection(MMFeedbacks source)
{
if (!OnChangeDirectionIsNull && TriggerUnityEvents)
{
OnChangeDirection.Invoke();
}
if (TriggerMMFeedbacksEvents)
{
MMFeedbacksEvent.Trigger(source, MMFeedbacksEvent.EventTypes.ChangeDirection);
}
}
/// <summary>
/// Fires complete events if needed
/// </summary>
/// <param name="source"></param>
public virtual void TriggerOnComplete(MMFeedbacks source)
{
if (!OnCompleteIsNull && TriggerUnityEvents)
{
OnComplete.Invoke();
}
if (TriggerMMFeedbacksEvents)
{
MMFeedbacksEvent.Trigger(source, MMFeedbacksEvent.EventTypes.Complete);
}
}
/// <summary>
/// Fires skip events if needed
/// </summary>
/// <param name="source"></param>
public virtual void TriggerOnSkipToTheEnd(MMFeedbacks source)
{
if (!OnSkipToTheEndIsNull && TriggerUnityEvents)
{
OnSkipToTheEnd.Invoke();
}
if (TriggerMMFeedbacksEvents)
{
MMFeedbacksEvent.Trigger(source, MMFeedbacksEvent.EventTypes.SkipToTheEnd);
}
}
public virtual void TriggerOnInitializationComplete(MMFeedbacks source)
{
if (!OnInitializationCompleteIsNull && TriggerUnityEvents)
{
OnInitializationComplete.Invoke();
}
if (TriggerMMFeedbacksEvents)
{
MMFeedbacksEvent.Trigger(source, MMFeedbacksEvent.EventTypes.InitializationComplete);
}
}
/// <summary>
/// Fires restore initial values events if needed
/// </summary>
/// <param name="source"></param>
public virtual void TriggerOnRestoreInitialValues(MMFeedbacks source)
{
if (!OnRestoreInitialValuesIsNull && TriggerUnityEvents)
{
OnRestoreInitialValues.Invoke();
}
if (TriggerMMFeedbacksEvents)
{
MMFeedbacksEvent.Trigger(source, MMFeedbacksEvent.EventTypes.RestoreInitialValues);
}
}
/// <summary>
/// Fires enable events if needed
/// </summary>
/// <param name="source"></param>
public virtual void TriggerOnEnable(MMF_Player source)
{
if (!OnEnableIsNull && TriggerUnityEvents)
{
OnEnable.Invoke();
}
if (TriggerMMFeedbacksEvents)
{
MMFeedbacksEvent.Trigger(source, MMFeedbacksEvent.EventTypes.Enable);
}
}
/// <summary>
/// Fires disable events if needed
/// </summary>
/// <param name="source"></param>
public virtual void TriggerOnDisable(MMF_Player source)
{
if (!OnDisableIsNull && TriggerUnityEvents)
{
OnDisable.Invoke();
}
if (TriggerMMFeedbacksEvents)
{
MMFeedbacksEvent.Trigger(source, MMFeedbacksEvent.EventTypes.Disable);
}
}
/// <summary>
/// Fires stop events if needed
/// </summary>
/// <param name="source"></param>
public virtual void TriggerOnStop(MMF_Player source)
{
if (!OnDisableIsNull && TriggerUnityEvents)
{
OnStop.Invoke();
}
if (TriggerMMFeedbacksEvents)
{
MMFeedbacksEvent.Trigger(source, MMFeedbacksEvent.EventTypes.Stop);
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 716ed1aa8290ba04ba69b411a3d8554a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Core/MMFeedbacksEvents.cs
uploadId: 830868

View File

@@ -0,0 +1,568 @@
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using System.Linq;
using System.Reflection;
using MoreMountains.Tools;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace MoreMountains.Feedbacks
{
[AddComponentMenu("")]
public class MMFeedbacksHelpers : MonoBehaviour
{
/// <summary>
/// Remaps a value x in interval [A,B], to the proportional value in interval [C,D]
/// </summary>
/// <param name="x">The value to remap.</param>
/// <param name="A">the minimum bound of interval [A,B] that contains the x value</param>
/// <param name="B">the maximum bound of interval [A,B] that contains the x value</param>
/// <param name="C">the minimum bound of target interval [C,D]</param>
/// <param name="D">the maximum bound of target interval [C,D]</param>
public static float Remap(float x, float A, float B, float C, float D)
{
float remappedValue = C + (x - A) / (B - A) * (D - C);
return remappedValue;
}
/// <summary>
/// A helper used to migrate values from an AnimationCurve field to a MMTweenType, useful when updating
/// old feedbacks to use them without losing legacy values
/// </summary>
/// <param name="oldCurve"></param>
/// <param name="newTweenType"></param>
/// <param name="owner"></param>
public static void MigrateCurve(AnimationCurve oldCurve, MMTweenType newTweenType, MMF_Player owner)
{
if ((oldCurve.keys.Length > 0) && (!newTweenType.Initialized))
{
newTweenType.Curve = oldCurve;
newTweenType.MMTweenDefinitionType = MMTweenDefinitionTypes.AnimationCurve;
oldCurve = null;
newTweenType.Initialized = true;
#if UNITY_EDITOR
UnityEditor.Undo.RecordObject(owner, "Ports animation curve to tween system");
#endif
}
}
}
public class MMFReadOnlyAttribute : PropertyAttribute { }
[System.AttributeUsage(System.AttributeTargets.Field)]
public class MMFInspectorButtonAttribute : PropertyAttribute
{
public readonly string MethodName;
public MMFInspectorButtonAttribute(string MethodName)
{
this.MethodName = MethodName;
}
}
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Class | AttributeTargets.Struct, Inherited = true)]
public class MMFEnumConditionAttribute : PropertyAttribute
{
public string ConditionEnum = "";
public bool Hidden = false;
BitArray bitArray = new BitArray(32);
public bool ContainsBitFlag(int enumValue)
{
return bitArray.Get(enumValue);
}
public MMFEnumConditionAttribute(string conditionBoolean, params int[] enumValues)
{
this.ConditionEnum = conditionBoolean;
this.Hidden = true;
for (int i = 0; i < enumValues.Length; i++)
{
bitArray.Set(enumValues[i], true);
}
}
}
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(MMFInspectorButtonAttribute))]
public class MMFInspectorButtonPropertyDrawer : PropertyDrawer
{
private MethodInfo _eventMethodInfo = null;
public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label)
{
MMFInspectorButtonAttribute inspectorButtonAttribute = (MMFInspectorButtonAttribute)attribute;
float buttonLength = position.width;
Rect buttonRect = new Rect(position.x + (position.width - buttonLength) * 0.5f, position.y, buttonLength, position.height);
if (GUI.Button(buttonRect, inspectorButtonAttribute.MethodName))
{
System.Type eventOwnerType = prop.serializedObject.targetObject.GetType();
string eventName = inspectorButtonAttribute.MethodName;
if (_eventMethodInfo == null)
{
_eventMethodInfo = eventOwnerType.GetMethod(eventName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
}
if (_eventMethodInfo != null)
{
_eventMethodInfo.Invoke(prop.serializedObject.targetObject, null);
}
else
{
Debug.LogWarning(string.Format("InspectorButton: Unable to find method {0} in {1}", eventName, eventOwnerType));
}
}
}
}
#endif
public class MMFInformationAttribute : PropertyAttribute
{
public enum InformationType { Error, Info, None, Warning }
#if UNITY_EDITOR
public string Message;
public MessageType Type;
public bool MessageAfterProperty;
public MMFInformationAttribute(string message, InformationType type, bool messageAfterProperty)
{
this.Message = message;
if (type == InformationType.Error) { this.Type = UnityEditor.MessageType.Error; }
if (type == InformationType.Info) { this.Type = UnityEditor.MessageType.Info; }
if (type == InformationType.Warning) { this.Type = UnityEditor.MessageType.Warning; }
if (type == InformationType.None) { this.Type = UnityEditor.MessageType.None; }
this.MessageAfterProperty = messageAfterProperty;
}
#else
public MMFInformationAttribute(string message, InformationType type, bool messageAfterProperty)
{
}
#endif
}
public class MMFHiddenAttribute : PropertyAttribute { }
[AttributeUsage(System.AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Class | AttributeTargets.Struct, Inherited = true)]
public class MMFConditionAttribute : PropertyAttribute
{
public string ConditionBoolean = "";
public bool Hidden = false;
public bool Negative = false;
public MMFConditionAttribute(string conditionBoolean)
{
this.ConditionBoolean = conditionBoolean;
this.Hidden = false;
this.Negative = false;
}
public MMFConditionAttribute(string conditionBoolean, bool hideInInspector)
{
this.ConditionBoolean = conditionBoolean;
this.Hidden = hideInInspector;
this.Negative = false;
}
public MMFConditionAttribute(string conditionBoolean, bool hideInInspector, bool negative)
{
this.ConditionBoolean = conditionBoolean;
this.Hidden = hideInInspector;
this.Negative = negative;
}
}
public class MMFVectorAttribute : PropertyAttribute
{
public readonly string[] Labels;
public MMFVectorAttribute(params string[] labels)
{
Labels = labels;
}
}
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(MMFVectorAttribute))]
public class MMVectorLabelsAttributeDrawer : PropertyDrawer
{
protected static readonly GUIContent[] originalLabels = new GUIContent[] { new GUIContent("X"), new GUIContent("Y"), new GUIContent("Z"), new GUIContent("W") };
protected const int padding = 375;
public override float GetPropertyHeight(SerializedProperty property, GUIContent guiContent)
{
int ratio = (padding > Screen.width) ? 2 : 1;
return ratio * base.GetPropertyHeight(property, guiContent);
}
public override void OnGUI(Rect rect, SerializedProperty property, GUIContent guiContent)
{
MMFVectorAttribute vector = (MMFVectorAttribute)attribute;
if (property.propertyType == SerializedPropertyType.Vector2)
{
float[] fieldArray = new float[] { property.vector2Value.x, property.vector2Value.y };
fieldArray = DrawFields(rect, fieldArray, ObjectNames.NicifyVariableName(property.name), EditorGUI.FloatField, vector, guiContent);
property.vector2Value = new Vector2(fieldArray[0], fieldArray[1]);
}
else if (property.propertyType == SerializedPropertyType.Vector3)
{
float[] fieldArray = new float[] { property.vector3Value.x, property.vector3Value.y, property.vector3Value.z };
fieldArray = DrawFields(rect, fieldArray, ObjectNames.NicifyVariableName(property.name), EditorGUI.FloatField, vector, guiContent);
property.vector3Value = new Vector3(fieldArray[0], fieldArray[1], fieldArray[2]);
}
else if (property.propertyType == SerializedPropertyType.Vector4)
{
float[] fieldArray = new float[] { property.vector4Value.x, property.vector4Value.y, property.vector4Value.z, property.vector4Value.w };
fieldArray = DrawFields(rect, fieldArray, ObjectNames.NicifyVariableName(property.name), EditorGUI.FloatField, vector, guiContent);
property.vector4Value = new Vector4(fieldArray[0], fieldArray[1], fieldArray[2]);
}
else if (property.propertyType == SerializedPropertyType.Vector2Int)
{
int[] fieldArray = new int[] { property.vector2IntValue.x, property.vector2IntValue.y };
fieldArray = DrawFields(rect, fieldArray, ObjectNames.NicifyVariableName(property.name), EditorGUI.IntField, vector, guiContent);
property.vector2IntValue = new Vector2Int(fieldArray[0], fieldArray[1]);
}
else if (property.propertyType == SerializedPropertyType.Vector3Int)
{
int[] array = new int[] { property.vector3IntValue.x, property.vector3IntValue.y, property.vector3IntValue.z };
array = DrawFields(rect, array, ObjectNames.NicifyVariableName(property.name), EditorGUI.IntField, vector, guiContent);
property.vector3IntValue = new Vector3Int(array[0], array[1], array[2]);
}
}
protected T[] DrawFields<T>(Rect rect, T[] vector, string mainLabel, System.Func<Rect, GUIContent, T, T> fieldDrawer, MMFVectorAttribute vectors, GUIContent originalGuiContent)
{
T[] result = vector;
bool shortSpace = (Screen.width < padding);
Rect mainLabelRect = rect;
mainLabelRect.width = EditorGUIUtility.labelWidth;
if (shortSpace)
{
mainLabelRect.height *= 0.5f;
}
Rect fieldRect = rect;
if (shortSpace)
{
fieldRect.height *= 0.5f;
fieldRect.y += fieldRect.height;
fieldRect.width = rect.width / vector.Length;
}
else
{
fieldRect.x += mainLabelRect.width;
fieldRect.width = (rect.width - mainLabelRect.width) / vector.Length;
}
GUIContent mainLabelContent = new GUIContent();
mainLabelContent.text = mainLabel;
mainLabelContent.tooltip = originalGuiContent.tooltip;
EditorGUI.LabelField(mainLabelRect, mainLabelContent);
for (int i = 0; i < vector.Length; i++)
{
GUIContent label = vectors.Labels.Length > i ? new GUIContent(vectors.Labels[i]) : originalLabels[i];
Vector2 labelSize = EditorStyles.label.CalcSize(label);
EditorGUIUtility.labelWidth = Mathf.Max(labelSize.x + 5, 0.3f * fieldRect.width);
result[i] = fieldDrawer(fieldRect, label, vector[i]);
fieldRect.x += fieldRect.width;
}
EditorGUIUtility.labelWidth = 0;
return result;
}
}
#endif
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public class MMFHiddenPropertiesAttribute : Attribute
{
public string[] PropertiesNames;
public MMFHiddenPropertiesAttribute(params string[] propertiesNames)
{
PropertiesNames = propertiesNames;
}
}
/// <summary>
/// An attribute used to group inspector fields under common dropdowns
/// Implementation inspired by Rodrigo Prinheiro's work, available at https://github.com/RodrigoPrinheiro/unityFoldoutAttribute
/// </summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Class | AttributeTargets.Struct, Inherited = true)]
public class MMFInspectorGroupAttribute : PropertyAttribute
{
public string GroupName;
public bool GroupAllFieldsUntilNextGroupAttribute;
public int GroupColorIndex;
public bool RequiresSetup;
public bool ClosedByDefault;
public MMFInspectorGroupAttribute(string groupName, bool groupAllFieldsUntilNextGroupAttribute = false, int groupColorIndex = 24, bool requiresSetup = false, bool closedByDefault = false)
{
if (groupColorIndex > 139) { groupColorIndex = 139; }
this.GroupName = groupName;
this.GroupAllFieldsUntilNextGroupAttribute = groupAllFieldsUntilNextGroupAttribute;
this.GroupColorIndex = groupColorIndex;
this.RequiresSetup = requiresSetup;
this.ClosedByDefault = closedByDefault;
}
}
[AttributeUsage(AttributeTargets.Field, AllowMultiple = true, Inherited = true)]
public class TmpAttribute : PropertyAttribute
{
/// <summary>
/// <para>The header text.</para>
/// </summary>
/// <footer><a href="https://docs.unity3d.com/2019.4/Documentation/ScriptReference/30_search.html?q=HeaderAttribute.header">`HeaderAttribute.header` on docs.unity3d.com</a></footer>
public readonly string header;
/// <summary>
/// <para>Add a header above some fields in the Inspector.</para>
/// </summary>
/// <param name="header">The header text.</param>
/// <footer><a href="https://docs.unity3d.com/2019.4/Documentation/ScriptReference/30_search.html?q=HeaderAttribute">`HeaderAttribute` on docs.unity3d.com</a></footer>
public TmpAttribute(string header) => this.header = header;
}
public static class MMFeedbackStaticMethods
{
static List<Component> m_ComponentCache = new List<Component>();
/// <summary>
/// Grabs a component without allocating memory uselessly
/// </summary>
/// <param name="this"></param>
/// <param name="componentType"></param>
/// <returns></returns>
public static Component GetComponentNoAlloc(this GameObject @this, System.Type componentType)
{
@this.GetComponents(componentType, m_ComponentCache);
var component = m_ComponentCache.Count > 0 ? m_ComponentCache[0] : null;
m_ComponentCache.Clear();
return component;
}
public static Type MMFGetTypeByName(string name)
{
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (Type type in assembly.GetTypes())
{
if (type.Name == name)
{
return type;
}
}
}
return null;
}
/// <summary>
/// Grabs a component without allocating memory uselessly
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="this"></param>
/// <returns></returns>
public static T MMFGetComponentNoAlloc<T>(this GameObject @this) where T : Component
{
@this.GetComponents(typeof(T), m_ComponentCache);
Component component = m_ComponentCache.Count > 0 ? m_ComponentCache[0] : null;
m_ComponentCache.Clear();
return component as T;
}
#if UNITY_EDITOR
/// <summary>
/// Returns the object value of a target serialized property
/// </summary>
/// <param name="property"></param>
/// <returns></returns>
public static object MMFGetObjectValue(this SerializedProperty property)
{
if (property == null)
{
return null;
}
string propertyPath = property.propertyPath.Replace(".Array.data[", "[");
object targetObject = property.serializedObject.targetObject;
var elements = propertyPath.Split('.');
foreach (var element in elements)
{
if (!element.Contains("["))
{
targetObject = MMFGetPropertyValue(targetObject, element);
}
else
{
string elementName = element.Substring(0, element.IndexOf("["));
int elementIndex = System.Convert.ToInt32(element.Substring(element.IndexOf("[")).Replace("[", "").Replace("]", ""));
targetObject = MMFGetPropertyValue(targetObject, elementName, elementIndex);
}
}
return targetObject;
}
private static object MMFGetPropertyValue(object source, string propertyName)
{
if (source == null)
{
return null;
}
Type propertyType = source.GetType();
while (propertyType != null)
{
FieldInfo fieldInfo = propertyType.GetField(propertyName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
if (fieldInfo != null)
{
return fieldInfo.GetValue(source);
}
PropertyInfo propertyInfo = propertyType.GetProperty(propertyName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.IgnoreCase | BindingFlags.Instance);
if (propertyInfo != null)
{
return propertyInfo.GetValue(source, null);
}
propertyType = propertyType.BaseType;
}
return null;
}
private static object MMFGetPropertyValue(object source, string propertyName, int index)
{
var enumerable = MMFGetPropertyValue(source, propertyName) as System.Collections.IEnumerable;
if (enumerable == null)
{
return null;
}
var enumerator = enumerable.GetEnumerator();
for (int i = 0; i <= index; i++)
{
if (!enumerator.MoveNext())
{
return null;
}
}
return enumerator.Current;
}
#endif
}
/// <summary>
/// Atttribute used to mark feedback class.
/// The provided path is used to sort the feedback list displayed in the feedback manager dropdown
/// </summary>
[System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public class FeedbackPathAttribute : System.Attribute
{
public string Path;
public string Name;
public FeedbackPathAttribute(string path)
{
Path = path;
Name = path.Split('/').Last();
}
static public string GetFeedbackDefaultName(System.Type type)
{
FeedbackPathAttribute attribute = type.GetCustomAttributes(false).OfType<FeedbackPathAttribute>().FirstOrDefault();
return attribute != null ? attribute.Name : type.Name;
}
static public string GetFeedbackDefaultPath(System.Type type)
{
FeedbackPathAttribute attribute = type.GetCustomAttributes(false).OfType<FeedbackPathAttribute>().FirstOrDefault();
return attribute != null ? attribute.Path : null;
}
}
/// <summary>
/// Atttribute used to mark feedback class.
/// The contents allow you to specify a help text for each feedback
/// </summary>
[System.AttributeUsage(System.AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public class FeedbackHelpAttribute : System.Attribute
{
public string HelpText;
public FeedbackHelpAttribute(string helpText)
{
HelpText = helpText;
}
static public string GetFeedbackHelpText(System.Type type)
{
FeedbackHelpAttribute attribute = type.GetCustomAttributes(false).OfType<FeedbackHelpAttribute>().FirstOrDefault();
return attribute != null ? attribute.HelpText : "";
}
}
public static class MMF_FieldInfo
{
public static Dictionary<int, List<FieldInfo>> FieldInfoList = new Dictionary<int, List<FieldInfo>>();
public static int GetFieldInfo(MMF_Feedback target, out List<FieldInfo> fieldInfoList)
{
Type targetType = target.GetType();
int targetTypeHashCode = targetType.GetHashCode();
if (!FieldInfoList.TryGetValue(targetTypeHashCode, out fieldInfoList))
{
IList<Type> typeTree = targetType.GetBaseTypes();
fieldInfoList = target.GetType().GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.NonPublic)
.OrderByDescending(x => typeTree.IndexOf(x.DeclaringType))
.ToList();
FieldInfoList.Add(targetTypeHashCode, fieldInfoList);
}
return fieldInfoList.Count;
}
public static int GetFieldInfo(UnityEngine.Object target, out List<FieldInfo> fieldInfoList)
{
Type targetType = target.GetType();
int targetTypeHashCode = targetType.GetHashCode();
if (!FieldInfoList.TryGetValue(targetTypeHashCode, out fieldInfoList))
{
IList<Type> typeTree = targetType.GetBaseTypes();
fieldInfoList = target.GetType().GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.NonPublic)
.OrderByDescending(x => typeTree.IndexOf(x.DeclaringType))
.ToList();
FieldInfoList.Add(targetTypeHashCode, fieldInfoList);
}
return fieldInfoList.Count;
}
public static IList<Type> GetBaseTypes(this Type t)
{
var types = new List<Type>();
while (t.BaseType != null)
{
types.Add(t);
t = t.BaseType;
}
return types;
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 0542c719094b3924cbee2c7229b1f4eb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Core/MMFeedbacksHelpers.cs
uploadId: 830868

View File

@@ -0,0 +1,34 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using MoreMountains.Feedbacks;
namespace MoreMountains.Feedbacks
{
public class MMFeedbacksInspectorColors : MonoBehaviour
{
public static Color32 GameObjectColor = new Color32(76, 174, 80, 255);
public static Color32 PostProcessColor = new Color32(254, 234, 59, 255);
public static Color32 RendererColor = new Color32(254, 151, 0, 255);
public static Color32 TransformColor = new Color32(134, 209, 243, 255);
public static Color32 CameraColor = new Color32(237, 0, 0, 255);
public static Color32 SoundsColor = new Color32(155, 39, 175, 255);
public static Color32 EventsColor = new Color32(232, 30, 99, 255);
public static Color32 SceneColor = new Color32(232, 30, 99, 255);
public static Color32 TimeColor = new Color32(240, 172, 172, 255);
public static Color32 LightColor = new Color32(254, 192, 7, 255);
public static Color32 ParticlesColor = new Color32(0, 149, 135, 255);
public static Color32 UIColor = new Color32(225, 2, 65, 255);
public static Color32 TMPColor = new Color32(135, 206, 250, 255);
public static Color32 HapticsColor = new Color32(61, 206, 250, 255);
public static Color32 FeedbacksColor = new Color32(105, 32, 133, 255);
public static Color32 AnimationColor = new Color32(200, 48, 128, 255);
public static Color32 SpringColor = new Color32(221, 230, 128, 255);
public static Color32 PauseColor = new Color32(98, 115, 0, 255);
public static Color32 HoldingPauseColor = new Color32(0, 114, 61, 255);
public static Color32 LooperColor = new Color32(12, 100, 128, 255);
public static Color32 DebugColor = new Color32(255, 0, 0, 255);
public static Color32 LooperStartColor = new Color32(166, 75, 5, 255);
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 97e6ede6fceb23f40805fef166a6f181
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Core/MMFeedbacksInspectorColors.cs
uploadId: 830868

View File

@@ -0,0 +1,395 @@
using System;
using MoreMountains.Tools;
using UnityEngine;
namespace MoreMountains.Feedbacks
{
public class MMShaker : MMMonoBehaviour
{
[MMInspectorGroup("Shaker Settings", true, 3)]
/// whether to listen on a channel defined by an int or by a MMChannel scriptable object. Ints are simple to setup but can get messy and make it harder to remember what int corresponds to what.
/// MMChannel scriptable objects require you to create them in advance, but come with a readable name and are more scalable
[Tooltip("whether to listen on a channel defined by an int or by a MMChannel scriptable object. Ints are simple to setup but can get messy and make it harder to remember what int corresponds to what. " +
"MMChannel scriptable objects require you to create them in advance, but come with a readable name and are more scalable")]
public MMChannelModes ChannelMode = MMChannelModes.Int;
/// the channel to listen to - has to match the one on the feedback
[Tooltip("the channel to listen to - has to match the one on the feedback")]
[MMEnumCondition("ChannelMode", (int)MMChannelModes.Int)]
public int Channel = 0;
/// the MMChannel definition asset to use to listen for events. The feedbacks targeting this shaker will have to reference that same MMChannel definition to receive events - to create a MMChannel,
/// right click anywhere in your project (usually in a Data folder) and go MoreMountains > MMChannel, then name it with some unique name
[Tooltip("the MMChannel definition asset to use to listen for events. The feedbacks targeting this shaker will have to reference that same MMChannel definition to receive events - to create a MMChannel, " +
"right click anywhere in your project (usually in a Data folder) and go MoreMountains > MMChannel, then name it with some unique name")]
[MMEnumCondition("ChannelMode", (int)MMChannelModes.MMChannel)]
public MMChannel MMChannelDefinition = null;
/// the duration of the shake, in seconds
[Tooltip("the duration of the shake, in seconds")]
public float ShakeDuration = 0.2f;
/// if this is true this shaker will play on awake
[Tooltip("if this is true this shaker will play on awake")]
public bool PlayOnAwake = false;
/// if this is true, the shaker will shake permanently as long as its game object is active
[Tooltip("if this is true, the shaker will shake permanently as long as its game object is active")]
public bool PermanentShake = false;
/// if this is true, a new shake can happen while shaking
[Tooltip("if this is true, a new shake can happen while shaking")]
public bool Interruptible = true;
/// if this is true, this shaker will always reset target values, regardless of how it was called
[Tooltip("if this is true, this shaker will always reset target values, regardless of how it was called")]
public bool AlwaysResetTargetValuesAfterShake = false;
/// if this is true, this shaker will ignore any value passed in an event that triggered it, and will instead use the values set on its inspector
[Tooltip("if this is true, this shaker will ignore any value passed in an event that triggered it, and will instead use the values set on its inspector")]
public bool OnlyUseShakerValues = false;
/// a cooldown, in seconds, after a shake, during which no other shake can start
[Tooltip("a cooldown, in seconds, after a shake, during which no other shake can start")]
public float CooldownBetweenShakes = 0f;
/// whether or not this shaker is shaking right now
[Tooltip("whether or not this shaker is shaking right now")]
[MMFReadOnly]
public bool Shaking = false;
[HideInInspector]
public bool ForwardDirection = true;
[HideInInspector]
public TimescaleModes TimescaleMode = TimescaleModes.Scaled;
public virtual float GetTime() { return (TimescaleMode == TimescaleModes.Scaled) ? Time.time : Time.unscaledTime; }
public virtual float GetDeltaTime() { return (TimescaleMode == TimescaleModes.Scaled) ? Time.deltaTime : Time.unscaledDeltaTime; }
public virtual MMChannelData ChannelData => new MMChannelData(ChannelMode, Channel, MMChannelDefinition);
public virtual bool ListeningToEvents => _listeningToEvents;
[HideInInspector]
internal bool _listeningToEvents = false;
protected float _shakeStartedTimestamp = -Single.MaxValue;
protected float _shakeStartedTimestampUnscaled = -Single.MaxValue;
protected float _remappedTimeSinceStart;
protected bool _resetShakerValuesAfterShake;
protected bool _resetTargetValuesAfterShake;
protected float _journey;
/// <summary>
/// On Awake we grab our volume and profile
/// </summary>
protected virtual void Awake()
{
Initialization();
// in case someone else trigger StartListening before Awake
if (!_listeningToEvents)
{
StartListening();
}
Shaking = PlayOnAwake;
this.enabled = PlayOnAwake;
}
/// <summary>
/// Override this method to initialize your shaker
/// </summary>
protected virtual void Initialization()
{
}
/// <summary>
/// Call this externally if you need to force a new initialization
/// </summary>
public virtual void ForceInitialization()
{
Initialization();
}
/// <summary>
/// Starts shaking the values
/// </summary>
public virtual void StartShaking()
{
_journey = ForwardDirection ? 0f : ShakeDuration;
if (InCooldown)
{
return;
}
if (Shaking)
{
return;
}
else
{
this.enabled = true;
SetShakeStartedTimestamp();
Shaking = true;
GrabInitialValues();
ShakeStarts();
}
}
/// <summary>
/// Logs the start timestamp for this shaker
/// </summary>
protected virtual void SetShakeStartedTimestamp()
{
if (TimescaleMode == TimescaleModes.Scaled)
{
_shakeStartedTimestamp = GetTime();
}
else
{
_shakeStartedTimestampUnscaled = GetTime();
}
}
/// <summary>
/// Describes what happens when a shake starts
/// </summary>
protected virtual void ShakeStarts()
{
}
/// <summary>
/// A method designed to collect initial values
/// </summary>
protected virtual void GrabInitialValues()
{
}
/// <summary>
/// On Update, we shake our values if needed, or reset if our shake has ended
/// </summary>
protected virtual void Update()
{
if (Shaking || PermanentShake)
{
Shake();
_journey += ForwardDirection ? GetDeltaTime() : -GetDeltaTime();
}
if (Shaking && !PermanentShake && ((_journey < 0) || (_journey > ShakeDuration)))
{
Shaking = false;
ShakeComplete();
}
if (PermanentShake)
{
if (_journey < 0)
{
_journey = ShakeDuration;
}
if (_journey > ShakeDuration)
{
_journey = 0;
}
}
}
/// <summary>
/// Override this method to implement shake over time
/// </summary>
protected virtual void Shake()
{
}
/// <summary>
/// A method used to "shake" a flot over time along a curve
/// </summary>
/// <param name="curve"></param>
/// <param name="remapMin"></param>
/// <param name="remapMax"></param>
/// <param name="relativeIntensity"></param>
/// <param name="initialValue"></param>
/// <returns></returns>
protected virtual float ShakeFloat(AnimationCurve curve, float remapMin, float remapMax, bool relativeIntensity, float initialValue)
{
float newValue = 0f;
float remappedTime = MMFeedbacksHelpers.Remap(_journey, 0f, ShakeDuration, 0f, 1f);
float curveValue = curve.Evaluate(remappedTime);
newValue = MMFeedbacksHelpers.Remap(curveValue, 0f, 1f, remapMin, remapMax);
if (relativeIntensity)
{
newValue += initialValue;
}
return newValue;
}
protected virtual Color ShakeGradient(Gradient gradient)
{
float remappedTime = MMFeedbacksHelpers.Remap(_journey, 0f, ShakeDuration, 0f, 1f);
return gradient.Evaluate(remappedTime);
}
/// <summary>
/// Resets the values on the target
/// </summary>
protected virtual void ResetTargetValues()
{
}
/// <summary>
/// Resets the values on the shaker
/// </summary>
protected virtual void ResetShakerValues()
{
}
/// <summary>
/// Describes what happens when the shake is complete
/// </summary>
protected virtual void ShakeComplete()
{
_journey = ForwardDirection ? ShakeDuration : 0f;
Shake();
if (_resetTargetValuesAfterShake || AlwaysResetTargetValuesAfterShake)
{
ResetTargetValues();
}
if (_resetShakerValuesAfterShake)
{
ResetShakerValues();
}
this.enabled = false;
}
/// <summary>
/// On enable we start shaking if needed
/// </summary>
protected virtual void OnEnable()
{
StartShaking();
}
/// <summary>
/// On destroy we stop listening for events
/// </summary>
protected virtual void OnDestroy()
{
StopListening();
}
/// <summary>
/// On disable we complete our shake if it was in progress
/// </summary>
protected virtual void OnDisable()
{
if (Shaking)
{
ShakeComplete();
}
}
/// <summary>
/// Starts this shaker
/// </summary>
public virtual void Play()
{
if (InCooldown)
{
return;
}
this.enabled = true;
}
/// <summary>
/// Stops this shaker
/// </summary>
public virtual void Stop()
{
Shaking = false;
ShakeComplete();
}
/// <summary>
/// Starts listening for events
/// </summary>
public virtual void StartListening()
{
_listeningToEvents = true;
}
/// <summary>
/// Stops listening for events
/// </summary>
public virtual void StopListening()
{
_listeningToEvents = false;
}
/// <summary>
/// Returns true if this shaker should listen to events, false otherwise
/// </summary>
/// <param name="channel"></param>
/// <returns></returns>
protected virtual bool CheckEventAllowed(MMChannelData channelData, bool useRange = false, float range = 0f, Vector3 eventOriginPosition = default(Vector3))
{
if (!MMChannel.Match(channelData, ChannelMode, Channel, MMChannelDefinition))
{
return false;
}
if (!this.gameObject.activeInHierarchy)
{
return false;
}
else
{
if (useRange)
{
if (Vector3.Distance(this.transform.position, eventOriginPosition) > range)
{
return false;
}
}
return true;
}
}
/// <summary>
/// Returns true if this shaker is currently in cooldown, false otherwise
/// </summary>
public virtual bool InCooldown
{
get
{
float startedTimeStamp = TimescaleMode == TimescaleModes.Scaled ? _shakeStartedTimestamp : _shakeStartedTimestampUnscaled;
float test = GetTime() - startedTimeStamp;
return (GetTime() - startedTimeStamp < CooldownBetweenShakes);
}
}
public virtual float ComputeRangeIntensity(bool useRange, float rangeDistance, bool useRangeFalloff, AnimationCurve rangeFalloff, Vector2 remapRangeFalloff, Vector3 rangePosition)
{
if (!useRange)
{
return 1f;
}
float distanceToCenter = Vector3.Distance(rangePosition, this.transform.position);
if (distanceToCenter > rangeDistance)
{
return 0f;
}
if (!useRangeFalloff)
{
return 1f;
}
float normalizedDistance = MMMaths.Remap(distanceToCenter, 0f, rangeDistance, 0f, 1f);
float curveValue = rangeFalloff.Evaluate(normalizedDistance);
float newIntensity = MMMaths.Remap(curveValue, 0f, 1f, remapRangeFalloff.x, remapRangeFalloff.y);
return newIntensity;
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 25d31bbce27b6524192fba29ccfe28df
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Core/MMShaker.cs
uploadId: 830868

View File

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

View File

@@ -0,0 +1,237 @@
using System.Collections.Generic;
using MoreMountains.Tools;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace MoreMountains.Feedbacks
{
public class MMMiniObjectPooler : MonoBehaviour
{
/// the game object we'll instantiate
public GameObject GameObjectToPool;
/// the number of objects we'll add to the pool
public int PoolSize = 20;
/// if true, the pool will automatically add objects to the itself if needed
public bool PoolCanExpand = true;
/// if this is true, the pool will try not to create a new waiting pool if it finds one with the same name.
public bool MutualizeWaitingPools = false;
/// if this is true, all waiting and active objects will be regrouped under an empty game object. Otherwise they'll just be at top level in the hierarchy
public bool NestWaitingPool = true;
/// this object is just used to group the pooled objects
protected GameObject _waitingPool = null;
protected MMMiniObjectPool _objectPool;
protected const int _initialPoolsListCapacity = 5;
static List<MMMiniObjectPool> _pools = new List<MMMiniObjectPool>(_initialPoolsListCapacity);
/// <summary>
/// Adds a pooler to the static list if needed
/// </summary>
/// <param name="pool"></param>
public static void AddPool(MMMiniObjectPool pool)
{
if (_pools == null)
{
_pools = new List<MMMiniObjectPool>(_initialPoolsListCapacity);
}
if (!_pools.Contains(pool))
{
_pools.Add(pool);
}
}
/// <summary>
/// Removes a pooler from the static list
/// </summary>
/// <param name="pool"></param>
public static void RemovePool(MMMiniObjectPool pool)
{
_pools?.Remove(pool);
}
/// <summary>
/// On awake we fill our object pool
/// </summary>
protected virtual void Awake()
{
FillObjectPool();
}
/// <summary>
/// On Destroy we remove ourselves from the list of poolers
/// </summary>
private void OnDestroy()
{
if (_objectPool != null)
{
RemovePool(_objectPool);
}
}
/// <summary>
/// Looks for an existing pooler for the same object, returns it if found, returns null otherwise
/// </summary>
/// <param name="objectToPool"></param>
/// <returns></returns>
public virtual MMMiniObjectPool ExistingPool(string poolName)
{
if (_pools == null)
{
_pools = new List<MMMiniObjectPool>(_initialPoolsListCapacity);
}
if (_pools.Count == 0)
{
var pools = FindObjectsByType<MMMiniObjectPool>(FindObjectsSortMode.None);
if (pools.Length > 0)
{
_pools.AddRange(pools);
}
}
foreach (MMMiniObjectPool pool in _pools)
{
if ((pool != null) && (pool.name == poolName)/* && (pool.gameObject.scene == this.gameObject.scene)*/)
{
return pool;
}
}
return null;
}
/// <summary>
/// Creates the waiting pool or tries to reuse one if there's already one available
/// </summary>
protected virtual void CreateWaitingPool()
{
if (!MutualizeWaitingPools)
{
// we create a container that will hold all the instances we create
_objectPool = this.gameObject.AddComponent<MMMiniObjectPool>();
_objectPool.PooledGameObjects = new List<GameObject>();
return;
}
else
{
MMMiniObjectPool waitingPool = ExistingPool(DetermineObjectPoolName(GameObjectToPool));
if (waitingPool != null)
{
_waitingPool = waitingPool.gameObject;
_objectPool = waitingPool;
}
else
{
GameObject newPool = new GameObject();
newPool.name = DetermineObjectPoolName(GameObjectToPool);
SceneManager.MoveGameObjectToScene(newPool, this.gameObject.scene);
_objectPool = newPool.AddComponent<MMMiniObjectPool>();
_objectPool.PooledGameObjects = new List<GameObject>();
AddPool(_objectPool);
}
}
}
/// <summary>
/// Determines the name of the object pool.
/// </summary>
/// <returns>The object pool name.</returns>
public static string DetermineObjectPoolName(GameObject gameObjectToPool)
{
return (gameObjectToPool.name + "_pool");
}
/// <summary>
/// Implement this method to fill the pool with objects
/// </summary>
public virtual void FillObjectPool()
{
if (GameObjectToPool == null)
{
return;
}
CreateWaitingPool();
int objectsToSpawn = PoolSize;
if (_objectPool != null)
{
objectsToSpawn -= _objectPool.PooledGameObjects.Count;
}
// we add to the pool the specified number of objects
for (int i = 0; i < objectsToSpawn; i++)
{
AddOneObjectToThePool();
}
}
/// <summary>
/// Implement this method to return a gameobject
/// </summary>
/// <returns>The pooled game object.</returns>
public virtual GameObject GetPooledGameObject()
{
// we go through the pool looking for an inactive object
for (int i = 0; i < _objectPool.PooledGameObjects.Count; i++)
{
if (!_objectPool.PooledGameObjects[i].gameObject.activeInHierarchy)
{
// if we find one, we return it
return _objectPool.PooledGameObjects[i];
}
}
// if we haven't found an inactive object (the pool is empty), and if we can extend it, we add one new object to the pool, and return it
if (PoolCanExpand)
{
return AddOneObjectToThePool();
}
// if the pool is empty and can't grow, we return nothing.
return null;
}
/// <summary>
/// Adds one object of the specified type (in the inspector) to the pool.
/// </summary>
/// <returns>The one object to the pool.</returns>
protected virtual GameObject AddOneObjectToThePool()
{
if (GameObjectToPool == null)
{
Debug.LogWarning("The " + gameObject.name + " ObjectPooler doesn't have any GameObjectToPool defined.", gameObject);
return null;
}
GameObject newGameObject = (GameObject)MMGameObjectExtensions.MMInstantiateDisabled(GameObjectToPool);
SceneManager.MoveGameObjectToScene(newGameObject, this.gameObject.scene);
if (NestWaitingPool)
{
newGameObject.transform.SetParent(_objectPool.transform);
}
newGameObject.name = GameObjectToPool.name + "-" + _objectPool.PooledGameObjects.Count;
_objectPool.PooledGameObjects.Add(newGameObject);
return newGameObject;
}
/// <summary>
/// Destroys the object pool
/// </summary>
public virtual void DestroyObjectPool()
{
if (_waitingPool != null)
{
Destroy(_waitingPool.gameObject);
}
}
}
public class MMMiniObjectPool : MonoBehaviour
{
[MMFReadOnly]
public List<GameObject> PooledGameObjects;
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 5a2e3aab8bd306249afbd26c52205f46
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Core/ObjectPool/MMMiniObjectPooler.cs
uploadId: 830868

View File

@@ -0,0 +1,58 @@
using UnityEngine;
using System.Collections;
using MoreMountains.Feedbacks;
using System;
namespace MoreMountains.Feedbacks
{
/// <summary>
/// Add this class to an object that you expect to pool from an objectPooler.
/// Note that these objects can't be destroyed by calling Destroy(), they'll just be set inactive (that's the whole point).
/// </summary>
public class MMMiniPoolableObject : MonoBehaviour
{
public delegate void Events();
public event Events OnSpawnComplete;
/// The life time, in seconds, of the object. If set to 0 it'll live forever, if set to any positive value it'll be set inactive after that time.
public float LifeTime = 0f;
/// <summary>
/// Turns the instance inactive, in order to eventually reuse it.
/// </summary>
public virtual void Destroy()
{
gameObject.SetActive(false);
}
/// <summary>
/// When the objects get enabled (usually after having been pooled from an ObjectPooler, we initiate its death countdown.
/// </summary>
protected virtual void OnEnable()
{
if (LifeTime > 0)
{
Invoke("Destroy", LifeTime);
}
}
/// <summary>
/// When the object gets disabled (maybe it got out of bounds), we cancel its programmed death
/// </summary>
protected virtual void OnDisable()
{
CancelInvoke();
}
/// <summary>
/// Triggers the on spawn complete event
/// </summary>
public virtual void TriggerOnSpawnComplete()
{
if(OnSpawnComplete != null)
{
OnSpawnComplete();
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: b0b3f00a75cc857439b13b8bafb37894
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Core/ObjectPool/MMMiniPoolableObject.cs
uploadId: 830868

View File

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

View File

@@ -0,0 +1,345 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Scripting.APIUpdating;
namespace MoreMountains.Feedbacks
{
/// <summary>
/// A feedback used to trigger an animation (bool, int, float or trigger) on the associated animator, with or without randomness
/// </summary>
[AddComponentMenu("")]
[FeedbackHelp("This feedback will allow you to send to an animator (bound in its inspector) a bool, int, float or trigger parameter, allowing you to trigger an animation, with or without randomness.")]
[MovedFrom(false, null, "MoreMountains.Feedbacks")]
[System.Serializable]
[FeedbackPath("Animation/Animation Parameter")]
public class MMF_Animation : MMF_Feedback
{
/// a static bool used to disable all feedbacks of this type at once
public static bool FeedbackTypeAuthorized = true;
/// the possible modes that pilot triggers
public enum TriggerModes { SetTrigger, ResetTrigger }
/// the possible ways to set a value
public enum ValueModes { None, Constant, Random, Incremental }
/// sets the inspector color for this feedback
#if UNITY_EDITOR
public override Color FeedbackColor { get { return MMFeedbacksInspectorColors.AnimationColor; } }
public override bool EvaluateRequiresSetup() { return (BoundAnimator == null); }
public override string RequiredTargetText { get { return BoundAnimator != null ? BoundAnimator.name : ""; } }
public override string RequiresSetupText { get { return "This feedback requires that a BoundAnimator be set to be able to work properly. You can set one below."; } }
#endif
/// the duration of this feedback is the declared duration
public override float FeedbackDuration { get { return ApplyTimeMultiplier(DeclaredDuration); } set { DeclaredDuration = value; } }
public override bool HasRandomness => true;
public override bool HasAutomatedTargetAcquisition => true;
protected override void AutomateTargetAcquisition() => BoundAnimator = FindAutomatedTarget<Animator>();
[MMFInspectorGroup("Animation", true, 12, true)]
/// the animator whose parameters you want to update
[Tooltip("the animator whose parameters you want to update")]
public Animator BoundAnimator;
/// the list of extra animators whose parameters you want to update
[Tooltip("the list of extra animators whose parameters you want to update")]
public List<Animator> ExtraBoundAnimators;
/// the duration for the player to consider. This won't impact your animation, but is a way to communicate to the MMF Player the duration of this feedback. Usually you'll want it to match your actual animation, and setting it can be useful to have this feedback work with holding pauses.
[Tooltip("the duration for the player to consider. This won't impact your animation, but is a way to communicate to the MMF Player the duration of this feedback. Usually you'll want it to match your actual animation, and setting it can be useful to have this feedback work with holding pauses.")]
public float DeclaredDuration = 0f;
[MMFInspectorGroup("Trigger", true, 16)]
/// if this is true, will update the specified trigger parameter
[Tooltip("if this is true, will update the specified trigger parameter")]
public bool UpdateTrigger = false;
/// the selected mode to interact with this trigger
[Tooltip("the selected mode to interact with this trigger")]
[MMFCondition("UpdateTrigger", true)]
public TriggerModes TriggerMode = TriggerModes.SetTrigger;
/// the trigger animator parameter to, well, trigger when the feedback is played
[Tooltip("the trigger animator parameter to, well, trigger when the feedback is played")]
[MMFCondition("UpdateTrigger", true)]
public string TriggerParameterName;
[MMFInspectorGroup("Random Trigger", true, 20)]
/// if this is true, will update a random trigger parameter, picked from the list below
[Tooltip("if this is true, will update a random trigger parameter, picked from the list below")]
public bool UpdateRandomTrigger = false;
/// the selected mode to interact with this trigger
[Tooltip("the selected mode to interact with this trigger")]
[MMFCondition("UpdateRandomTrigger", true)]
public TriggerModes RandomTriggerMode = TriggerModes.SetTrigger;
/// the trigger animator parameters to trigger at random when the feedback is played
[Tooltip("the trigger animator parameters to trigger at random when the feedback is played")]
public List<string> RandomTriggerParameterNames;
[MMFInspectorGroup("Bool", true, 17)]
/// if this is true, will update the specified bool parameter
[Tooltip("if this is true, will update the specified bool parameter")]
public bool UpdateBool = false;
/// the bool parameter to turn true when the feedback gets played
[Tooltip("the bool parameter to turn true when the feedback gets played")]
[MMFCondition("UpdateBool", true)]
public string BoolParameterName;
/// when in bool mode, whether to set the bool parameter to true or false
[Tooltip("when in bool mode, whether to set the bool parameter to true or false")]
[MMFCondition("UpdateBool", true)]
public bool BoolParameterValue = true;
[MMFInspectorGroup("Random Bool", true, 19)]
/// if this is true, will update a random bool parameter picked from the list below
[Tooltip("if this is true, will update a random bool parameter picked from the list below")]
public bool UpdateRandomBool = false;
/// when in bool mode, whether to set the bool parameter to true or false
[Tooltip("when in bool mode, whether to set the bool parameter to true or false")]
[MMFCondition("UpdateRandomBool", true)]
public bool RandomBoolParameterValue = true;
/// the bool parameter to turn true when the feedback gets played
[Tooltip("the bool parameter to turn true when the feedback gets played")]
public List<string> RandomBoolParameterNames;
[MMFInspectorGroup("Int", true, 24)]
/// the int parameter to turn true when the feedback gets played
[Tooltip("the int parameter to turn true when the feedback gets played")]
public ValueModes IntValueMode = ValueModes.None;
/// the int parameter to turn true when the feedback gets played
[Tooltip("the int parameter to turn true when the feedback gets played")]
[MMFEnumCondition("IntValueMode", (int)ValueModes.Constant, (int)ValueModes.Random, (int)ValueModes.Incremental)]
public string IntParameterName;
/// the value to set to that int parameter
[Tooltip("the value to set to that int parameter")]
[MMFEnumCondition("IntValueMode", (int)ValueModes.Constant)]
public int IntValue;
/// the min value (inclusive) to set at random to that int parameter
[Tooltip("the min value (inclusive) to set at random to that int parameter")]
[MMFEnumCondition("IntValueMode", (int)ValueModes.Random)]
public int IntValueMin;
/// the max value (exclusive) to set at random to that int parameter
[Tooltip("the max value (exclusive) to set at random to that int parameter")]
[MMFEnumCondition("IntValueMode", (int)ValueModes.Random)]
public int IntValueMax = 5;
/// the value to increment that int parameter by
[Tooltip("the value to increment that int parameter by")]
[MMFEnumCondition("IntValueMode", (int)ValueModes.Incremental)]
public int IntIncrement = 1;
[MMFInspectorGroup("Float", true, 22)]
/// the Float parameter to turn true when the feedback gets played
[Tooltip("the Float parameter to turn true when the feedback gets played")]
public ValueModes FloatValueMode = ValueModes.None;
/// the float parameter to turn true when the feedback gets played
[Tooltip("the float parameter to turn true when the feedback gets played")]
[MMFEnumCondition("FloatValueMode", (int)ValueModes.Constant, (int)ValueModes.Random, (int)ValueModes.Incremental)]
public string FloatParameterName;
/// the value to set to that float parameter
[Tooltip("the value to set to that float parameter")]
[MMFEnumCondition("FloatValueMode", (int)ValueModes.Constant)]
public float FloatValue;
/// the min value (inclusive) to set at random to that float parameter
[Tooltip("the min value (inclusive) to set at random to that float parameter")]
[MMFEnumCondition("FloatValueMode", (int)ValueModes.Random)]
public float FloatValueMin;
/// the max value (exclusive) to set at random to that float parameter
[Tooltip("the max value (exclusive) to set at random to that float parameter")]
[MMFEnumCondition("FloatValueMode", (int)ValueModes.Random)]
public float FloatValueMax = 5;
/// the value to increment that float parameter by
[Tooltip("the value to increment that float parameter by")]
[MMFEnumCondition("FloatValueMode", (int)ValueModes.Incremental)]
public float FloatIncrement = 1;
[MMFInspectorGroup("Layer Weights", true, 22)]
/// whether or not to set layer weights on the specified layer when playing this feedback
[Tooltip("whether or not to set layer weights on the specified layer when playing this feedback")]
public bool SetLayerWeight = false;
/// the index of the layer to target when changing layer weights
[Tooltip("the index of the layer to target when changing layer weights")]
[MMFCondition("SetLayerWeight", true)]
public int TargetLayerIndex = 1;
/// the name of the Animator layer you want the layer weight change to occur on. This is optional. If left empty, the layer ID above will be used, if not empty, the Layer id specified above will be ignored.
[Tooltip("the name of the Animator layer you want the layer weight change to occur on. This is optional. If left empty, the layer ID above will be used, if not empty, the Layer id specified above will be ignored.")]
public string LayerName = "";
/// the new weight to set on the target animator layer
[Tooltip("the new weight to set on the target animator layer")]
[MMFCondition("SetLayerWeight", true)]
public float NewWeight = 0.5f;
protected int _triggerParameter;
protected int _boolParameter;
protected int _intParameter;
protected int _floatParameter;
protected List<int> _randomTriggerParameters;
protected List<int> _randomBoolParameters;
protected int _layerID;
/// <summary>
/// Custom Init
/// </summary>
/// <param name="owner"></param>
protected override void CustomInitialization(MMF_Player owner)
{
base.CustomInitialization(owner);
_triggerParameter = Animator.StringToHash(TriggerParameterName);
_boolParameter = Animator.StringToHash(BoolParameterName);
_intParameter = Animator.StringToHash(IntParameterName);
_floatParameter = Animator.StringToHash(FloatParameterName);
if (RandomTriggerParameterNames == null)
{
RandomTriggerParameterNames = new List<string>();
}
if (RandomBoolParameterNames == null)
{
RandomBoolParameterNames = new List<string>();
}
_randomTriggerParameters = new List<int>();
foreach (string name in RandomTriggerParameterNames)
{
_randomTriggerParameters.Add(Animator.StringToHash(name));
}
_randomBoolParameters = new List<int>();
foreach (string name in RandomBoolParameterNames)
{
_randomBoolParameters.Add(Animator.StringToHash(name));
}
_layerID = TargetLayerIndex;
if ((LayerName != "") && (BoundAnimator != null))
{
_layerID = BoundAnimator.GetLayerIndex(LayerName);
}
}
/// <summary>
/// On Play, checks if an animator is bound and triggers parameters
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
if (BoundAnimator == null)
{
Debug.LogWarning("[Animation Feedback] The animation feedback on "+Owner.name+" doesn't have a BoundAnimator, it won't work. You need to specify one in its inspector.");
return;
}
float intensityMultiplier = ComputeIntensity(feedbacksIntensity, position);
ApplyValue(BoundAnimator, intensityMultiplier);
foreach (Animator animator in ExtraBoundAnimators)
{
ApplyValue(animator, intensityMultiplier);
}
}
/// <summary>
/// Applies values on the target Animator
/// </summary>
/// <param name="targetAnimator"></param>
/// <param name="intensityMultiplier"></param>
protected virtual void ApplyValue(Animator targetAnimator, float intensityMultiplier)
{
if (UpdateTrigger)
{
if (TriggerMode == TriggerModes.SetTrigger)
{
targetAnimator.SetTrigger(_triggerParameter);
}
if (TriggerMode == TriggerModes.ResetTrigger)
{
targetAnimator.ResetTrigger(_triggerParameter);
}
}
if (UpdateRandomTrigger)
{
int randomParameter = _randomTriggerParameters[Random.Range(0, _randomTriggerParameters.Count)];
if (RandomTriggerMode == TriggerModes.SetTrigger)
{
targetAnimator.SetTrigger(randomParameter);
}
if (RandomTriggerMode == TriggerModes.ResetTrigger)
{
targetAnimator.ResetTrigger(randomParameter);
}
}
if (UpdateBool)
{
targetAnimator.SetBool(_boolParameter, BoolParameterValue);
}
if (UpdateRandomBool)
{
int randomParameter = _randomBoolParameters[Random.Range(0, _randomBoolParameters.Count)];
targetAnimator.SetBool(randomParameter, RandomBoolParameterValue);
}
switch (IntValueMode)
{
case ValueModes.Constant:
targetAnimator.SetInteger(_intParameter, IntValue);
break;
case ValueModes.Incremental:
int newValue = targetAnimator.GetInteger(_intParameter) + IntIncrement;
targetAnimator.SetInteger(_intParameter, newValue);
break;
case ValueModes.Random:
int randomValue = Random.Range(IntValueMin, IntValueMax);
targetAnimator.SetInteger(_intParameter, randomValue);
break;
}
switch (FloatValueMode)
{
case ValueModes.Constant:
targetAnimator.SetFloat(_floatParameter, FloatValue * intensityMultiplier);
break;
case ValueModes.Incremental:
float newValue = targetAnimator.GetFloat(_floatParameter) + FloatIncrement * intensityMultiplier;
targetAnimator.SetFloat(_floatParameter, newValue);
break;
case ValueModes.Random:
float randomValue = Random.Range(FloatValueMin, FloatValueMax) * intensityMultiplier;
targetAnimator.SetFloat(_floatParameter, randomValue);
break;
}
if (SetLayerWeight)
{
targetAnimator.SetLayerWeight(_layerID, NewWeight);
}
}
/// <summary>
/// On stop, turns the bool parameter to false
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomStopFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !UpdateBool || !FeedbackTypeAuthorized)
{
return;
}
BoundAnimator.SetBool(_boolParameter, false);
foreach (Animator animator in ExtraBoundAnimators)
{
animator.SetBool(_boolParameter, false);
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 88367c53ef5132e4c9df08d23e92c06d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Feedbacks/MMF_Animation.cs
uploadId: 830868

View File

@@ -0,0 +1,163 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Scripting.APIUpdating;
namespace MoreMountains.Feedbacks
{
/// <summary>
/// A feedback used to trigger an animation (bool, int, float or trigger) on the associated animator, with or without randomness
/// </summary>
[AddComponentMenu("")]
[FeedbackHelp("This feedback will allow you to cross fade a target Animator to the specified state.")]
[MovedFrom(false, null, "MoreMountains.Feedbacks")]
[System.Serializable]
[FeedbackPath("Animation/Animation Crossfade")]
public class MMF_AnimationCrossfade : MMF_Feedback
{
/// a static bool used to disable all feedbacks of this type at once
public static bool FeedbackTypeAuthorized = true;
/// the possible modes that pilot triggers
public enum TriggerModes { SetTrigger, ResetTrigger }
/// the possible ways to set a value
public enum ValueModes { None, Constant, Random, Incremental }
/// sets the inspector color for this feedback
#if UNITY_EDITOR
public override Color FeedbackColor { get { return MMFeedbacksInspectorColors.AnimationColor; } }
public override bool EvaluateRequiresSetup() { return (BoundAnimator == null); }
public override string RequiredTargetText { get { return BoundAnimator != null ? BoundAnimator.name : ""; } }
public override string RequiresSetupText { get { return "This feedback requires that a BoundAnimator be set to be able to work properly. You can set one below."; } }
#endif
/// the duration of this feedback is the declared duration
public override float FeedbackDuration { get { return ApplyTimeMultiplier(DeclaredDuration); } set { DeclaredDuration = value; } }
public override bool HasRandomness => true;
public override bool HasAutomatedTargetAcquisition => true;
protected override void AutomateTargetAcquisition() => BoundAnimator = FindAutomatedTarget<Animator>();
public enum Modes { Seconds, Normalized }
[MMFInspectorGroup("Animation", true, 12, true)]
/// the animator whose parameters you want to update
[Tooltip("the animator whose parameters you want to update")]
public Animator BoundAnimator;
/// the list of extra animators whose parameters you want to update
[Tooltip("the list of extra animators whose parameters you want to update")]
public List<Animator> ExtraBoundAnimators;
/// the duration for the player to consider. This won't impact your animation, but is a way to communicate to the MMF Player the duration of this feedback. Usually you'll want it to match your actual animation, and setting it can be useful to have this feedback work with holding pauses.
[Tooltip("the duration for the player to consider. This won't impact your animation, but is a way to communicate to the MMF Player the duration of this feedback. Usually you'll want it to match your actual animation, and setting it can be useful to have this feedback work with holding pauses.")]
public float DeclaredDuration = 0f;
[MMFInspectorGroup("CrossFade", true, 16)]
/// the name of the state towards which to transition. That's the name of the yellow or gray box in your Animator
[Tooltip("the name of the state towards which to transition. That's the name of the yellow or gray box in your Animator")]
public string StateName = "NewState";
/// an optional list of names of state towards which to transition. If left empty, StateName above will be used. If filled, a random state will be chosen from this list, ignoring the StateName specified above
[Tooltip("an optional list of names of state towards which to transition. If left empty, StateName above will be used. If filled, a random state will be chosen from this list, ignoring the StateName specified above")]
public List<string> RandomStateNames = new List<string>();
/// the ID of the Animator layer you want the crossfade to occur on
[Tooltip("the ID of the Animator layer you want the crossfade to occur on")]
public int Layer = -1;
/// the name of the Animator layer you want the crossfade to occur on. This is optional. If left empty, the layer ID above will be used, if not empty, the Layer id specified above will be ignored.
[Tooltip("the name of the Animator layer you want the crossfade to occur on. This is optional. If left empty, the layer ID above will be used, if not empty, the Layer id specified above will be ignored.")]
public string LayerName = "";
/// whether to specify timing data for the crossfade in seconds or in normalized (0-1) values
[Tooltip("whether to specify timing data for the crossfade in seconds or in normalized (0-1) values")]
public Modes Mode = Modes.Seconds;
/// in Seconds mode, the duration of the transition, in seconds
[Tooltip("in Seconds mode, the duration of the transition, in seconds")]
[MMFEnumCondition("Mode", (int)Modes.Seconds)]
public float TransitionDuration = 0.1f;
/// in Seconds mode, the offset at which to transition to, in seconds
[Tooltip("in Seconds mode, the offset at which to transition to, in seconds")]
[MMFEnumCondition("Mode", (int)Modes.Seconds)]
public float TimeOffset = 0f;
/// in Normalized mode, the duration of the transition, normalized between 0 and 1
[Tooltip("in Normalized mode, the duration of the transition, normalized between 0 and 1")]
[MMFEnumCondition("Mode", (int)Modes.Normalized)]
public float NormalizedTransitionDuration = 0.1f;
/// in Normalized mode, the offset at which to transition to, normalized between 0 and 1
[Tooltip("in Normalized mode, the offset at which to transition to, normalized between 0 and 1")]
[MMFEnumCondition("Mode", (int)Modes.Normalized)]
public float NormalizedTimeOffset = 0f;
/// according to Unity's docs, 'the time of the transition, normalized'. Really nobody's sure what this does. It's optional.
[Tooltip("according to Unity's docs, 'the time of the transition, normalized'. Really nobody's sure what this does. It's optional.")]
public float NormalizedTransitionTime = 0f;
protected int _stateHashName;
protected int _layerID;
/// <summary>
/// Custom Init
/// </summary>
/// <param name="owner"></param>
protected override void CustomInitialization(MMF_Player owner)
{
base.CustomInitialization(owner);
_stateHashName = Animator.StringToHash(StateName);
_layerID = Layer;
if ((LayerName != "") && (BoundAnimator != null))
{
_layerID = BoundAnimator.GetLayerIndex(LayerName);
}
}
/// <summary>
/// On Play, checks if an animator is bound and crossfades to the specified state
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
if (BoundAnimator == null)
{
Debug.LogWarning("[Animation Crossfade Feedback] The animation crossfade feedback on "+Owner.name+" doesn't have a BoundAnimator, it won't work. You need to specify one in its inspector.");
return;
}
if (RandomStateNames.Count > 0)
{
int randomIndex = UnityEngine.Random.Range(0, RandomStateNames.Count);
StateName = RandomStateNames[randomIndex];
_stateHashName = Animator.StringToHash(StateName);
}
CrossFade(BoundAnimator);
foreach (Animator animator in ExtraBoundAnimators)
{
CrossFade(animator);
}
}
/// <summary>
/// Crossfades either via fixed time or regular (normalized) calls
/// </summary>
/// <param name="targetAnimator"></param>
protected virtual void CrossFade(Animator targetAnimator)
{
switch (Mode)
{
case Modes.Seconds:
targetAnimator.CrossFadeInFixedTime(_stateHashName, TransitionDuration, _layerID, TimeOffset, NormalizedTransitionTime);
break;
case Modes.Normalized:
targetAnimator.CrossFade(_stateHashName, NormalizedTransitionDuration, _layerID, NormalizedTimeOffset, NormalizedTransitionTime);
break;
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: c0952ef5bf0c90a4eb36a3217da349b6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Feedbacks/MMF_AnimationCrossfade.cs
uploadId: 830868

View File

@@ -0,0 +1,169 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Scripting.APIUpdating;
namespace MoreMountains.Feedbacks
{
/// <summary>
/// A feedback used to play the specified state on the target Animator, either in normalized or fixed time.
/// </summary>
[AddComponentMenu("")]
[FeedbackHelp("This feedback will allow you to play the specified state on the target Animator, either in normalized or fixed time.")]
[MovedFrom(false, null, "MoreMountains.Feedbacks")]
[System.Serializable]
[FeedbackPath("Animation/Animator Play State")]
public class MMF_AnimatorPlayState : MMF_Feedback
{
/// a static bool used to disable all feedbacks of this type at once
public static bool FeedbackTypeAuthorized = true;
/// the possible modes that pilot triggers
public enum TriggerModes { SetTrigger, ResetTrigger }
/// the possible ways to set a value
public enum ValueModes { None, Constant, Random, Incremental }
/// sets the inspector color for this feedback
#if UNITY_EDITOR
public override Color FeedbackColor { get { return MMFeedbacksInspectorColors.AnimationColor; } }
public override bool EvaluateRequiresSetup() { return (BoundAnimator == null); }
public override string RequiredTargetText { get { return BoundAnimator != null ? BoundAnimator.name : ""; } }
public override string RequiresSetupText { get { return "This feedback requires that a BoundAnimator be set to be able to work properly. You can set one below."; } }
#endif
/// the duration of this feedback is the declared duration
public override float FeedbackDuration { get { return ApplyTimeMultiplier(DeclaredDuration); } set { DeclaredDuration = value; } }
public override bool HasRandomness => true;
public override bool HasAutomatedTargetAcquisition => true;
protected override void AutomateTargetAcquisition() => BoundAnimator = FindAutomatedTarget<Animator>();
public enum Modes { NormalizedTime, FixedTime }
[MMFInspectorGroup("Animation", true, 12, true)]
/// the animator whose parameters you want to update
[Tooltip("the animator whose parameters you want to update")]
public Animator BoundAnimator;
/// the list of extra animators whose parameters you want to update
[Tooltip("the list of extra animators whose parameters you want to update")]
public List<Animator> ExtraBoundAnimators;
/// the duration for the player to consider. This won't impact your animation, but is a way to communicate to the MMF Player the duration of this feedback. Usually you'll want it to match your actual animation, and setting it can be useful to have this feedback work with holding pauses.
[Tooltip("the duration for the player to consider. This won't impact your animation, but is a way to communicate to the MMF Player the duration of this feedback. Usually you'll want it to match your actual animation, and setting it can be useful to have this feedback work with holding pauses.")]
public float DeclaredDuration = 0f;
[MMFInspectorGroup("State", true, 16)]
/// The name of the state to play on the target animator
[Tooltip("The name of the state to play on the target animator")]
public string StateName;
/// Whether to play the state at a normalized time (between 0 and 1) or a fixed time (in seconds)
[Tooltip("Whether to play the state at a normalized time (between 0 and 1) or a fixed time (in seconds)")]
public Modes Mode = Modes.NormalizedTime;
/// The time offset between zero and one at which to play the specified state
[Tooltip("The time offset between zero and one at which to play the specified state")]
[MMFEnumCondition("Mode", (int)Modes.NormalizedTime)]
public float NormalizedTime = 0f;
/// The time offset (in seconds) at which to play the specified state
[Tooltip("The time offset (in seconds) at which to play the specified state")]
[MMFEnumCondition("Mode", (int)Modes.FixedTime)]
public float FixedTime = 0f;
/// The layer index. If layer is -1, it plays the first state with the given state name or hash.
[Tooltip("The layer index. If layer is -1, it plays the first state with the given state name or hash.")]
public int LayerIndex = -1;
/// the name of the Animator layer you want the state to play on. This is optional. If left empty, the layer ID above will be used, if not empty, the Layer id specified above will be ignored.
[Tooltip("the name of the Animator layer you want the state to play on. This is optional. If left empty, the layer ID above will be used, if not empty, the Layer id specified above will be ignored.")]
public string LayerName = "";
[MMFInspectorGroup("Layer Weights", true, 22)]
/// whether or not to set layer weights on the specified layer when playing this feedback
[Tooltip("whether or not to set layer weights on the specified layer when playing this feedback")]
public bool SetLayerWeight = false;
/// the index of the layer to target when changing layer weights
[Tooltip("the index of the layer to target when changing layer weights")]
[MMFCondition("SetLayerWeight", true)]
public int TargetLayerIndex = 1;
/// the new weight to set on the target animator layer
[Tooltip("the new weight to set on the target animator layer")]
[MMFCondition("SetLayerWeight", true)]
public float NewWeight = 0.5f;
protected int _targetParameter;
protected int _layerID;
/// <summary>
/// Custom Init
/// </summary>
/// <param name="owner"></param>
protected override void CustomInitialization(MMF_Player owner)
{
base.CustomInitialization(owner);
_targetParameter = Animator.StringToHash(StateName);
_layerID = TargetLayerIndex;
if ((LayerName != "") && (BoundAnimator != null))
{
_layerID = BoundAnimator.GetLayerIndex(LayerName);
}
}
/// <summary>
/// On Play, checks if an animator is bound and plays the specified state
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
if (BoundAnimator == null)
{
Debug.LogWarning("[Animator Play State Feedback] The animator play state feedback on "+Owner.name+" doesn't have a BoundAnimator, it won't work. You need to specify one in its inspector.");
return;
}
float intensityMultiplier = ComputeIntensity(feedbacksIntensity, position);
PlayState(BoundAnimator, intensityMultiplier);
foreach (Animator animator in ExtraBoundAnimators)
{
PlayState(animator, intensityMultiplier);
}
}
/// <summary>
/// Plays the specified state on the target animator
/// </summary>
/// <param name="targetAnimator"></param>
/// <param name="intensityMultiplier"></param>
protected virtual void PlayState(Animator targetAnimator, float intensityMultiplier)
{
if (SetLayerWeight)
{
targetAnimator.SetLayerWeight(_layerID, NewWeight);
}
if (Mode == Modes.NormalizedTime)
{
targetAnimator.Play(_targetParameter, LayerIndex, NormalizedTime);
}
else
{
targetAnimator.PlayInFixedTime(_targetParameter, LayerIndex, FixedTime);
}
}
/// <summary>
/// On stop, we do nothing
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomStopFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 333259468901c6b40b6cfd1b603a34d5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Feedbacks/MMF_AnimatorPlayState.cs
uploadId: 830868

View File

@@ -0,0 +1,171 @@
using System.Collections;
using System.Collections.Generic;
using MoreMountains.Tools;
using UnityEngine;
using UnityEngine.Scripting.APIUpdating;
namespace MoreMountains.Feedbacks
{
/// <summary>
/// This feedback will let you change the speed of a target animator, either once, or instantly and then reset it, or interpolate it over time
/// </summary>
[AddComponentMenu("")]
[FeedbackHelp("This feedback will let you change the speed of a target animator, either once, or instantly and then reset it, or interpolate it over time")]
[MovedFrom(false, null, "MoreMountains.Feedbacks")]
[System.Serializable]
[FeedbackPath("Animation/Animator Speed")]
public class MMF_AnimatorSpeed : MMF_Feedback
{
/// a static bool used to disable all feedbacks of this type at once
public static bool FeedbackTypeAuthorized = true;
/// sets the inspector color for this feedback
#if UNITY_EDITOR
public override Color FeedbackColor { get { return MMFeedbacksInspectorColors.AnimationColor; } }
public override bool EvaluateRequiresSetup() { return (BoundAnimator == null); }
public override string RequiredTargetText { get { return BoundAnimator != null ? BoundAnimator.name : ""; } }
public override string RequiresSetupText { get { return "This feedback requires that a BoundAnimator be set to be able to work properly. You can set one below."; } }
#endif
public override bool HasRandomness => true;
public override bool CanForceInitialValue => true;
public override bool HasAutomatedTargetAcquisition => true;
protected override void AutomateTargetAcquisition() => BoundAnimator = FindAutomatedTarget<Animator>();
public enum SpeedModes { Once, InstantThenReset, OverTime }
[MMFInspectorGroup("Animation", true, 12, true)]
/// the animator whose parameters you want to update
[Tooltip("the animator whose parameters you want to update")]
public Animator BoundAnimator;
[MMFInspectorGroup("Speed", true, 14, true)]
/// whether to change the speed of the target animator once, instantly and reset it later, or have it change over time
[Tooltip("whether to change the speed of the target animator once, instantly and reset it later, or have it change over time")]
public SpeedModes Mode = SpeedModes.Once;
/// the new minimum speed at which to set the animator - value will be randomized between min and max
[Tooltip("the new minimum speed at which to set the animator - value will be randomized between min and max")]
public float NewSpeedMin = 0f;
/// the new maximum speed at which to set the animator - value will be randomized between min and max
[Tooltip("the new maximum speed at which to set the animator - value will be randomized between min and max")]
public float NewSpeedMax = 0f;
/// when in instant then reset or over time modes, the duration of the effect
[Tooltip("when in instant then reset or over time modes, the duration of the effect")]
[MMFEnumCondition("Mode", (int)SpeedModes.InstantThenReset, (int)SpeedModes.OverTime)]
public float Duration = 1f;
/// when in over time mode, the curve against which to evaluate the new speed
[Tooltip("when in over time mode, the curve against which to evaluate the new speed")]
[MMFEnumCondition("Mode", (int)SpeedModes.OverTime)]
public AnimationCurve Curve = new AnimationCurve(new Keyframe(0, 0f), new Keyframe(0.5f, 1f), new Keyframe(1, 0f));
protected Coroutine _coroutine;
protected float _initialSpeed;
protected float _startedAt;
/// <summary>
/// On Play, checks if an animator is bound and triggers parameters
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
if (BoundAnimator == null)
{
Debug.LogWarning("[Animator Speed Feedback] The animator speed feedback on "+Owner.name+" doesn't have a BoundAnimator, it won't work. You need to specify one in its inspector.");
return;
}
if (!IsPlaying)
{
_initialSpeed = BoundAnimator.speed;
}
if (Mode == SpeedModes.Once)
{
BoundAnimator.speed = ComputeIntensity(DetermineNewSpeed(), position);
}
else
{
if (_coroutine != null) { Owner.StopCoroutine(_coroutine); }
_coroutine = Owner.StartCoroutine(ChangeSpeedCo());
}
}
/// <summary>
/// A coroutine used in ForDuration mode
/// </summary>
/// <returns></returns>
protected virtual IEnumerator ChangeSpeedCo()
{
if (Mode == SpeedModes.InstantThenReset)
{
IsPlaying = true;
BoundAnimator.speed = DetermineNewSpeed();
yield return WaitFor(Duration);
BoundAnimator.speed = _initialSpeed;
IsPlaying = false;
}
else if (Mode == SpeedModes.OverTime)
{
IsPlaying = true;
_startedAt = FeedbackTime;
float newTargetSpeed = DetermineNewSpeed();
while (FeedbackTime - _startedAt < Duration)
{
float time = MMFeedbacksHelpers.Remap(FeedbackTime - _startedAt, 0f, Duration, 0f, 1f);
float t = Curve.Evaluate(time);
BoundAnimator.speed = Mathf.Max(0f, MMFeedbacksHelpers.Remap(t, 0f, 1f, _initialSpeed, newTargetSpeed));
yield return null;
}
BoundAnimator.speed = _initialSpeed;
IsPlaying = false;
}
}
/// <summary>
/// Determines the new speed for the target animator
/// </summary>
/// <returns></returns>
protected virtual float DetermineNewSpeed()
{
return Mathf.Abs(Random.Range(NewSpeedMin, NewSpeedMax));
}
/// <summary>
/// On stop, turns the bool parameter to false
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomStopFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
if (_coroutine != null)
{
Owner.StopCoroutine(_coroutine);
}
BoundAnimator.speed = _initialSpeed;
}
/// <summary>
/// On restore, we restore our initial state
/// </summary>
protected override void CustomRestoreInitialValues()
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
BoundAnimator.speed = _initialSpeed;
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 42453e475524af140ac923a2fe1e86f6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Feedbacks/MMF_AnimatorSpeed.cs
uploadId: 830868

View File

@@ -0,0 +1,110 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Scripting.APIUpdating;
namespace MoreMountains.Feedbacks
{
/// <summary>
/// This feedback lets you control the distortion level of a distortion filter. You'll need a MMAudioFilterDistortionShaker on the filter.
/// </summary>
[AddComponentMenu("")]
[MovedFrom(false, null, "MoreMountains.Feedbacks")]
[System.Serializable]
[FeedbackPath("Audio/Audio Filter Distortion")]
[FeedbackHelp("This feedback lets you control a distortion audio filter over time. You'll need a MMAudioFilterDistortionShaker on the filter.")]
public class MMF_AudioFilterDistortion : MMF_Feedback
{
/// a static bool used to disable all feedbacks of this type at once
public static bool FeedbackTypeAuthorized = true;
/// sets the inspector color for this feedback
#if UNITY_EDITOR
public override Color FeedbackColor { get { return MMFeedbacksInspectorColors.SoundsColor; } }
public override string RequiredTargetText => RequiredChannelText;
#endif
/// returns the duration of the feedback
public override float FeedbackDuration { get { return ApplyTimeMultiplier(Duration); } set { Duration = value; } }
public override bool HasChannel => true;
public override bool HasRandomness => true;
[MMFInspectorGroup("Distortion Filter", true, 28)]
/// the duration of the shake, in seconds
[Tooltip("the duration of the shake, in seconds")]
public float Duration = 2f;
/// whether or not to reset shaker values after shake
[Tooltip("whether or not to reset shaker values after shake")]
public bool ResetShakerValuesAfterShake = true;
/// whether or not to reset the target's values after shake
[Tooltip("whether or not to reset the target's values after shake")]
public bool ResetTargetValuesAfterShake = true;
/// whether or not to add to the initial value
[Tooltip("whether or not to add to the initial value")]
public bool RelativeDistortion = false;
/// the curve used to animate the intensity value on
[Tooltip("the curve used to animate the intensity value on")]
public AnimationCurve ShakeDistortion = new AnimationCurve(new Keyframe(0, 0), new Keyframe(0.5f, 1), new Keyframe(1, 0));
/// the value to remap the curve's 0 to
[Tooltip("the value to remap the curve's 0 to")]
[Range(0f, 1f)]
public float RemapDistortionZero = 0f;
/// the value to remap the curve's 1 to
[Tooltip("the value to remap the curve's 1 to")]
[Range(0f, 1f)]
public float RemapDistortionOne = 1f;
/// <summary>
/// Triggers the corresponding coroutine
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
float intensityMultiplier = ComputeIntensity(feedbacksIntensity, position);
float remapZero = 0f;
float remapOne = 0f;
if (!Timing.ConstantIntensity)
{
remapZero = RemapDistortionZero * intensityMultiplier;
remapOne = RemapDistortionOne * intensityMultiplier;
}
MMAudioFilterDistortionShakeEvent.Trigger(ShakeDistortion, FeedbackDuration, remapZero, remapOne, RelativeDistortion,
intensityMultiplier, ChannelData, ResetShakerValuesAfterShake, ResetTargetValuesAfterShake, NormalPlayDirection, ComputedTimescaleMode);
}
/// <summary>
/// On stop we stop our transition
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomStopFeedback(Vector3 position, float feedbacksIntensity = 1)
{
base.CustomStopFeedback(position, feedbacksIntensity);
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
MMAudioFilterDistortionShakeEvent.Trigger(ShakeDistortion, FeedbackDuration, 0f,0f, stop:true);
}
/// <summary>
/// On restore, we restore our initial state
/// </summary>
protected override void CustomRestoreInitialValues()
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
MMAudioFilterDistortionShakeEvent.Trigger(ShakeDistortion, FeedbackDuration, 0f,0f, restore:true);
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 8d956ba1792f2034a94f45a349064ba1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Feedbacks/MMF_AudioFilterDistortion.cs
uploadId: 830868

View File

@@ -0,0 +1,100 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Scripting.APIUpdating;
namespace MoreMountains.Feedbacks
{
/// <summary>
/// This feedback lets you control the wetmix level of an echo filter. You'll need a MMAudioFilterEchoShaker on your filter.
/// </summary>
[AddComponentMenu("")]
[MovedFrom(false, null, "MoreMountains.Feedbacks")]
[System.Serializable]
[FeedbackPath("Audio/Audio Filter Echo")]
[FeedbackHelp("This feedback lets you control an echo audio filter's wet mix value over time. You'll need a MMAudioFilterEchoShaker on your filter.")]
public class MMF_AudioFilterEcho : MMF_Feedback
{
/// a static bool used to disable all feedbacks of this type at once
public static bool FeedbackTypeAuthorized = true;
/// sets the inspector color for this feedback
#if UNITY_EDITOR
public override Color FeedbackColor { get { return MMFeedbacksInspectorColors.SoundsColor; } }
public override string RequiredTargetText => RequiredChannelText;
#endif
/// returns the duration of the feedback
public override float FeedbackDuration { get { return ApplyTimeMultiplier(Duration); } set { Duration = value; } }
public override bool HasChannel => true;
public override bool HasRandomness => true;
[MMFInspectorGroup("Echo Filter", true, 28)]
/// the duration of the shake, in seconds
[Tooltip("the duration of the shake, in seconds")]
public float Duration = 2f;
/// whether or not to reset shaker values after shake
[Tooltip("whether or not to reset shaker values after shake")]
public bool ResetShakerValuesAfterShake = true;
/// whether or not to reset the target's values after shake
[Tooltip("whether or not to reset the target's values after shake")]
public bool ResetTargetValuesAfterShake = true;
/// whether or not to add to the initial value
[Tooltip("whether or not to add to the initial value")]
public bool RelativeEcho = false;
/// the curve used to animate the intensity value on
[Tooltip("the curve used to animate the intensity value on")]
public AnimationCurve ShakeEcho = new AnimationCurve(new Keyframe(0, 0), new Keyframe(0.5f, 1), new Keyframe(1, 0));
/// the value to remap the curve's 0 to
[Range(0f, 1f)]
[Tooltip("the value to remap the curve's 0 to")]
public float RemapEchoZero = 0f;
/// the value to remap the curve's 1 to
[Range(0f, 1f)]
[Tooltip("the value to remap the curve's 1 to")]
public float RemapEchoOne = 1f;
/// <summary>
/// Triggers the corresponding coroutine
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
float intensityMultiplier = ComputeIntensity(feedbacksIntensity, position);
MMAudioFilterEchoShakeEvent.Trigger(ShakeEcho, FeedbackDuration, RemapEchoZero, RemapEchoOne, RelativeEcho,
intensityMultiplier, ChannelData, ResetShakerValuesAfterShake, ResetTargetValuesAfterShake, NormalPlayDirection, ComputedTimescaleMode);
}
/// <summary>
/// On stop we stop our transition
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomStopFeedback(Vector3 position, float feedbacksIntensity = 1)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
base.CustomStopFeedback(position, feedbacksIntensity);
MMAudioFilterEchoShakeEvent.Trigger(ShakeEcho, FeedbackDuration, RemapEchoZero, RemapEchoOne, RelativeEcho, stop:true);
}
/// <summary>
/// On restore, we restore our initial state
/// </summary>
protected override void CustomRestoreInitialValues()
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
MMAudioFilterEchoShakeEvent.Trigger(ShakeEcho, FeedbackDuration, RemapEchoZero, RemapEchoOne, RelativeEcho, restore:true);
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: c3a9753eaf81ae04aa91936d315f19f6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Feedbacks/MMF_AudioFilterEcho.cs
uploadId: 830868

View File

@@ -0,0 +1,99 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Scripting.APIUpdating;
namespace MoreMountains.Feedbacks
{
/// <summary>
/// This feedback lets you control the cutoff frequency of a high pass filter. You'll need a MMAudioFilterHighPassShaker on your filter.
/// </summary>
[AddComponentMenu("")]
[MovedFrom(false, null, "MoreMountains.Feedbacks")]
[System.Serializable]
[FeedbackPath("Audio/Audio Filter High Pass")]
[FeedbackHelp("This feedback lets you control a high pass audio filter over time. You'll need a MMAudioFilterHighPassShaker on your filter.")]
public class MMF_AudioFilterHighPass : MMF_Feedback
{
/// a static bool used to disable all feedbacks of this type at once
public static bool FeedbackTypeAuthorized = true;
/// sets the inspector color for this feedback
#if UNITY_EDITOR
public override Color FeedbackColor { get { return MMFeedbacksInspectorColors.SoundsColor; } }
public override string RequiredTargetText => RequiredChannelText;
#endif
/// returns the duration of the feedback
public override float FeedbackDuration { get { return ApplyTimeMultiplier(Duration); } set { Duration = value; } }
public override bool HasChannel => true;
public override bool HasRandomness => true;
[MMFInspectorGroup("High Pass Filter", true, 28)]
/// the duration of the shake, in seconds
[Tooltip("the duration of the shake, in seconds")]
public float Duration = 2f;
/// whether or not to reset shaker values after shake
[Tooltip("whether or not to reset shaker values after shake")]
public bool ResetShakerValuesAfterShake = true;
/// whether or not to reset the target's values after shake
[Tooltip("whether or not to reset the target's values after shake")]
public bool ResetTargetValuesAfterShake = true;
/// whether or not to add to the initial value
[Tooltip("whether or not to add to the initial value")]
public bool RelativeHighPass = false;
/// the curve used to animate the intensity value on
[Tooltip("the curve used to animate the intensity value on")]
public AnimationCurve ShakeHighPass = new AnimationCurve(new Keyframe(0, 0f), new Keyframe(0.5f, 1f), new Keyframe(1, 0f));
/// the value to remap the curve's 0 to
[Range(10f, 22000f)]
[Tooltip("the value to remap the curve's 0 to")]
public float RemapHighPassZero = 0f;
/// the value to remap the curve's 1 to
[Range(10f, 22000f)]
[Tooltip("the value to remap the curve's 1 to")]
public float RemapHighPassOne = 10000f;
/// <summary>
/// Triggers the corresponding coroutine
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
float intensityMultiplier = ComputeIntensity(feedbacksIntensity, position);
MMAudioFilterHighPassShakeEvent.Trigger(ShakeHighPass, FeedbackDuration, RemapHighPassZero, RemapHighPassOne, RelativeHighPass,
intensityMultiplier, ChannelData, ResetShakerValuesAfterShake, ResetTargetValuesAfterShake, NormalPlayDirection, ComputedTimescaleMode);
}
/// <summary>
/// On stop we stop our transition
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomStopFeedback(Vector3 position, float feedbacksIntensity = 1)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
base.CustomStopFeedback(position, feedbacksIntensity);
MMAudioFilterHighPassShakeEvent.Trigger(ShakeHighPass, FeedbackDuration, RemapHighPassZero, RemapHighPassOne, stop:true);
}
/// <summary>
/// On restore, we restore our initial state
/// </summary>
protected override void CustomRestoreInitialValues()
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
MMAudioFilterHighPassShakeEvent.Trigger(ShakeHighPass, FeedbackDuration, RemapHighPassZero, RemapHighPassOne, restore:true);
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: d1398e413230465419066aaaf13ffe1c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Feedbacks/MMF_AudioFilterHighPass.cs
uploadId: 830868

View File

@@ -0,0 +1,101 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Scripting.APIUpdating;
namespace MoreMountains.Feedbacks
{
/// <summary>
/// This feedback lets you control the cutoff frequency of a low pass filter. You'll need a MMAudioFilterLowPassShaker on your filter.
/// </summary>
[AddComponentMenu("")]
[MovedFrom(false, null, "MoreMountains.Feedbacks")]
[System.Serializable]
[FeedbackPath("Audio/Audio Filter Low Pass")]
[FeedbackHelp(
"This feedback lets you control a low pass audio filter over time. You'll need a MMAudioFilterLowPassShaker on your filter.")]
public class MMF_AudioFilterLowPass : MMF_Feedback
{
/// a static bool used to disable all feedbacks of this type at once
public static bool FeedbackTypeAuthorized = true;
/// sets the inspector color for this feedback
#if UNITY_EDITOR
public override Color FeedbackColor { get { return MMFeedbacksInspectorColors.SoundsColor; } }
public override string RequiredTargetText => RequiredChannelText;
#endif
/// returns the duration of the feedback
public override float FeedbackDuration { get { return ApplyTimeMultiplier(Duration); } set { Duration = value; } }
public override bool HasChannel => true;
public override bool HasRandomness => true;
[MMFInspectorGroup("Low Pass Filter", true, 28)]
/// the duration of the shake, in seconds
[Tooltip("the duration of the shake, in seconds")]
public float Duration = 2f;
/// whether or not to reset shaker values after shake
[Tooltip("whether or not to reset shaker values after shake")]
public bool ResetShakerValuesAfterShake = true;
/// whether or not to reset the target's values after shake
[Tooltip("whether or not to reset the target's values after shake")]
public bool ResetTargetValuesAfterShake = true;
/// whether or not to add to the initial value
[Tooltip("whether or not to add to the initial value")]
public bool RelativeLowPass = false;
/// the curve used to animate the intensity value on
[Tooltip("the curve used to animate the intensity value on")]
public AnimationCurve ShakeLowPass = new AnimationCurve(new Keyframe(0, 1f), new Keyframe(0.5f, 0f), new Keyframe(1, 1f));
/// the value to remap the curve's 0 to
[Range(10f, 22000f)]
[Tooltip("the value to remap the curve's 0 to")]
public float RemapLowPassZero = 0f;
/// the value to remap the curve's 1 to
[Range(10f, 22000f)]
[Tooltip("the value to remap the curve's 1 to")]
public float RemapLowPassOne = 10000f;
/// <summary>
/// Triggers the corresponding coroutine
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
float intensityMultiplier = ComputeIntensity(feedbacksIntensity, position);
MMAudioFilterLowPassShakeEvent.Trigger(ShakeLowPass, FeedbackDuration, RemapLowPassZero, RemapLowPassOne, RelativeLowPass,
intensityMultiplier, ChannelData, ResetShakerValuesAfterShake, ResetTargetValuesAfterShake, NormalPlayDirection, ComputedTimescaleMode);
}
/// <summary>
/// On stop we stop our transition
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomStopFeedback(Vector3 position, float feedbacksIntensity = 1)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
base.CustomStopFeedback(position, feedbacksIntensity);
MMAudioFilterLowPassShakeEvent.Trigger(ShakeLowPass, FeedbackDuration, RemapLowPassZero, RemapLowPassOne, stop:true);
}
/// <summary>
/// On restore, we restore our initial state
/// </summary>
protected override void CustomRestoreInitialValues()
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
MMAudioFilterLowPassShakeEvent.Trigger(ShakeLowPass, FeedbackDuration, RemapLowPassZero, RemapLowPassOne, restore:true);
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 6112045d35430d84797f5786482c0129
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Feedbacks/MMF_AudioFilterLowPass.cs
uploadId: 830868

View File

@@ -0,0 +1,101 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Scripting.APIUpdating;
namespace MoreMountains.Feedbacks
{
/// <summary>
/// This feedback lets you control the reverb level of a reverb filter. You'll need a MMAudioFilterReverbShaker on your filter.
/// </summary>
[AddComponentMenu("")]
[MovedFrom(false, null, "MoreMountains.Feedbacks")]
[System.Serializable]
[FeedbackPath("Audio/Audio Filter Reverb")]
[FeedbackHelp(
"This feedback lets you control a low pass audio filter over time. You'll need a MMAudioFilterReverbShaker on your filter.")]
public class MMF_AudioFilterReverb : MMF_Feedback
{
/// a static bool used to disable all feedbacks of this type at once
public static bool FeedbackTypeAuthorized = true;
/// sets the inspector color for this feedback
#if UNITY_EDITOR
public override Color FeedbackColor { get { return MMFeedbacksInspectorColors.SoundsColor; } }
public override string RequiredTargetText => RequiredChannelText;
#endif
/// returns the duration of the feedback
public override float FeedbackDuration { get { return ApplyTimeMultiplier(Duration); } set { Duration = value; } }
public override bool HasChannel => true;
public override bool HasRandomness => true;
[MMFInspectorGroup("Reverb Filter", true, 28)]
/// the duration of the shake, in seconds
[Tooltip("the duration of the shake, in seconds")]
public float Duration = 2f;
/// whether or not to reset shaker values after shake
[Tooltip("whether or not to reset shaker values after shake")]
public bool ResetShakerValuesAfterShake = true;
/// whether or not to reset the target's values after shake
[Tooltip("whether or not to reset the target's values after shake")]
public bool ResetTargetValuesAfterShake = true;
/// whether or not to add to the initial value
[Tooltip("whether or not to add to the initial value")]
public bool RelativeReverb = false;
/// the curve used to animate the intensity value on
[Tooltip("the curve used to animate the intensity value on")]
public AnimationCurve ShakeReverb = new AnimationCurve(new Keyframe(0, 0f), new Keyframe(0.5f, 1f), new Keyframe(1, 0f));
/// the value to remap the curve's 0 to
[Range(-10000f, 2000f)]
[Tooltip("the value to remap the curve's 0 to")]
public float RemapReverbZero = -10000f;
/// the value to remap the curve's 1 to
[Range(-10000f, 2000f)]
[Tooltip("the value to remap the curve's 1 to")]
public float RemapReverbOne = 2000f;
/// <summary>
/// Triggers the corresponding coroutine
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
float intensityMultiplier = ComputeIntensity(feedbacksIntensity, position);
MMAudioFilterReverbShakeEvent.Trigger(ShakeReverb, FeedbackDuration, RemapReverbZero, RemapReverbOne, RelativeReverb,
intensityMultiplier, ChannelData, ResetShakerValuesAfterShake, ResetTargetValuesAfterShake, NormalPlayDirection, ComputedTimescaleMode);
}
/// <summary>
/// On stop we stop our transition
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomStopFeedback(Vector3 position, float feedbacksIntensity = 1)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
base.CustomStopFeedback(position, feedbacksIntensity);
MMAudioFilterReverbShakeEvent.Trigger(ShakeReverb, FeedbackDuration, RemapReverbZero, RemapReverbOne, stop:true);
}
/// <summary>
/// On restore, we restore our initial state
/// </summary>
protected override void CustomRestoreInitialValues()
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
MMAudioFilterReverbShakeEvent.Trigger(ShakeReverb, FeedbackDuration, RemapReverbZero, RemapReverbOne, restore:true);
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: fb2fb44761e9da645a012cd87424fc10
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Feedbacks/MMF_AudioFilterReverb.cs
uploadId: 830868

View File

@@ -0,0 +1,73 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Scripting.APIUpdating;
namespace MoreMountains.Feedbacks
{
/// <summary>
/// This feedback will let you transition to a target AudioMixer Snapshot over a specified time
/// </summary>
[AddComponentMenu("")]
[FeedbackHelp("This feedback will let you transition to a target AudioMixer Snapshot over a specified time")]
[MovedFrom(false, null, "MoreMountains.Feedbacks")]
[System.Serializable]
[FeedbackPath("Audio/AudioMixer Snapshot Transition")]
public class MMF_AudioMixerSnapshotTransition : MMF_Feedback
{
/// a static bool used to disable all feedbacks of this type at once
public static bool FeedbackTypeAuthorized = true;
#if UNITY_EDITOR
public override Color FeedbackColor { get { return MMFeedbacksInspectorColors.UIColor; } }
public override bool EvaluateRequiresSetup() { return ((TargetSnapshot == null) || (OriginalSnapshot == null)); }
public override string RequiredTargetText { get { return ((TargetSnapshot != null) && (OriginalSnapshot != null)) ? TargetSnapshot.name + " to "+ OriginalSnapshot.name : ""; } }
public override string RequiresSetupText { get { return "This feedback requires that both a OriginalSnapshot and TargetSnapshot be set to be able to work properly. You can set these below."; } }
#endif
[MMFInspectorGroup("AudioMixer Snapshot", true, 44)]
/// the target audio mixer snapshot we want to transition to
[Tooltip("the target audio mixer snapshot we want to transition to")]
public AudioMixerSnapshot TargetSnapshot;
/// the audio mixer snapshot we want to transition from, optional, only needed if you plan to play this feedback in reverse
[Tooltip("the audio mixer snapshot we want to transition from, optional, only needed if you plan to play this feedback in reverse")]
public AudioMixerSnapshot OriginalSnapshot;
/// the duration, in seconds, over which to transition to the selected snapshot
[Tooltip("the duration, in seconds, over which to transition to the selected snapshot")]
public float TransitionDuration = 1f;
/// <summary>
/// On play we transition to the selected snapshot
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
if (TargetSnapshot == null)
{
return;
}
if (!NormalPlayDirection)
{
if (OriginalSnapshot != null)
{
OriginalSnapshot.TransitionTo(TransitionDuration);
}
else
{
TargetSnapshot.TransitionTo(TransitionDuration);
}
}
else
{
TargetSnapshot.TransitionTo(TransitionDuration);
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 89f0c7ac1091bf24aa52fc37f6bbd307
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Feedbacks/MMF_AudioMixerSnapshotTransition.cs
uploadId: 830868

View File

@@ -0,0 +1,175 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Scripting.APIUpdating;
using Random = UnityEngine.Random;
namespace MoreMountains.Feedbacks
{
[AddComponentMenu("")]
[MovedFrom(false, null, "MoreMountains.Feedbacks")]
[System.Serializable]
[FeedbackPath("Audio/AudioSource")]
[FeedbackHelp("This feedback lets you play a target audio source, with some elements at random.")]
public class MMF_AudioSource : MMF_Feedback
{
/// a static bool used to disable all feedbacks of this type at once
public static bool FeedbackTypeAuthorized = true;
/// sets the inspector color for this feedback
#if UNITY_EDITOR
public override Color FeedbackColor { get { return MMFeedbacksInspectorColors.SoundsColor; } }
public override bool EvaluateRequiresSetup() { return (TargetAudioSource == null); }
public override string RequiredTargetText { get { return TargetAudioSource != null ? TargetAudioSource.name : ""; } }
public override string RequiresSetupText { get { return "This feedback requires that a TargetAudioSource be set to be able to work properly. You can set one below."; } }
#endif
public override bool HasRandomness => true;
public override bool HasAutomatedTargetAcquisition => true;
protected override void AutomateTargetAcquisition() => TargetAudioSource = FindAutomatedTarget<AudioSource>();
/// the possible ways to interact with the audiosource
public enum Modes { Play, Pause, UnPause, Stop }
[MMFInspectorGroup("Audiosource", true, 5, true)]
/// the target audio source to play
[Tooltip("the target audio source to play")]
public AudioSource TargetAudioSource;
/// whether we should play the audio source or stop it or pause it
[Tooltip("whether we should play the audio source or stop it or pause it")]
public Modes Mode = Modes.Play;
[Header("Random Sound")]
/// an array to pick a random sfx from
[Tooltip("an array to pick a random sfx from")]
public AudioClip[] RandomSfx;
[MMFInspectorGroup("Audio Settings", true, 29)]
[Header("Volume")]
/// the minimum volume to play the sound at
[Tooltip("the minimum volume to play the sound at")]
public float MinVolume = 1f;
/// the maximum volume to play the sound at
[Tooltip("the maximum volume to play the sound at")]
public float MaxVolume = 1f;
[Header("Pitch")]
/// the minimum pitch to play the sound at
[Tooltip("the minimum pitch to play the sound at")]
public float MinPitch = 1f;
/// the maximum pitch to play the sound at
[Tooltip("the maximum pitch to play the sound at")]
public float MaxPitch = 1f;
[Header("Mixer")]
/// the audiomixer to play the sound with (optional)
[Tooltip("the audiomixer to play the sound with (optional)")]
public AudioMixerGroup SfxAudioMixerGroup;
/// the duration of this feedback is the duration of the clip being played
public override float FeedbackDuration { get { return _duration; } set { _duration = value; } }
protected AudioClip _randomClip;
protected float _duration;
protected override void CustomInitialization(MMF_Player owner)
{
base.CustomInitialization(owner);
if (Active)
{
if (RandomSfx == null)
{
RandomSfx = Array.Empty<AudioClip>();
}
}
}
/// <summary>
/// Plays either a random sound or the specified sfx
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
float intensityMultiplier = ComputeIntensity(feedbacksIntensity, position);
switch(Mode)
{
case Modes.Play:
if (RandomSfx.Length > 0)
{
_randomClip = RandomSfx[Random.Range(0, RandomSfx.Length)];
TargetAudioSource.clip = _randomClip;
}
float volume = Random.Range(MinVolume, MaxVolume) * intensityMultiplier;
float pitch = Random.Range(MinPitch, MaxPitch);
if (TargetAudioSource == null)
{
Debug.LogWarning("[AudioSource Feedback] The audio source feedback on "+Owner.name+" doesn't have a TargetAudioSource, it won't work. You need to specify one in its inspector.");
return;
}
_duration = TargetAudioSource.clip.length;
PlayAudioSource(TargetAudioSource, volume, pitch);
break;
case Modes.Pause:
_duration = 0.1f;
TargetAudioSource.Pause();
break;
case Modes.UnPause:
_duration = 0.1f;
TargetAudioSource.UnPause();
break;
case Modes.Stop:
_duration = 0.1f;
TargetAudioSource.Stop();
break;
}
}
/// <summary>
/// Plays the audiosource at the selected volume and pitch
/// </summary>
/// <param name="audioSource"></param>
/// <param name="volume"></param>
/// <param name="pitch"></param>
protected virtual void PlayAudioSource(AudioSource audioSource, float volume, float pitch)
{
// we set the audio source volume to the one in parameters
audioSource.volume = volume;
audioSource.pitch = pitch;
audioSource.timeSamples = 0;
if (!NormalPlayDirection)
{
audioSource.pitch = -1;
audioSource.timeSamples = audioSource.clip.samples - 1;
}
// we start playing the sound
audioSource.Play();
}
/// <summary>
/// Stops the audiosource from playing
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
public override void Stop(Vector3 position, float feedbacksIntensity = 1.0f)
{
base.Stop(position, feedbacksIntensity);
if (TargetAudioSource != null)
{
TargetAudioSource?.Stop();
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 9d6b34f746558214f8be920b214b567e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Feedbacks/MMF_AudioSource.cs
uploadId: 830868

View File

@@ -0,0 +1,99 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Scripting.APIUpdating;
namespace MoreMountains.Feedbacks
{
/// <summary>
/// This feedback lets you control the pitch of an AudioSource over time
/// </summary>
[AddComponentMenu("")]
[MovedFrom(false, null, "MoreMountains.Feedbacks")]
[System.Serializable]
[FeedbackPath("Audio/AudioSource Pitch")]
[FeedbackHelp("This feedback lets you control the pitch of a target AudioSource over time.")]
public class MMF_AudioSourcePitch : MMF_Feedback
{
/// a static bool used to disable all feedbacks of this type at once
public static bool FeedbackTypeAuthorized = true;
/// sets the inspector color for this feedback
#if UNITY_EDITOR
public override Color FeedbackColor { get { return MMFeedbacksInspectorColors.SoundsColor; } }
public override string RequiredTargetText => RequiredChannelText;
#endif
/// returns the duration of the feedback
public override float FeedbackDuration { get { return ApplyTimeMultiplier(Duration); } set { Duration = value; } }
public override bool HasChannel => true;
public override bool HasRandomness => true;
[MMFInspectorGroup("AudioSource Pitch", true, 77)]
/// the duration of the shake, in seconds
[Tooltip("the duration of the shake, in seconds")]
public float Duration = 2f;
/// whether or not to reset shaker values after shake
[Tooltip("whether or not to reset shaker values after shake")]
public bool ResetShakerValuesAfterShake = true;
/// whether or not to reset the target's values after shake
[Tooltip("whether or not to reset the target's values after shake")]
public bool ResetTargetValuesAfterShake = true;
/// whether or not to add to the initial value
[Tooltip("whether or not to add to the initial value")]
public bool RelativePitch = false;
/// the curve used to animate the intensity value on
[Tooltip("the curve used to animate the intensity value on")]
public AnimationCurve PitchTween = new AnimationCurve(new Keyframe(0, 1f), new Keyframe(0.5f, 0f), new Keyframe(1, 1f));
/// the value to remap the curve's 0 to
[Range(-3f, 3f)]
[Tooltip("the value to remap the curve's 0 to")]
public float RemapPitchZero = 0f;
/// the value to remap the curve's 1 to
[Range(-3f, 3f)]
[Tooltip("the value to remap the curve's 1 to")]
public float RemapPitchOne = 1f;
/// <summary>
/// Triggers the corresponding coroutine
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
float intensityMultiplier = ComputeIntensity(feedbacksIntensity, position);
MMAudioSourcePitchShakeEvent.Trigger(PitchTween, FeedbackDuration, RemapPitchZero, RemapPitchOne, RelativePitch,
intensityMultiplier, ChannelData, ResetShakerValuesAfterShake, ResetTargetValuesAfterShake, NormalPlayDirection, ComputedTimescaleMode);
}
/// <summary>
/// On stop we stop our transition
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomStopFeedback(Vector3 position, float feedbacksIntensity = 1)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
base.CustomStopFeedback(position, feedbacksIntensity);
MMAudioSourcePitchShakeEvent.Trigger(PitchTween, FeedbackDuration, RemapPitchZero, RemapPitchOne, RelativePitch, stop:true);
}
/// <summary>
/// On restore, we restore our initial state
/// </summary>
protected override void CustomRestoreInitialValues()
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
MMAudioSourcePitchShakeEvent.Trigger(PitchTween, FeedbackDuration, RemapPitchZero, RemapPitchOne, RelativePitch, restore:true);
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 0a5f5fa0a0eb12242b82f5e32e147334
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Feedbacks/MMF_AudioSourcePitch.cs
uploadId: 830868

View File

@@ -0,0 +1,100 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Scripting.APIUpdating;
namespace MoreMountains.Feedbacks
{
/// <summary>
/// This feedback lets you control the stereo pan of a target AudioSource over time.
/// </summary>
[AddComponentMenu("")]
[MovedFrom(false, null, "MoreMountains.Feedbacks")]
[System.Serializable]
[FeedbackPath("Audio/AudioSource Stereo Pan")]
[FeedbackHelp("This feedback lets you control the stereo pan of a target AudioSource over time.")]
public class MMF_AudioSourceStereoPan : MMF_Feedback
{
/// a static bool used to disable all feedbacks of this type at once
public static bool FeedbackTypeAuthorized = true;
/// sets the inspector color for this feedback
#if UNITY_EDITOR
public override Color FeedbackColor { get { return MMFeedbacksInspectorColors.SoundsColor; } }
public override string RequiredTargetText => RequiredChannelText;
#endif
/// returns the duration of the feedback
public override float FeedbackDuration { get { return ApplyTimeMultiplier(Duration); } set { Duration = value; } }
public override bool HasChannel => true;
public override bool HasRandomness => true;
[MMFInspectorGroup("AudioSource Stereo Pan", true, 48)]
/// the duration of the shake, in seconds
[Tooltip("the duration of the shake, in seconds")]
public float Duration = 2f;
/// whether or not to reset shaker values after shake
[Tooltip("whether or not to reset shaker values after shake")]
public bool ResetShakerValuesAfterShake = true;
/// whether or not to reset the target's values after shake
[Tooltip("whether or not to reset the target's values after shake")]
public bool ResetTargetValuesAfterShake = true;
/// whether or not to add to the initial value
[Tooltip("whether or not to add to the initial value")]
public bool RelativeStereoPan = false;
/// the curve used to animate the intensity value on
[Tooltip("the curve used to animate the intensity value on")]
public AnimationCurve ShakeStereoPan = new AnimationCurve(new Keyframe(0, 0f), new Keyframe(0.3f, 1f), new Keyframe(0.6f, -1f), new Keyframe(1, 0f));
/// the value to remap the curve's 0 to
[Range(-1f, 1f)]
[Tooltip("the value to remap the curve's 0 to")]
public float RemapStereoPanZero = 0f;
/// the value to remap the curve's 1 to
[Range(-1f, 1f)]
[Tooltip("the value to remap the curve's 1 to")]
public float RemapStereoPanOne = 1f;
/// <summary>
/// Triggers the corresponding coroutine
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
float intensityMultiplier = ComputeIntensity(feedbacksIntensity, position);
MMAudioSourceStereoPanShakeEvent.Trigger(ShakeStereoPan, FeedbackDuration, RemapStereoPanZero, RemapStereoPanOne, RelativeStereoPan,
intensityMultiplier, ChannelData, ResetShakerValuesAfterShake, ResetTargetValuesAfterShake, NormalPlayDirection, ComputedTimescaleMode);
}
/// <summary>
/// On stop we stop our transition
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomStopFeedback(Vector3 position, float feedbacksIntensity = 1)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
base.CustomStopFeedback(position, feedbacksIntensity);
MMAudioSourceStereoPanShakeEvent.Trigger(ShakeStereoPan, FeedbackDuration, RemapStereoPanZero, RemapStereoPanOne, stop:true);
}
/// <summary>
/// On restore, we restore our initial state
/// </summary>
protected override void CustomRestoreInitialValues()
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
MMAudioSourceStereoPanShakeEvent.Trigger(ShakeStereoPan, FeedbackDuration, RemapStereoPanZero, RemapStereoPanOne, restore:true);
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: a1d30844a1ef58b4f8e34a359c02ccd7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Feedbacks/MMF_AudioSourceStereoPan.cs
uploadId: 830868

View File

@@ -0,0 +1,99 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Scripting.APIUpdating;
namespace MoreMountains.Feedbacks
{
/// <summary>
/// This feedback lets you control the volume of a target AudioSource over time.
/// </summary>
[AddComponentMenu("")]
[MovedFrom(false, null, "MoreMountains.Feedbacks")]
[System.Serializable]
[FeedbackPath("Audio/AudioSource Volume")]
[FeedbackHelp("This feedback lets you control the volume of a target AudioSource over time.")]
public class MMF_AudioSourceVolume : MMF_Feedback
{
/// a static bool used to disable all feedbacks of this type at once
public static bool FeedbackTypeAuthorized = true;
/// sets the inspector color for this feedback
#if UNITY_EDITOR
public override Color FeedbackColor { get { return MMFeedbacksInspectorColors.SoundsColor; } }
public override string RequiredTargetText => RequiredChannelText;
#endif
/// returns the duration of the feedback
public override float FeedbackDuration { get { return ApplyTimeMultiplier(Duration); } set { Duration = value; } }
public override bool HasChannel => true;
public override bool HasRandomness => true;
[MMFInspectorGroup("AudioSource Volume", true, 87)]
/// the duration of the shake, in seconds
[Tooltip("the duration of the shake, in seconds")]
public float Duration = 2f;
/// whether or not to reset shaker values after shake
[Tooltip("whether or not to reset shaker values after shake")]
public bool ResetShakerValuesAfterShake = true;
/// whether or not to reset the target's values after shake
[Tooltip("whether or not to reset the target's values after shake")]
public bool ResetTargetValuesAfterShake = true;
/// whether or not to add to the initial value
[Tooltip("whether or not to add to the initial value")]
public bool RelativeVolume = false;
/// the curve used to animate the intensity value on
[Tooltip("the curve used to animate the intensity value on")]
public AnimationCurve VolumeTween = new AnimationCurve(new Keyframe(0, 1f), new Keyframe(0.5f, 0f), new Keyframe(1, 1f));
/// the value to remap the curve's 0 to
[Range(-1f, 1f)]
[Tooltip("the value to remap the curve's 0 to")]
public float RemapVolumeZero = 0f;
/// the value to remap the curve's 1 to
[Range(-1f, 1f)]
[Tooltip("the value to remap the curve's 1 to")]
public float RemapVolumeOne = 1f;
/// <summary>
/// Triggers the corresponding coroutine
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
float intensityMultiplier = ComputeIntensity(feedbacksIntensity, position);
MMAudioSourceVolumeShakeEvent.Trigger(VolumeTween, FeedbackDuration, RemapVolumeZero, RemapVolumeOne, RelativeVolume,
intensityMultiplier, ChannelData, ResetShakerValuesAfterShake, ResetTargetValuesAfterShake, NormalPlayDirection, ComputedTimescaleMode);
}
/// <summary>
/// On stop we stop our transition
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomStopFeedback(Vector3 position, float feedbacksIntensity = 1)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
base.CustomStopFeedback(position, feedbacksIntensity);
MMAudioSourceVolumeShakeEvent.Trigger(VolumeTween, FeedbackDuration, RemapVolumeZero, RemapVolumeOne, stop:true);
}
/// <summary>
/// On restore, we restore our initial state
/// </summary>
protected override void CustomRestoreInitialValues()
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
MMAudioSourceVolumeShakeEvent.Trigger(VolumeTween, FeedbackDuration, RemapVolumeZero, RemapVolumeOne, restore:true);
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: d02d555b253bdc24e98b4e6bc088c59c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Feedbacks/MMF_AudioSourceVolume.cs
uploadId: 830868

View File

@@ -0,0 +1,116 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Scripting.APIUpdating;
namespace MoreMountains.Feedbacks
{
/// <summary>
/// This feedback lets you control a camera's clipping planes over time. You'll need a MMCameraClippingPlanesShaker on your camera.
/// </summary>
[AddComponentMenu("")]
[MovedFrom(false, null, "MoreMountains.Feedbacks")]
[System.Serializable]
[FeedbackPath("Camera/Clipping Planes")]
[FeedbackHelp("This feedback lets you control a camera's clipping planes over time. You'll need a MMCameraClippingPlanesShaker on your camera.")]
public class MMF_CameraClippingPlanes : MMF_Feedback
{
/// a static bool used to disable all feedbacks of this type at once
public static bool FeedbackTypeAuthorized = true;
/// sets the inspector color for this feedback
#if UNITY_EDITOR
public override Color FeedbackColor { get { return MMFeedbacksInspectorColors.CameraColor; } }
public override string RequiredTargetText => RequiredChannelText;
#endif
/// returns the duration of the feedback
public override float FeedbackDuration { get { return ApplyTimeMultiplier(Duration); } set { Duration = value; } }
public override bool HasChannel => true;
public override bool HasRandomness => true;
[MMFInspectorGroup("Clipping Planes", true, 52)]
/// the duration of the shake, in seconds
[Tooltip("the duration of the shake, in seconds")]
public float Duration = 2f;
/// whether or not to reset shaker values after shake
[Tooltip("whether or not to reset shaker values after shake")]
public bool ResetShakerValuesAfterShake = true;
/// whether or not to reset the target's values after shake
[Tooltip("whether or not to reset the target's values after shake")]
public bool ResetTargetValuesAfterShake = true;
/// whether or not to add to the initial value
[Tooltip("whether or not to add to the initial value")]
public bool RelativeClippingPlanes = false;
[MMFInspectorGroup("Near Plane", true, 53)]
/// the curve used to animate the intensity value on
[Tooltip("the curve used to animate the intensity value on")]
public AnimationCurve ShakeNear = new AnimationCurve(new Keyframe(0, 0), new Keyframe(0.5f, 1), new Keyframe(1, 0));
/// the value to remap the curve's 0 to
[Tooltip("the value to remap the curve's 0 to")]
public float RemapNearZero = 0.01f;
/// the value to remap the curve's 1 to
[Tooltip("the value to remap the curve's 1 to")]
public float RemapNearOne = 6.25f;
[MMFInspectorGroup("Far Plane", true, 54)]
/// the curve used to animate the intensity value on
[Tooltip("the curve used to animate the intensity value on")]
public AnimationCurve ShakeFar = new AnimationCurve(new Keyframe(0, 0), new Keyframe(0.5f, 1), new Keyframe(1, 0));
/// the value to remap the curve's 0 to
[Tooltip("the value to remap the curve's 0 to")]
public float RemapFarZero = 1000f;
/// the value to remap the curve's 1 to
[Tooltip("the value to remap the curve's 1 to")]
public float RemapFarOne = 5000f;
/// <summary>
/// Triggers the corresponding coroutine
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
feedbacksIntensity = ComputeIntensity(feedbacksIntensity, position);
MMCameraClippingPlanesShakeEvent.Trigger(ShakeNear, FeedbackDuration, RemapNearZero, RemapNearOne,
ShakeFar, RemapFarZero, RemapFarOne,
RelativeClippingPlanes,
feedbacksIntensity, ChannelData, ResetShakerValuesAfterShake, ResetTargetValuesAfterShake, NormalPlayDirection, ComputedTimescaleMode);
}
/// <summary>
/// On stop we stop our transition
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomStopFeedback(Vector3 position, float feedbacksIntensity = 1)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
base.CustomStopFeedback(position, feedbacksIntensity);
MMCameraClippingPlanesShakeEvent.Trigger(ShakeNear, FeedbackDuration, RemapNearZero, RemapNearOne,
ShakeFar, RemapFarZero, RemapFarOne, stop: true);
}
/// <summary>
/// On restore, we restore our initial state
/// </summary>
protected override void CustomRestoreInitialValues()
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
MMCameraClippingPlanesShakeEvent.Trigger(ShakeNear, FeedbackDuration, RemapNearZero, RemapNearOne,
ShakeFar, RemapFarZero, RemapFarOne, restore: true);
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: b76fc03c4a7392642aa1edd7647ffdac
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Feedbacks/MMF_CameraClippingPlanes.cs
uploadId: 830868

View File

@@ -0,0 +1,156 @@
using MoreMountains.FeedbacksForThirdParty;
using MoreMountains.Tools;
using UnityEngine;
using UnityEngine.Scripting.APIUpdating;
namespace MoreMountains.Feedbacks
{
/// <summary>
/// This feedback lets you control a camera's field of view over time. You'll need a MMCameraFieldOfViewShaker on your camera.
/// </summary>
[AddComponentMenu("")]
[MovedFrom(false, null, "MoreMountains.Feedbacks")]
[System.Serializable]
[FeedbackPath("Camera/Field of View")]
[FeedbackHelp(
"This feedback lets you control a camera's field of view over time. You'll need a MMCameraFieldOfViewShaker on your camera.")]
public class MMF_CameraFieldOfView : MMF_Feedback
{
/// a static bool used to disable all feedbacks of this type at once
public static bool FeedbackTypeAuthorized = true;
/// sets the inspector color for this feedback
#if UNITY_EDITOR
public override Color FeedbackColor => MMFeedbacksInspectorColors.CameraColor;
public override string RequiredTargetText => RequiredChannelText;
public override bool HasCustomInspectors => true;
public override bool HasAutomaticShakerSetup => true;
#endif
/// returns the duration of the feedback
public override float FeedbackDuration
{
get { return ApplyTimeMultiplier(Duration); }
set { Duration = value; }
}
public override bool HasChannel => true;
public override bool CanForceInitialValue => true;
public override bool ForceInitialValueDelayed => true;
public override bool HasRandomness => true;
[MMFInspectorGroup("Field of View", true, 37)]
/// the duration of the shake, in seconds
[Tooltip("the duration of the shake, in seconds")]
public float Duration = 2f;
/// whether or not to reset shaker values after shake
[Tooltip("whether or not to reset shaker values after shake")]
public bool ResetShakerValuesAfterShake = true;
/// whether or not to reset the target's values after shake
[Tooltip("whether or not to reset the target's values after shake")]
public bool ResetTargetValuesAfterShake = true;
/// whether or not to add to the initial value
[Tooltip("whether or not to add to the initial value")]
public bool RelativeFieldOfView = false;
/// the curve used to animate the intensity value on
[Tooltip("the curve used to animate the intensity value on")]
public AnimationCurve ShakeFieldOfView =
new AnimationCurve(new Keyframe(0, 0), new Keyframe(0.5f, 1), new Keyframe(1, 0));
/// the value to remap the curve's 0 to
[Tooltip("the value to remap the curve's 0 to")] [Range(0f, 179f)]
public float RemapFieldOfViewZero = 60f;
/// the value to remap the curve's 1 to
[Tooltip("the value to remap the curve's 1 to")] [Range(0f, 179f)]
public float RemapFieldOfViewOne = 120f;
/// <summary>
/// Triggers the corresponding coroutine
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
float intensityMultiplier = ComputeIntensity(feedbacksIntensity, position);
MMCameraFieldOfViewShakeEvent.Trigger(ShakeFieldOfView, FeedbackDuration, RemapFieldOfViewZero,
RemapFieldOfViewOne, RelativeFieldOfView,
intensityMultiplier, ChannelData, ResetShakerValuesAfterShake, ResetTargetValuesAfterShake,
NormalPlayDirection, ComputedTimescaleMode);
}
/// <summary>
/// On stop we stop our transition
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomStopFeedback(Vector3 position, float feedbacksIntensity = 1)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
base.CustomStopFeedback(position, feedbacksIntensity);
MMCameraFieldOfViewShakeEvent.Trigger(ShakeFieldOfView, FeedbackDuration, RemapFieldOfViewZero,
RemapFieldOfViewOne, stop: true);
}
/// <summary>
/// On restore, we restore our initial state
/// </summary>
protected override void CustomRestoreInitialValues()
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
MMCameraFieldOfViewShakeEvent.Trigger(ShakeFieldOfView, FeedbackDuration, RemapFieldOfViewZero,
RemapFieldOfViewOne, restore: true);
}
/// <summary>
/// Automatically tries to add a MMCameraFieldOfViewShaker to the main camera, if none are present
/// </summary>
public override void AutomaticShakerSetup()
{
#if MM_CINEMACHINE || MM_CINEMACHINE3
bool virtualCameraFound = false;
#endif
#if MMCINEMACHINE
CinemachineVirtualCamera virtualCamera = (CinemachineVirtualCamera)Object.FindObjectOfType(typeof(CinemachineVirtualCamera));
virtualCameraFound = (virtualCamera != null);
#elif MMCINEMACHINE3
CinemachineCamera virtualCamera = (CinemachineCamera)Object.FindObjectOfType(typeof(CinemachineCamera));
virtualCameraFound = (virtualCamera != null);
#endif
#if MM_CINEMACHINE || MM_CINEMACHINE3
if (virtualCameraFound)
{
MMCinemachineHelpers.AutomaticCinemachineShakersSetup(Owner, "CinemachineImpulse");
return;
}
#endif
MMCameraFieldOfViewShaker fieldOfViewShaker = (MMCameraFieldOfViewShaker)Object.FindAnyObjectByType(typeof(MMCameraFieldOfViewShaker));
if (fieldOfViewShaker != null)
{
return;
}
Camera.main.gameObject.MMGetOrAddComponent<MMCameraFieldOfViewShaker>();
MMDebug.DebugLogInfo( "Added a MMCameraFieldOfViewShaker to the main camera. You're all set.");
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 6313950da8f5bbf459733aed2e327e0c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Feedbacks/MMF_CameraFieldOfView.cs
uploadId: 830868

View File

@@ -0,0 +1,137 @@
using System.Collections;
using System.Collections.Generic;
using MoreMountains.FeedbacksForThirdParty;
using MoreMountains.Tools;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Scripting.APIUpdating;
namespace MoreMountains.Feedbacks
{
/// <summary>
/// This feedback lets you control a camera's orthographic size over time. You'll need a MMCameraOrthographicSizeShaker on your camera.
/// </summary>
[AddComponentMenu("")]
[MovedFrom(false, null, "MoreMountains.Feedbacks")]
[System.Serializable]
[FeedbackPath("Camera/Orthographic Size")]
[FeedbackHelp("This feedback lets you control a camera's orthographic size over time. You'll need a MMCameraOrthographicSizeShaker on your camera.")]
public class MMF_CameraOrthographicSize : MMF_Feedback
{
/// a static bool used to disable all feedbacks of this type at once
public static bool FeedbackTypeAuthorized = true;
/// sets the inspector color for this feedback
#if UNITY_EDITOR
public override Color FeedbackColor => MMFeedbacksInspectorColors.CameraColor;
public override string RequiredTargetText => RequiredChannelText;
public override bool HasCustomInspectors => true;
public override bool HasAutomaticShakerSetup => true;
#endif
/// returns the duration of the feedback
public override float FeedbackDuration { get { return ApplyTimeMultiplier(Duration); } set { Duration = value; } }
public override bool HasChannel => true;
[MMFInspectorGroup("Orthographic Size", true, 41)]
/// the duration of the shake, in seconds
[Tooltip("the duration of the shake, in seconds")]
public float Duration = 2f;
/// whether or not to reset shaker values after shake
[Tooltip("whether or not to reset shaker values after shake")]
public bool ResetShakerValuesAfterShake = true;
/// whether or not to reset the target's values after shake
[Tooltip("whether or not to reset the target's values after shake")]
public bool ResetTargetValuesAfterShake = true;
/// whether or not to add to the initial value
[Tooltip("whether or not to add to the initial value")]
public bool RelativeOrthographicSize = false;
/// the curve used to animate the intensity value on
[Tooltip("the curve used to animate the intensity value on")]
public AnimationCurve ShakeOrthographicSize = new AnimationCurve(new Keyframe(0, 0), new Keyframe(0.5f, 1), new Keyframe(1, 0));
/// the value to remap the curve's 0 to
[Tooltip("the value to remap the curve's 0 to")]
public float RemapOrthographicSizeZero = 5f;
/// the value to remap the curve's 1 to
[Tooltip("the value to remap the curve's 1 to")]
public float RemapOrthographicSizeOne = 10f;
/// <summary>
/// Triggers the corresponding coroutine
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
MMCameraOrthographicSizeShakeEvent.Trigger(ShakeOrthographicSize, FeedbackDuration, RemapOrthographicSizeZero, RemapOrthographicSizeOne, RelativeOrthographicSize,
feedbacksIntensity, ChannelData, ResetShakerValuesAfterShake, ResetTargetValuesAfterShake, NormalPlayDirection, ComputedTimescaleMode);
}
/// <summary>
/// On stop we stop our transition
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomStopFeedback(Vector3 position, float feedbacksIntensity = 1)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
base.CustomStopFeedback(position, feedbacksIntensity);
MMCameraOrthographicSizeShakeEvent.Trigger(ShakeOrthographicSize, FeedbackDuration,
RemapOrthographicSizeZero, RemapOrthographicSizeOne, stop: true);
}
/// <summary>
/// On restore, we restore our initial state
/// </summary>
protected override void CustomRestoreInitialValues()
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
MMCameraOrthographicSizeShakeEvent.Trigger(ShakeOrthographicSize, FeedbackDuration,
RemapOrthographicSizeZero, RemapOrthographicSizeOne, restore: true);
}
/// <summary>
/// Automatically tries to add a MMCameraFieldOfViewShaker to the main camera, if none are present
/// </summary>
public override void AutomaticShakerSetup()
{
#if MM_CINEMACHINE || MM_CINEMACHINE3
bool virtualCameraFound = false;
#endif
#if MMCINEMACHINE
CinemachineVirtualCamera virtualCamera = (CinemachineVirtualCamera)Object.FindObjectOfType(typeof(CinemachineVirtualCamera));
virtualCameraFound = (virtualCamera != null);
#elif MMCINEMACHINE3
CinemachineCamera virtualCamera = (CinemachineCamera)Object.FindObjectOfType(typeof(CinemachineCamera));
virtualCameraFound = (virtualCamera != null);
#endif
#if MM_CINEMACHINE || MM_CINEMACHINE3
if (virtualCameraFound)
{
MMCinemachineHelpers.AutomaticCinemachineShakersSetup(Owner, "CinemachineImpulse");
return;
}
#endif
MMCameraOrthographicSizeShaker orthographicSizeShaker = (MMCameraOrthographicSizeShaker)Object.FindAnyObjectByType(typeof(MMCameraOrthographicSizeShaker));
if (orthographicSizeShaker != null)
{
return;
}
Camera.main.gameObject.MMGetOrAddComponent<MMCameraOrthographicSizeShaker>();
MMDebug.DebugLogInfo( "Added a MMCameraOrthographicSizeShaker to the main camera. You're all set.");
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 5a5c04124f3de9c4c99bc8ccccb85f21
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Feedbacks/MMF_CameraOrthographicSize.cs
uploadId: 830868

View File

@@ -0,0 +1,117 @@
using MoreMountains.FeedbacksForThirdParty;
using MoreMountains.Tools;
using UnityEngine;
using UnityEngine.Scripting.APIUpdating;
namespace MoreMountains.Feedbacks
{
/// <summary>
/// This feedback will send a shake event when played
/// </summary>
[AddComponentMenu("")]
[FeedbackHelp("Define camera shake properties (duration in seconds, amplitude and frequency), and this will broadcast a MMCameraShakeEvent with these same settings. " +
"You'll need to add a MMCameraShaker on your camera for this to work (or a MMCinemachineCameraShaker component on your virtual camera if you're using Cinemachine). " +
"Note that although this event and system was built for cameras in mind, you could technically use it to shake other objects as well.")]
[System.Serializable]
[FeedbackPath("Camera/Camera Shake")]
[MovedFrom(false, null, "MoreMountains.Feedbacks")]
public class MMF_CameraShake : MMF_Feedback
{
/// a static bool used to disable all feedbacks of this type at once
public static bool FeedbackTypeAuthorized = true;
/// sets the inspector color for this feedback
#if UNITY_EDITOR
public override Color FeedbackColor { get { return MMFeedbacksInspectorColors.CameraColor; } }
public override string RequiredTargetText => RequiredChannelText;
public override bool HasCustomInspectors => true;
public override bool HasAutomaticShakerSetup => true;
#endif
/// the duration of this feedback is the duration of the shake
public override float FeedbackDuration { get { return ApplyTimeMultiplier(CameraShakeProperties.Duration); } set { CameraShakeProperties.Duration = value; } }
public override bool HasChannel => true;
public override bool HasRandomness => true;
[MMFInspectorGroup("Camera Shake", true, 57)]
/// whether or not this shake should repeat forever, until stopped
[Tooltip("whether or not this shake should repeat forever, until stopped")]
public bool RepeatUntilStopped = false;
/// the properties of the shake (duration, intensity, frequenc)
[Tooltip("the properties of the shake (duration, intensity, frequenc)")]
public MMCameraShakeProperties CameraShakeProperties = new MMCameraShakeProperties(0.1f, 0.2f, 40f);
/// <summary>
/// On Play, sends a shake camera event
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
float intensityMultiplier = ComputeIntensity(feedbacksIntensity, position);
MMCameraShakeEvent.Trigger(FeedbackDuration, CameraShakeProperties.Amplitude * intensityMultiplier, CameraShakeProperties.Frequency,
CameraShakeProperties.AmplitudeX * intensityMultiplier, CameraShakeProperties.AmplitudeY * intensityMultiplier, CameraShakeProperties.AmplitudeZ * intensityMultiplier,
RepeatUntilStopped, ChannelData, ComputedTimescaleMode == TimescaleModes.Unscaled);
}
protected override void CustomStopFeedback(Vector3 position, float feedbacksIntensity = 1)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
base.CustomStopFeedback(position, feedbacksIntensity);
MMCameraShakeStopEvent.Trigger(ChannelData);
}
/// <summary>
/// Automatically tries to add a camera rig if none are present
/// </summary>
public override void AutomaticShakerSetup()
{
#if MM_CINEMACHINE || MM_CINEMACHINE3
bool virtualCameraFound = false;
#endif
#if MMCINEMACHINE
CinemachineVirtualCamera virtualCamera = (CinemachineVirtualCamera)Object.FindObjectOfType(typeof(CinemachineVirtualCamera));
virtualCameraFound = (virtualCamera != null);
#elif MMCINEMACHINE3
CinemachineCamera virtualCamera = (CinemachineCamera)Object.FindObjectOfType(typeof(CinemachineCamera));
virtualCameraFound = (virtualCamera != null);
#endif
#if MM_CINEMACHINE || MM_CINEMACHINE3
if (virtualCameraFound)
{
MMCinemachineHelpers.AutomaticCinemachineShakersSetup(Owner, "CinemachineImpulse");
return;
}
#endif
MMCameraShaker camShaker = (MMCameraShaker)Object.FindAnyObjectByType(typeof(MMCameraShaker));
if (camShaker != null)
{
return;
}
GameObject cameraRig = new GameObject("CameraRig");
cameraRig.transform.position = Camera.main.transform.position;
GameObject cameraShaker = new GameObject("CameraShaker");
cameraShaker.transform.SetParent(cameraRig.transform);
cameraShaker.transform.localPosition = Vector3.zero;
cameraShaker.AddComponent<MMCameraShaker>();
MMWiggle wiggle = cameraShaker.GetComponent<MMWiggle>();
wiggle.PositionActive = true;
wiggle.PositionWiggleProperties = new WiggleProperties();
wiggle.PositionWiggleProperties.WigglePermitted = false;
wiggle.PositionWiggleProperties.WiggleType = WiggleTypes.Noise;
Camera.main.transform.SetParent(cameraShaker.transform);
MMDebug.DebugLogInfo( "Added a CameraRig to the main camera. You're all set.");
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: a3cc2a6a2ccbc204299038009e15eb65
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Feedbacks/MMF_CameraShake.cs
uploadId: 830868

View File

@@ -0,0 +1,137 @@
using MoreMountains.FeedbacksForThirdParty;
using MoreMountains.Tools;
using UnityEngine;
using UnityEngine.Scripting.APIUpdating;
namespace MoreMountains.Feedbacks
{
/// <summary>
/// A feedback that will allow you to change the zoom of a (3D) camera when played
/// </summary>
[AddComponentMenu("")]
[FeedbackHelp("Define zoom properties : For will set the zoom to the specified parameters for a certain duration, " +
"Set will leave them like that forever. Zoom properties include the field of view, the duration of the " +
"zoom transition (in seconds) and the zoom duration (the time the camera should remain zoomed in, in seconds). " +
"For this to work, you'll need to add a MMCameraZoom component to your Camera, or a MMCinemachineZoom if you're " +
"using virtual cameras.")]
[MovedFrom(false, null, "MoreMountains.Feedbacks")]
[System.Serializable]
[FeedbackPath("Camera/Camera Zoom")]
public class MMF_CameraZoom : MMF_Feedback
{
/// a static bool used to disable all feedbacks of this type at once
public static bool FeedbackTypeAuthorized = true;
/// sets the inspector color for this feedback
#if UNITY_EDITOR
public override Color FeedbackColor { get { return MMFeedbacksInspectorColors.CameraColor; } }
public override string RequiredTargetText => RequiredChannelText;
public override bool HasCustomInspectors => true;
public override bool HasAutomaticShakerSetup => true;
#endif
/// the duration of this feedback is the duration of the zoom
public override float FeedbackDuration { get { return ApplyTimeMultiplier(ZoomDuration); } set { ZoomDuration = value; } }
public override bool HasChannel => true;
public override bool CanForceInitialValue => true;
[MMFInspectorGroup("Camera Zoom", true, 72)]
/// the zoom mode (for : forward for TransitionDuration, static for Duration, backwards for TransitionDuration)
[Tooltip("the zoom mode (for : forward for TransitionDuration, static for Duration, backwards for TransitionDuration)")]
public MMCameraZoomModes ZoomMode = MMCameraZoomModes.For;
/// the target field of view
[Tooltip("the target field of view")]
public float ZoomFieldOfView = 30f;
/// the zoom transition duration
[Tooltip("the zoom transition duration")]
public float ZoomTransitionDuration = 0.05f;
/// the duration for which the zoom is at max zoom
[Tooltip("the duration for which the zoom is at max zoom")]
public float ZoomDuration = 0.1f;
/// whether or not ZoomFieldOfView should add itself to the current camera's field of view value
[Tooltip("whether or not ZoomFieldOfView should add itself to the current camera's field of view value")]
public bool RelativeFieldOfView = false;
[Header("Transition Speed")]
/// the animation curve to apply to the zoom transition
[Tooltip("the animation curve to apply to the zoom transition")]
public MMTweenType ZoomTween = new MMTweenType( new AnimationCurve(new Keyframe(0f, 0f), new Keyframe(1f, 1f)));
/// <summary>
/// On Play, triggers a zoom event
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
MMCameraZoomEvent.Trigger(ZoomMode, ZoomFieldOfView, ZoomTransitionDuration, FeedbackDuration, ChannelData,
ComputedTimescaleMode == TimescaleModes.Unscaled, false, RelativeFieldOfView, tweenType: ZoomTween);
}
/// <summary>
/// On stop we stop our transition
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomStopFeedback(Vector3 position, float feedbacksIntensity = 1)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
base.CustomStopFeedback(position, feedbacksIntensity);
MMCameraZoomEvent.Trigger(ZoomMode, ZoomFieldOfView, ZoomTransitionDuration, FeedbackDuration, ChannelData,
ComputedTimescaleMode == TimescaleModes.Unscaled, stop:true, tweenType: ZoomTween);
}
/// <summary>
/// On restore, we restore our initial state
/// </summary>
protected override void CustomRestoreInitialValues()
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
MMCameraZoomEvent.Trigger(ZoomMode, ZoomFieldOfView, ZoomTransitionDuration, FeedbackDuration, ChannelData,
ComputedTimescaleMode == TimescaleModes.Unscaled, restore:true, tweenType: ZoomTween);
}
/// <summary>
/// Automatically tries to add a MMCameraZoom to the main camera, if none are present
/// </summary>
public override void AutomaticShakerSetup()
{
#if MM_CINEMACHINE || MM_CINEMACHINE3
bool virtualCameraFound = false;
#endif
#if MMCINEMACHINE
CinemachineVirtualCamera virtualCamera = (CinemachineVirtualCamera)Object.FindObjectOfType(typeof(CinemachineVirtualCamera));
virtualCameraFound = (virtualCamera != null);
#elif MMCINEMACHINE3
CinemachineCamera virtualCamera = (CinemachineCamera)Object.FindObjectOfType(typeof(CinemachineCamera));
virtualCameraFound = (virtualCamera != null);
#endif
#if MM_CINEMACHINE || MM_CINEMACHINE3
if (virtualCameraFound)
{
MMCinemachineHelpers.AutomaticCinemachineShakersSetup(Owner, "CinemachineImpulse");
return;
}
#endif
MMCameraZoom camZoom = (MMCameraZoom)Object.FindAnyObjectByType(typeof(MMCameraZoom));
if (camZoom != null)
{
return;
}
Camera.main.gameObject.MMGetOrAddComponent<MMCameraZoom>();
MMDebug.DebugLogInfo( "Added a MMCameraZoom to the main camera. You're all set.");
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 258c18f9cd813e644ad4c42e5b4f0d02
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Feedbacks/MMF_CameraZoom.cs
uploadId: 830868

View File

@@ -0,0 +1,71 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;using UnityEngine.Scripting.APIUpdating;
namespace MoreMountains.Feedbacks
{
/// <summary>
/// This feedback will let you turn the BlocksRaycast parameter of a target CanvasGroup on or off on play
/// </summary>
[AddComponentMenu("")]
[FeedbackHelp("This feedback will let you turn the BlocksRaycast parameter of a target CanvasGroup on or off on play")]
[MovedFrom(false, null, "MoreMountains.Feedbacks")]
[System.Serializable]
[FeedbackPath("UI/CanvasGroup BlocksRaycasts")]
public class MMF_CanvasGroupBlocksRaycasts : MMF_Feedback
{
/// a static bool used to disable all feedbacks of this type at once
public static bool FeedbackTypeAuthorized = true;
#if UNITY_EDITOR
public override Color FeedbackColor { get { return MMFeedbacksInspectorColors.UIColor; } }
public override bool EvaluateRequiresSetup() { return (TargetCanvasGroup == null); }
public override string RequiredTargetText { get { return TargetCanvasGroup != null ? TargetCanvasGroup.name : ""; } }
public override string RequiresSetupText { get { return "This feedback requires that a TargetCanvasGroup be set to be able to work properly. You can set one below."; } }
#endif
public override bool HasAutomatedTargetAcquisition => true;
protected override void AutomateTargetAcquisition() => TargetCanvasGroup = FindAutomatedTarget<CanvasGroup>();
[MMFInspectorGroup("Block Raycasts", true, 54, true)]
/// the target canvas group we want to control the BlocksRaycasts parameter on
[Tooltip("the target canvas group we want to control the BlocksRaycasts parameter on")]
public CanvasGroup TargetCanvasGroup;
/// if this is true, on play, the target canvas group will block raycasts, if false it won't
[Tooltip("if this is true, on play, the target canvas group will block raycasts, if false it won't")]
public bool ShouldBlockRaycasts = true;
protected bool _initialState;
/// <summary>
/// On play we turn raycast block on or off
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
if (TargetCanvasGroup == null)
{
return;
}
_initialState = TargetCanvasGroup.blocksRaycasts;
TargetCanvasGroup.blocksRaycasts = ShouldBlockRaycasts;
}
/// <summary>
/// On restore, we restore our initial state
/// </summary>
protected override void CustomRestoreInitialValues()
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
TargetCanvasGroup.blocksRaycasts = _initialState;
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 8d3188dd93bc22141a98ee77523b7853
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Feedbacks/MMF_CanvasGroupBlocksRaycasts.cs
uploadId: 830868

View File

@@ -0,0 +1,130 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Scripting.APIUpdating;
namespace MoreMountains.Feedbacks
{
/// <summary>
/// This feedback will let you enable/disable/toggle a target collider, or change its trigger status
/// </summary>
[AddComponentMenu("")]
[FeedbackHelp("This feedback will let you enable/disable/toggle a target collider, or change its trigger status")]
[MovedFrom(false, null, "MoreMountains.Feedbacks")]
[System.Serializable]
[FeedbackPath("GameObject/Collider")]
public class MMF_Collider : MMF_Feedback
{
/// a static bool used to disable all feedbacks of this type at once
public static bool FeedbackTypeAuthorized = true;
/// sets the inspector color for this feedback
#if UNITY_EDITOR
public override Color FeedbackColor { get { return MMFeedbacksInspectorColors.GameObjectColor; } }
public override bool EvaluateRequiresSetup() { return (TargetCollider == null); }
public override string RequiredTargetText { get { return TargetCollider != null ? TargetCollider.name : ""; } }
public override string RequiresSetupText { get { return "This feedback requires that a TargetCollider be set to be able to work properly. You can set one below."; } }
#endif
public override bool HasAutomatedTargetAcquisition => true;
protected override void AutomateTargetAcquisition() => TargetCollider = FindAutomatedTarget<Collider>();
/// the possible effects the feedback can have on the target collider's status
public enum Modes { Enable, Disable, ToggleActive, Trigger, NonTrigger, ToggleTrigger }
[MMFInspectorGroup("Collider", true, 12, true)]
/// the collider to act upon
[Tooltip("the collider to act upon")]
public Collider TargetCollider;
/// the effect the feedback will have on the target collider's status
public Modes Mode = Modes.Disable;
protected bool _initialState;
/// <summary>
/// On Play we change the state of our collider if needed
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
if (TargetCollider != null)
{
ApplyChanges(Mode);
}
}
/// <summary>
/// Changes the state of the collider
/// </summary>
/// <param name="state"></param>
protected virtual void ApplyChanges(Modes mode)
{
switch (mode)
{
case Modes.Enable:
_initialState = TargetCollider.enabled;
TargetCollider.enabled = true;
break;
case Modes.Disable:
_initialState = TargetCollider.enabled;
TargetCollider.enabled = false;
break;
case Modes.ToggleActive:
_initialState = TargetCollider.enabled;
TargetCollider.enabled = !TargetCollider.enabled;
break;
case Modes.Trigger:
_initialState = TargetCollider.isTrigger;
TargetCollider.isTrigger = true;
break;
case Modes.NonTrigger:
_initialState = TargetCollider.isTrigger;
TargetCollider.isTrigger = false;
break;
case Modes.ToggleTrigger:
_initialState = TargetCollider.isTrigger;
TargetCollider.isTrigger = !TargetCollider.isTrigger;
break;
default:
throw new ArgumentOutOfRangeException(nameof(mode), mode, null);
}
}
/// <summary>
/// On restore, we put our object back at its initial position
/// </summary>
protected override void CustomRestoreInitialValues()
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
switch (Mode)
{
case Modes.Enable:
TargetCollider.enabled = _initialState;
break;
case Modes.Disable:
TargetCollider.enabled = _initialState;
break;
case Modes.ToggleActive:
TargetCollider.enabled = _initialState;
break;
case Modes.Trigger:
TargetCollider.isTrigger = _initialState;
break;
case Modes.NonTrigger:
TargetCollider.isTrigger = _initialState;
break;
case Modes.ToggleTrigger:
TargetCollider.isTrigger = _initialState;
break;
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: eba8f600b11482740a9ae555e6cd1ea9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Feedbacks/MMF_Collider.cs
uploadId: 830868

View File

@@ -0,0 +1,129 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Scripting.APIUpdating;
namespace MoreMountains.Feedbacks
{
#if MM_PHYSICS2D
/// <summary>
/// This feedback will let you enable/disable/toggle a target collider 2D, or change its trigger status
/// </summary>
[AddComponentMenu("")]
[FeedbackHelp("This feedback will let you enable/disable/toggle a target collider 2D, or change its trigger status")]
[MovedFrom(false, null, "MoreMountains.Feedbacks")]
[System.Serializable]
[FeedbackPath("GameObject/Collider2D")]
public class MMF_Collider2D : MMF_Feedback
{
/// a static bool used to disable all feedbacks of this type at once
public static bool FeedbackTypeAuthorized = true;
/// sets the inspector color for this feedback
#if UNITY_EDITOR
public override Color FeedbackColor { get { return MMFeedbacksInspectorColors.GameObjectColor; } }
public override bool EvaluateRequiresSetup() { return (TargetCollider2D == null); }
public override string RequiredTargetText { get { return TargetCollider2D != null ? TargetCollider2D.name : ""; } }
public override string RequiresSetupText { get { return "This feedback requires that a TargetCollider2D be set to be able to work properly. You can set one below."; } }
#endif
public override bool HasAutomatedTargetAcquisition => true;
protected override void AutomateTargetAcquisition() => TargetCollider2D = FindAutomatedTarget<Collider2D>();
/// the possible effects the feedback can have on the target collider's status
public enum Modes { Enable, Disable, ToggleActive, Trigger, NonTrigger, ToggleTrigger }
[MMFInspectorGroup("Collider 2D", true, 12, true)]
/// the collider to act upon
[Tooltip("the collider to act upon")]
public Collider2D TargetCollider2D;
/// the effect the feedback will have on the target collider's status
public Modes Mode = Modes.Disable;
protected bool _initialState;
/// <summary>
/// On Play we change the state of our collider if needed
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized || (TargetCollider2D == null))
{
return;
}
ApplyChanges(Mode);
}
/// <summary>
/// Changes the state of the collider
/// </summary>
/// <param name="state"></param>
protected virtual void ApplyChanges(Modes mode)
{
switch (mode)
{
case Modes.Enable:
_initialState = TargetCollider2D.enabled;
TargetCollider2D.enabled = true;
break;
case Modes.Disable:
_initialState = TargetCollider2D.enabled;
TargetCollider2D.enabled = false;
break;
case Modes.ToggleActive:
_initialState = TargetCollider2D.enabled;
TargetCollider2D.enabled = !TargetCollider2D.enabled;
break;
case Modes.Trigger:
_initialState = TargetCollider2D.isTrigger;
TargetCollider2D.isTrigger = true;
break;
case Modes.NonTrigger:
_initialState = TargetCollider2D.isTrigger;
TargetCollider2D.isTrigger = false;
break;
case Modes.ToggleTrigger:
_initialState = TargetCollider2D.isTrigger;
TargetCollider2D.isTrigger = !TargetCollider2D.isTrigger;
break;
default:
throw new ArgumentOutOfRangeException(nameof(mode), mode, null);
}
}
/// <summary>
/// On restore, we put our object back at its initial position
/// </summary>
protected override void CustomRestoreInitialValues()
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
switch (Mode)
{
case Modes.Enable:
TargetCollider2D.enabled = _initialState;
break;
case Modes.Disable:
TargetCollider2D.enabled = _initialState;
break;
case Modes.ToggleActive:
TargetCollider2D.enabled = _initialState;
break;
case Modes.Trigger:
TargetCollider2D.isTrigger = _initialState;
break;
case Modes.NonTrigger:
TargetCollider2D.isTrigger = _initialState;
break;
case Modes.ToggleTrigger:
TargetCollider2D.isTrigger = _initialState;
break;
}
}
}
#endif
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: b117019c414540246a342a9d82792889
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Feedbacks/MMF_Collider2D.cs
uploadId: 830868

View File

@@ -0,0 +1,292 @@
using System.Collections;
using System.Collections.Generic;
using MoreMountains.Tools;
using UnityEngine;
using UnityEngine.Scripting.APIUpdating;
namespace MoreMountains.Feedbacks
{
/// <summary>
/// This feedback will let you animate the position/rotation/scale of a target transform to match the one of a destination transform.
/// </summary>
[AddComponentMenu("")]
[FeedbackHelp("This feedback will let you animate the position/rotation/scale of a target transform to match the one of a destination transform.")]
[MovedFrom(false, null, "MoreMountains.Feedbacks")]
[System.Serializable]
[FeedbackPath("Transform/Destination")]
public class MMF_DestinationTransform : MMF_Feedback
{
/// a static bool used to disable all feedbacks of this type at once
public static bool FeedbackTypeAuthorized = true;
/// the possible timescales this feedback can animate on
public enum TimeScales { Scaled, Unscaled }
/// sets the inspector color for this feedback
#if UNITY_EDITOR
public override Color FeedbackColor { get { return MMFeedbacksInspectorColors.TransformColor; } }
public override bool EvaluateRequiresSetup() { return (TargetTransform == null) || (Destination == null); }
public override string RequiredTargetText { get { return TargetTransform != null ? TargetTransform.name : ""; } }
public override string RequiresSetupText { get { return "This feedback requires that a TargetTransform and a Destination be set to be able to work properly. You can set one below."; } }
public override bool HasCustomInspectors { get { return true; } }
#endif
public override bool HasAutomatedTargetAcquisition => true;
protected override void AutomateTargetAcquisition() => TargetTransform = FindAutomatedTarget<Transform>();
[MMFInspectorGroup("Target to animate", true, 61, true)]
/// the target transform we want to animate properties on
[Tooltip("the target transform we want to animate properties on")]
public Transform TargetTransform;
/// whether or not we want to force an origin transform. If not, the current position of the target transform will be used as origin instead
[Tooltip("whether or not we want to force an origin transform. If not, the current position of the target transform will be used as origin instead")]
public bool ForceOrigin = false;
/// the transform to use as origin in ForceOrigin mode
[Tooltip("the transform to use as origin in ForceOrigin mode")]
[MMFCondition("ForceOrigin", true)]
public Transform Origin;
/// the destination transform whose properties we want to match
[Tooltip("the destination transform whose properties we want to match")]
public Transform Destination;
[MMFInspectorGroup("Transition", true, 63)]
/// a global curve to animate all properties on, unless dedicated ones are specified
[Tooltip("a global curve to animate all properties on, unless dedicated ones are specified")]
public MMTweenType GlobalAnimationTween = new MMTweenType( new AnimationCurve(new Keyframe(0, 0), new Keyframe(0.3f, 1f), new Keyframe(1, 0)));
/// the duration of the transition, in seconds
[Tooltip("the duration of the transition, in seconds")]
public float Duration = 0.2f;
/// if this is true, the destination will be updated every frame, allowing for dynamic changes to the destination transform, otherwise the destination will be cached on init and not updated after that
[Tooltip("if this is true, the destination will be updated every frame, allowing for dynamic changes to the destination transform, otherwise the destination will be cached on init and not updated after that")]
public bool UpdateDestinationEveryFrame = false;
[MMFInspectorGroup("Axis Locks", true, 64)]
/// whether or not to animate the X position
[Tooltip("whether or not to animate the X Position")]
public bool AnimatePositionX = true;
/// whether or not to animate the Y position
[Tooltip("whether or not to animate the Y Position")]
public bool AnimatePositionY = true;
/// whether or not to animate the Z position
[Tooltip("whether or not to animate the Z Position")]
public bool AnimatePositionZ = true;
/// whether or not to animate the X rotation
[Tooltip("whether or not to animate the X rotation")]
public bool AnimateRotationX = true;
/// whether or not to animate the Y rotation
[Tooltip("whether or not to animate the Y rotation")]
public bool AnimateRotationY = true;
/// whether or not to animate the Z rotation
[Tooltip("whether or not to animate the Z rotation")]
public bool AnimateRotationZ = true;
/// whether or not to animate the W rotation
[Tooltip("whether or not to animate the W rotation")]
public bool AnimateRotationW = true;
/// whether or not to animate the X scale
[Tooltip("whether or not to animate the X scale")]
public bool AnimateScaleX = true;
/// whether or not to animate the Y scale
[Tooltip("whether or not to animate the Y scale")]
public bool AnimateScaleY = true;
/// whether or not to animate the Z scale
[Tooltip("whether or not to animate the Z scale")]
public bool AnimateScaleZ = true;
[MMFInspectorGroup("Separate Curves", true, 65)]
/// whether or not to use a separate animation curve to animate the position
[Tooltip("whether or not to use a separate animation curve to animate the position")]
public bool SeparatePositionCurve = false;
/// the curve to use to animate the position on
[Tooltip("the curve to use to animate the position on")]
public MMTweenType AnimatePositionTween = new MMTweenType( new AnimationCurve(new Keyframe(0, 0), new Keyframe(0.3f, 1f), new Keyframe(1, 0)), "SeparatePositionCurve");
/// whether or not to use a separate animation curve to animate the rotation
[Tooltip("whether or not to use a separate animation curve to animate the rotation")]
public bool SeparateRotationCurve = false;
/// the curve to use to animate the rotation on
[Tooltip("the curve to use to animate the rotation on")]
public MMTweenType AnimateRotationTween = new MMTweenType( new AnimationCurve(new Keyframe(0, 0), new Keyframe(0.3f, 1f), new Keyframe(1, 0)), "SeparateRotationCurve");
/// whether or not to use a separate animation curve to animate the scale
[Tooltip("whether or not to use a separate animation curve to animate the scale")]
public bool SeparateScaleCurve = false;
/// the curve to use to animate the scale on
[Tooltip("the curve to use to animate the scale on")]
public MMTweenType AnimateScaleTween = new MMTweenType( new AnimationCurve(new Keyframe(0, 0), new Keyframe(0.3f, 1f), new Keyframe(1, 0)), "SeparateScaleCurve");
/// the duration of this feedback is the duration of the movement
public override float FeedbackDuration { get { return ApplyTimeMultiplier(Duration); } set { Duration = value; } }
/// a global curve to animate all properties on, unless dedicated ones are specified
[HideInInspector] public AnimationCurve GlobalAnimationCurve = null;
/// the curve to use to animate the position on
[HideInInspector] public AnimationCurve AnimateScaleCurve = null;
/// the curve to use to animate the rotation on
[HideInInspector] public AnimationCurve AnimatePositionCurve = null;
/// the curve to use to animate the scale on
[HideInInspector] public AnimationCurve AnimateRotationCurve = null;
protected Coroutine _coroutine;
protected Vector3 _newPosition;
protected Quaternion _newRotation;
protected Vector3 _newScale;
protected Vector3 _pointAPosition;
protected Vector3 _pointBPosition;
protected Quaternion _pointARotation;
protected Quaternion _pointBRotation;
protected Vector3 _pointAScale;
protected Vector3 _pointBScale;
protected MMTweenType _animationTweenType;
protected Vector3 _initialPosition;
protected Vector3 _initialScale;
protected Quaternion _initialRotation;
/// <summary>
/// On Play we animate the pos/rotation/scale of the target transform towards its destination
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized || (TargetTransform == null))
{
return;
}
if (_coroutine != null) { Owner.StopCoroutine(_coroutine); }
_coroutine = Owner.StartCoroutine(AnimateToDestination());
}
/// <summary>
/// A coroutine used to animate the pos/rotation/scale of the target transform towards its destination
/// </summary>
/// <returns></returns>
protected virtual IEnumerator AnimateToDestination()
{
_initialPosition = TargetTransform.position;
_initialRotation = TargetTransform.rotation;
_initialScale = TargetTransform.localScale;
_pointAPosition = ForceOrigin ? Origin.transform.position : TargetTransform.position;
_pointARotation = ForceOrigin ? Origin.transform.rotation : TargetTransform.rotation;
_pointAScale = ForceOrigin ? Origin.transform.localScale : TargetTransform.localScale;
CacheDestinationValues();
IsPlaying = true;
float journey = NormalPlayDirection ? 0f : FeedbackDuration;
while ((journey >= 0) && (journey <= FeedbackDuration) && (FeedbackDuration > 0))
{
if (UpdateDestinationEveryFrame)
{
CacheDestinationValues();
}
float percent = Mathf.Clamp01(journey / FeedbackDuration);
ChangeTransformValues(percent);
journey += NormalPlayDirection ? FeedbackDeltaTime : -FeedbackDeltaTime;
yield return null;
}
// set final position
ChangeTransformValues(1f);
IsPlaying = false;
_coroutine = null;
yield break;
}
protected virtual void CacheDestinationValues()
{
_pointBPosition = Destination.transform.position;
if (!AnimatePositionX) { _pointAPosition.x = TargetTransform.position.x; _pointBPosition.x = _pointAPosition.x; }
if (!AnimatePositionY) { _pointAPosition.y = TargetTransform.position.y; _pointBPosition.y = _pointAPosition.y; }
if (!AnimatePositionZ) { _pointAPosition.z = TargetTransform.position.z; _pointBPosition.z = _pointAPosition.z; }
_pointBRotation = Destination.transform.rotation;
if (!AnimateRotationX) { _pointARotation.x = TargetTransform.rotation.x; _pointBRotation.x = _pointARotation.x; }
if (!AnimateRotationY) { _pointARotation.y = TargetTransform.rotation.y; _pointBRotation.y = _pointARotation.y; }
if (!AnimateRotationZ) { _pointARotation.z = TargetTransform.rotation.z; _pointBRotation.z = _pointARotation.z; }
if (!AnimateRotationW) { _pointARotation.w = TargetTransform.rotation.w; _pointBRotation.w = _pointARotation.w; }
_pointBScale = Destination.transform.localScale;
if (!AnimateScaleX) { _pointAScale.x = TargetTransform.localScale.x; _pointBScale.x = _pointAScale.x; }
if (!AnimateScaleY) { _pointAScale.y = TargetTransform.localScale.y; _pointBScale.y = _pointAScale.y; }
if (!AnimateScaleZ) { _pointAScale.z = TargetTransform.localScale.z; _pointBScale.z = _pointAScale.z; }
}
/// <summary>
/// Computes the new position, rotation and scale for our transform, and applies it to the transform
/// </summary>
/// <param name="percent"></param>
protected virtual void ChangeTransformValues(float percent)
{
_animationTweenType = SeparatePositionCurve ? AnimatePositionTween : GlobalAnimationTween;
_newPosition = Vector3.LerpUnclamped(_pointAPosition, _pointBPosition, _animationTweenType.Evaluate(percent));
_animationTweenType = SeparateRotationCurve ? AnimateRotationTween : GlobalAnimationTween;
_newRotation = Quaternion.LerpUnclamped(_pointARotation, _pointBRotation, _animationTweenType.Evaluate(percent));
_animationTweenType = SeparateScaleCurve ? AnimateScaleTween : GlobalAnimationTween;
_newScale = Vector3.LerpUnclamped(_pointAScale, _pointBScale, _animationTweenType.Evaluate(percent));
TargetTransform.position = _newPosition;
TargetTransform.rotation = _newRotation;
TargetTransform.localScale = _newScale;
}
/// <summary>
/// On Stop we stop our coroutine if needed
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomStopFeedback(Vector3 position, float feedbacksIntensity = 1)
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
base.CustomStopFeedback(position, feedbacksIntensity);
IsPlaying = false;
if ((TargetTransform != null) && (_coroutine != null))
{
Owner.StopCoroutine(_coroutine);
}
}
/// <summary>
/// On restore, we restore our initial state
/// </summary>
protected override void CustomRestoreInitialValues()
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
TargetTransform.position = _initialPosition;
TargetTransform.rotation = _initialRotation;
TargetTransform.localScale = _initialScale;
}
/// <summary>
/// On Validate, we migrate our deprecated animation curves to our tween types if needed
/// </summary>
public override void OnValidate()
{
base.OnValidate();
MMFeedbacksHelpers.MigrateCurve(GlobalAnimationCurve, GlobalAnimationTween, Owner);
MMFeedbacksHelpers.MigrateCurve(AnimatePositionCurve, AnimatePositionTween, Owner);
MMFeedbacksHelpers.MigrateCurve(AnimateRotationCurve, AnimateRotationTween, Owner);
MMFeedbacksHelpers.MigrateCurve(AnimateScaleCurve, AnimateScaleTween, Owner);
if (string.IsNullOrEmpty(AnimatePositionTween.ConditionPropertyName))
{
AnimatePositionTween.ConditionPropertyName = "SeparatePositionCurve";
AnimateRotationTween.ConditionPropertyName = "SeparateRotationCurve";
AnimateScaleTween.ConditionPropertyName = "SeparateScaleCurve";
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 2a22f321adcb1374cb909aee327ff9f0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Feedbacks/MMF_DestinationTransform.cs
uploadId: 830868

View File

@@ -0,0 +1,102 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Scripting.APIUpdating;
namespace MoreMountains.Feedbacks
{
/// <summary>
/// This feedback allows you to destroy a target gameobject, either via Destroy, DestroyImmediate, or SetActive:False
/// </summary>
[AddComponentMenu("")]
[FeedbackHelp("This feedback allows you to destroy a target gameobject, either via Destroy, DestroyImmediate, or SetActive:False")]
[MovedFrom(false, null, "MoreMountains.Feedbacks")]
[System.Serializable]
[FeedbackPath("GameObject/Destroy")]
public class MMF_Destroy : MMF_Feedback
{
/// a static bool used to disable all feedbacks of this type at once
public static bool FeedbackTypeAuthorized = true;
/// sets the inspector color for this feedback
#if UNITY_EDITOR
public override Color FeedbackColor { get { return MMFeedbacksInspectorColors.GameObjectColor; } }
public override bool EvaluateRequiresSetup() { return (TargetGameObject == null); }
public override string RequiredTargetText { get { return TargetGameObject != null ? TargetGameObject.name : ""; } }
public override string RequiresSetupText { get { return "This feedback requires that a TargetGameObject be set to be able to work properly. You can set one below."; } }
#endif
public override bool HasAutomatedTargetAcquisition => true;
protected override void AutomateTargetAcquisition() => TargetGameObject = FindAutomatedTargetGameObject();
/// the possible ways to destroy an object
public enum Modes { Destroy, DestroyImmediate, Disable }
[MMFInspectorGroup("Destruction", true, 18, true)]
/// the gameobject we want to change the active state of
[Tooltip("the game object we want to destroy")]
public GameObject TargetGameObject;
/// the optional list of extra gameobjects we want to change the active state of
[Tooltip("the optional list of extra gameobjects we want to change the active state of")]
public List<GameObject> ExtraTargetGameObjects;
/// the selected destruction mode
[Tooltip("the selected destruction mode")]
public Modes Mode;
protected bool _initialActiveState;
/// <summary>
/// On Play we change the state of our Behaviour if needed
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized || (TargetGameObject == null))
{
return;
}
ProceedWithDestruction(TargetGameObject);
foreach (GameObject go in ExtraTargetGameObjects)
{
ProceedWithDestruction(go);
}
}
/// <summary>
/// Changes the status of the Behaviour
/// </summary>
/// <param name="state"></param>
protected virtual void ProceedWithDestruction(GameObject go)
{
switch (Mode)
{
case Modes.Destroy:
Owner.ProxyDestroy(go);
break;
case Modes.DestroyImmediate:
Owner.ProxyDestroyImmediate(go);
break;
case Modes.Disable:
_initialActiveState = go.activeInHierarchy;
go.SetActive(false);
break;
}
}
/// <summary>
/// On restore, we put our object back at its initial position
/// </summary>
protected override void CustomRestoreInitialValues()
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
if (Mode == Modes.Disable)
{
TargetGameObject.SetActive(_initialActiveState);
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 1ed6dae7e25050744b45262d80b35bdf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Feedbacks/MMF_Destroy.cs
uploadId: 830868

View File

@@ -0,0 +1,197 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Scripting.APIUpdating;
namespace MoreMountains.Feedbacks
{
/// <summary>
/// Turns an object active or inactive at the various stages of the feedback
/// </summary>
[AddComponentMenu("")]
[FeedbackHelp("This feedback allows you to change the state of a behaviour on a target gameobject from active to inactive (or the opposite), on init, play, stop or reset. " +
"For each of these you can specify if you want to force a state (enabled or disabled), or toggle it (enabled becomes disabled, disabled becomes enabled).")]
[MovedFrom(false, null, "MoreMountains.Feedbacks")]
[System.Serializable]
[FeedbackPath("GameObject/Enable Behaviour")]
public class MMF_Enable : MMF_Feedback
{
/// a static bool used to disable all feedbacks of this type at once
public static bool FeedbackTypeAuthorized = true;
/// sets the inspector color for this feedback
#if UNITY_EDITOR
public override Color FeedbackColor { get { return MMFeedbacksInspectorColors.GameObjectColor; } }
public override bool EvaluateRequiresSetup() { return (TargetBehaviour == null); }
public override string RequiredTargetText { get { return TargetBehaviour != null ? TargetBehaviour.name : ""; } }
public override string RequiresSetupText { get { return "This feedback requires that a TargetBehaviour be set to be able to work properly. You can set one below."; } }
#endif
/// the possible effects the feedback can have on the target object's status
public enum PossibleStates { Enabled, Disabled, Toggle }
[MMFInspectorGroup("Enable Target Monobehaviour", true, 86, true)]
/// the gameobject we want to change the active state of
[Tooltip("the gameobject we want to change the active state of")]
public Behaviour TargetBehaviour;
/// a list of extra gameobjects we want to change the active state of
[Tooltip("a list of extra gameobjects we want to change the active state of")]
public List<Behaviour> ExtraTargetBehaviours;
/// whether or not we should alter the state of the target object on init
[Tooltip("whether or not we should alter the state of the target object on init")]
public bool SetStateOnInit = false;
/// how to change the state on init
[MMFCondition("SetStateOnInit", true)]
[Tooltip("how to change the state on init")]
public PossibleStates StateOnInit = PossibleStates.Disabled;
/// whether or not we should alter the state of the target object on play
[Tooltip("whether or not we should alter the state of the target object on play")]
public bool SetStateOnPlay = false;
/// how to change the state on play
[MMFCondition("SetStateOnPlay", true)]
[Tooltip("how to change the state on play")]
public PossibleStates StateOnPlay = PossibleStates.Disabled;
/// whether or not we should alter the state of the target object on stop
[Tooltip("whether or not we should alter the state of the target object on stop")]
public bool SetStateOnStop = false;
/// how to change the state on stop
[Tooltip("how to change the state on stop")]
[MMFCondition("SetStateOnStop", true)]
public PossibleStates StateOnStop = PossibleStates.Disabled;
/// whether or not we should alter the state of the target object on reset
[Tooltip("whether or not we should alter the state of the target object on reset")]
public bool SetStateOnReset = false;
/// how to change the state on reset
[Tooltip("how to change the state on reset")]
[MMFCondition("SetStateOnReset", true)]
public PossibleStates StateOnReset = PossibleStates.Disabled;
protected bool _initialState;
/// <summary>
/// On init we change the state of our Behaviour if needed
/// </summary>
/// <param name="owner"></param>
protected override void CustomInitialization(MMF_Player owner)
{
base.CustomInitialization(owner);
if (Active && (TargetBehaviour != null))
{
if (SetStateOnInit)
{
SetStatus(StateOnInit);
}
}
}
/// <summary>
/// On Play we change the state of our Behaviour if needed
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized || (TargetBehaviour == null))
{
return;
}
if (SetStateOnPlay)
{
SetStatus(StateOnPlay);
}
}
/// <summary>
/// On Stop we change the state of our Behaviour if needed
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomStopFeedback(Vector3 position, float feedbacksIntensity = 1)
{
if (!Active || !FeedbackTypeAuthorized || (TargetBehaviour == null))
{
return;
}
base.CustomStopFeedback(position, feedbacksIntensity);
if (SetStateOnStop)
{
SetStatus(StateOnStop);
}
}
/// <summary>
/// On Reset we change the state of our Behaviour if needed
/// </summary>
protected override void CustomReset()
{
base.CustomReset();
if (InCooldown)
{
return;
}
if (!Active || !FeedbackTypeAuthorized || (TargetBehaviour == null))
{
return;
}
if (SetStateOnReset)
{
SetStatus(StateOnReset);
}
}
/// <summary>
/// Changes the status of the Behaviour
/// </summary>
/// <param name="state"></param>
protected virtual void SetStatus(PossibleStates state)
{
SetStatus(state, TargetBehaviour);
foreach (Behaviour extra in ExtraTargetBehaviours)
{
SetStatus(state, extra);
}
}
/// <summary>
/// Sets the specified status on the target Behaviour
/// </summary>
/// <param name="state"></param>
/// <param name="target"></param>
protected virtual void SetStatus(PossibleStates state, Behaviour target)
{
_initialState = target.enabled;
switch (state)
{
case PossibleStates.Enabled:
target.enabled = NormalPlayDirection ? true : false;
break;
case PossibleStates.Disabled:
target.enabled = NormalPlayDirection ? false : true;
break;
case PossibleStates.Toggle:
target.enabled = !target.enabled;
break;
}
}
/// <summary>
/// On restore, we put our object back at its initial position
/// </summary>
protected override void CustomRestoreInitialValues()
{
if (!Active || !FeedbackTypeAuthorized)
{
return;
}
TargetBehaviour.enabled = _initialState;
foreach (Behaviour extra in ExtraTargetBehaviours)
{
extra.enabled = _initialState;
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 15fc18f096da54f4c9777f3cabf74f3a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Feedbacks/MMF_Enable.cs
uploadId: 830868

View File

@@ -0,0 +1,94 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Scripting.APIUpdating;
namespace MoreMountains.Feedbacks
{
/// <summary>
/// A feedback to bind Unity events to and trigger them when played
/// </summary>
[AddComponentMenu("")]
[FeedbackHelp("This feedback allows you to bind any type of Unity events to this feebdack's Play, Stop, Initialization and Reset methods.")]
[MovedFrom(false, null, "MoreMountains.Feedbacks")]
[System.Serializable]
[FeedbackPath("Events/Unity Events")]
public class MMF_Events : MMF_Feedback
{
/// a static bool used to disable all feedbacks of this type at once
public static bool FeedbackTypeAuthorized = true;
/// sets the inspector color for this feedback
#if UNITY_EDITOR
public override Color FeedbackColor { get { return MMFeedbacksInspectorColors.EventsColor; } }
#endif
[MMFInspectorGroup("Events", true, 44)]
/// the events to trigger when the feedback is played
[Tooltip("the events to trigger when the feedback is played")]
public UnityEvent PlayEvents;
/// the events to trigger when the feedback is stopped
[Tooltip("the events to trigger when the feedback is stopped")]
public UnityEvent StopEvents;
/// the events to trigger when the feedback is initialized
[Tooltip("the events to trigger when the feedback is initialized")]
public UnityEvent InitializationEvents;
/// the events to trigger when the feedback is reset
[Tooltip("the events to trigger when the feedback is reset")]
public UnityEvent ResetEvents;
/// <summary>
/// On init, triggers the init events
/// </summary>
/// <param name="owner"></param>
protected override void CustomInitialization(MMF_Player owner)
{
base.CustomInitialization(owner);
if (Active && (InitializationEvents != null))
{
InitializationEvents.Invoke();
}
}
/// <summary>
/// On Play, triggers the play events
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomPlayFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized || (PlayEvents == null))
{
return;
}
PlayEvents.Invoke();
}
/// <summary>
/// On Stop, triggers the stop events
/// </summary>
/// <param name="position"></param>
/// <param name="feedbacksIntensity"></param>
protected override void CustomStopFeedback(Vector3 position, float feedbacksIntensity = 1.0f)
{
if (!Active || !FeedbackTypeAuthorized || (StopEvents == null))
{
return;
}
StopEvents.Invoke();
}
/// <summary>
/// On reset, triggers the reset events
/// </summary>
protected override void CustomReset()
{
if (!Active || !FeedbackTypeAuthorized || (ResetEvents == null))
{
return;
}
base.CustomReset();
ResetEvents.Invoke();
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 931b39b62e090af46bb775a436d4cb0e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 183370
packageName: Feel
packageVersion: 5.9.1
assetPath: Assets/Feel/MMFeedbacks/MMFeedbacks/Feedbacks/MMF_Events.cs
uploadId: 830868

Some files were not shown because too many files have changed in this diff Show More