Insanely huge initial commit

This commit is contained in:
2026-02-21 17:04:05 -08:00
parent 9cdd36191a
commit 613d75914a
22525 changed files with 4035207 additions and 0 deletions

View File

@@ -0,0 +1,273 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
namespace MoreMountains.Tools
{
[System.Serializable]
public class MMRadioSignalOnValueChange : UnityEvent<float> { }
/// <summary>
/// A class used to define a signal, meant to be broadcasted by a MMRadioBroadcaster
/// It'll output a Level value to broadcast, using one time, persistent or driven modes
/// Meant to be extended
/// </summary>
public abstract class MMRadioSignal : MonoBehaviour
{
/// the possible modes a radio signal can operate on
/// - one time : plays its signal once, goes back to sleep
/// - outputs a signal constantly while not sleeping
/// - driven : lets you drive the level value from another script
public enum SignalModes { OneTime, Persistent, Driven }
/// whether this signal operates on scaled or unscaled time
public enum TimeScales { Unscaled, Scaled }
/// the level, to read from a MMRadioBroadcaster
public virtual float Level { get { return CurrentLevel; } }
/// the time, unscaled or scaled
public float TimescaleTime { get { return (TimeScale == TimeScales.Scaled) ? Time.time : Time.unscaledTime; } }
/// the delta time, unscaled or not
public float TimescaleDeltaTime { get { return (TimeScale == TimeScales.Scaled) ? Time.deltaTime : Time.unscaledDeltaTime; } }
[Header("Signal")]
/// the selected signal mode
public SignalModes SignalMode = SignalModes.Persistent;
/// the selected time scale
public TimeScales TimeScale = TimeScales.Unscaled;
/// the duration of the shake, in seconds
public float Duration = 2f;
/// a global multiplier to apply to the end result of the combination
public float GlobalMultiplier = 1f;
/// the current level, not to be read from a broadcaster (it's best to use the property than the field, fields generate garbage)
[MMReadOnly]
public float CurrentLevel = 0f;
[Header("Play Settings")]
/// whether or not this shaker is shaking right now
[MMReadOnly]
public bool Playing = false;
/// the driver time, that can be controlled from another class if you're in Driven mode
[Range(0f, 1f)]
public float DriverTime;
/// if this is true this shaker will play on awake
public bool PlayOnStart = true;
/// an event to trigger on value change
public MMRadioSignalOnValueChange OnValueChange;
/// a test button to start shaking
[Header(("Debug"))]
[MMInspectorButton("StartShaking")]
public bool StartShakingButton;
protected float _signalTime = 0f;
protected float _shakeStartedTimestamp;
protected float _levelLastFrame;
/// <summary>
/// On Awake we grab our volume and profile
/// </summary>
protected virtual void Awake()
{
Initialization();
if (PlayOnStart)
{
StartShaking();
}
this.enabled = PlayOnStart;
}
/// <summary>
/// Override this method to initialize your shaker
/// </summary>
protected virtual void Initialization()
{
CurrentLevel = 0f;
}
/// <summary>
/// Starts shaking the values
/// </summary>
public virtual void StartShaking()
{
if (Playing)
{
return;
}
else
{
this.enabled = true;
_shakeStartedTimestamp = TimescaleTime;
Playing = true;
ShakeStarts();
}
}
/// <summary>
/// Describes what happens when a shake starts
/// </summary>
protected virtual void ShakeStarts()
{
}
/// <summary>
/// On Update, we shake our values if needed, or reset if our shake has ended
/// </summary>
protected virtual void Update()
{
ProcessUpdate();
if (SignalMode == SignalModes.Driven)
{
ProcessDrivenMode();
}
else if (SignalMode == SignalModes.Persistent)
{
_signalTime += TimescaleDeltaTime;
if (_signalTime > Duration)
{
_signalTime = 0f;
}
DriverTime = MMMaths.Remap(_signalTime, 0f, Duration, 0f, 1f);
}
else if (SignalMode == SignalModes.OneTime)
{
}
if (Playing || (SignalMode == SignalModes.Driven))
{
Shake();
}
if ((SignalMode == SignalModes.OneTime) && Playing && (TimescaleTime - _shakeStartedTimestamp > Duration))
{
ShakeComplete();
}
if ((_levelLastFrame != Level) && (OnValueChange != null))
{
ApplyLevel(Level);
}
_levelLastFrame = Level;
}
public virtual void ApplyLevel(float level)
{
OnValueChange.Invoke(level);
}
/// <summary>
/// A method to override to describe the behaviour in Driven mode
/// </summary>
protected virtual void ProcessDrivenMode()
{
}
/// <summary>
/// A method to override to describe what should happen at update
/// </summary>
protected virtual void ProcessUpdate()
{
}
/// <summary>
/// Override this method to implement shake over time
/// </summary>
protected virtual void Shake()
{
}
public virtual float GraphValue(float time)
{
return 0f;
}
/// <summary>
/// Describes what happens when the shake is complete
/// </summary>
protected virtual void ShakeComplete()
{
Playing = false;
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()
{
}
/// <summary>
/// On disable we complete our shake if it was in progress
/// </summary>
protected virtual void OnDisable()
{
if (Playing)
{
ShakeComplete();
}
}
/// <summary>
/// Starts this shaker
/// </summary>
public virtual void Play()
{
this.enabled = true;
}
/// <summary>
/// Starts this shaker
/// </summary>
public virtual void Stop()
{
ShakeComplete();
}
/// <summary>
/// Applies a bias to a time value
/// </summary>
/// <param name="t"></param>
/// <param name="bias"></param>
/// <returns></returns>
public virtual float ApplyBias(float t, float bias)
{
if (bias == 0.5f)
{
return t;
}
bias = MMMaths.Remap(bias, 0f, 1f, 1f, 0f);
float a = bias * 2.0f - 1.0f;
if (a < 0)
{
t = 1 - Mathf.Pow(1.0f - t, Mathf.Max(1 + a, .01f));
}
else
{
t = Mathf.Pow(t, Mathf.Max(1 - a, .01f));
}
return t;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a81b3d6b0f5d3d14a8395a2a9611e7a4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,27 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace MoreMountains.Tools
{
/// <summary>
/// A class used to expose a beat level from a target MMAudioAnalyzer, to be broadcasted by a MMAudioBroadcaster
/// </summary>
public class MMRadioSignalAudioAnalyzer : MMRadioSignal
{
[Header("Audio Analyzer")]
/// the MMAudioAnalyzer to read the value on
public MMAudioAnalyzer TargetAnalyzer;
/// the ID of the beat to listen to
public int BeatID;
/// <summary>
/// On Shake, we output our beat value
/// </summary>
protected override void Shake()
{
base.Shake();
CurrentLevel = TargetAnalyzer.Beats[BeatID].CurrentValue * GlobalMultiplier;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d566c4f1cefdec64fbce3a07b23976cb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,165 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
namespace MoreMountains.Tools
{
/// <summary>
/// A class used to generate signals, normalized values between 0 and 1
/// You can then use these values from a MMRadioBroadcaster, or simply evaluate its value to use wherever you want,
/// like a supercharged animation curve. In that case, simply disable the component, and read from it using its Evaluate method
/// </summary>
public class MMRadioSignalGenerator : MMRadioSignal
{
/// whether or not to display an animated preview
public bool AnimatedPreview = false;
/// whether this signal should play in back & forth (mirroring the curve around a tipping point)
public bool BackAndForth = false;
/// the tipping point at which to mirror the curve (between 0 and 1)
[MMCondition("BackAndForth", true)]
public float BackAndForthMirrorPoint = 0.5f;
/// the list of signals to assemble to create the final signal
public MMRadioSignalGeneratorItemList SignalList;
/// how to clamp the result value
[MMVector("Min", "Max")]
public Vector2 Clamps = new Vector2(0f, 1f);
/// the amplitude of the signal
[Range(0f, 1f)]
public float Bias = 0.5f;
/// <summary>
/// On reset, we initialize our list
/// </summary>
void Reset()
{
SignalList = new MMRadioSignalGeneratorItemList(){
new MMRadioSignalGeneratorItem()
};
}
/// <summary>
/// Returns the y value of the generated signal curve, at the x time value specified in parameters
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
public virtual float Evaluate(float time)
{
float level = 1f;
if (SignalList.Count <= 0)
{
return level;
}
time = ApplyBias(time, Bias);
for (int i = 0; i < SignalList.Count; i++)
{
if (SignalList[i].Active)
{
float newLevel = MMSignal.GetValueNormalized(time,
SignalList[i].SignalType, SignalList[i].Phase,
SignalList[i].Amplitude, SignalList[i].Frequency, SignalList[i].Offset,
SignalList[i].Invert, SignalList[i].Curve, SignalList[i].TweenCurve,
true, Clamps.x, Clamps.y, BackAndForth, BackAndForthMirrorPoint);
level = (SignalList[i].Mode == MMRadioSignalGeneratorItem.GeneratorItemModes.Multiply) ? level * newLevel : level + newLevel;
}
}
CurrentLevel *= GlobalMultiplier;
CurrentLevel = Mathf.Clamp(CurrentLevel, Clamps.x, Clamps.y);
return level;
}
/// <summary>
/// On Shake, we shake our level if needed
/// </summary>
protected override void Shake()
{
base.Shake();
if (!Playing)
{
return;
}
if (SignalMode == SignalModes.OneTime)
{
float elapsedTime = TimescaleTime - _shakeStartedTimestamp;
CurrentLevel = Evaluate(MMMaths.Remap(elapsedTime, 0f, Duration, 0f, 1f));
}
else
{
CurrentLevel = Evaluate(DriverTime);
}
}
/// <summary>
/// Once the shake is complete, we apply our final level
/// </summary>
protected override void ShakeComplete()
{
base.ShakeComplete();
CurrentLevel = Evaluate(1f);
}
/// <summary>
/// returns a custom value to display in the graph in inspector
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
public override float GraphValue(float time)
{
time = ApplyBias(time, Bias);
return Evaluate(time);
}
}
/// <summary>
/// A class used to store generator items and their properties
/// </summary>
[System.Serializable]
public class MMRadioSignalGeneratorItem
{
/// whether this individual signal should be multiplied or added to the rest
public enum GeneratorItemModes { Multiply, Additive }
/// whether to take this signal into account in the generator or not
public bool Active = true;
/// the type of this signal
public MMSignal.SignalType SignalType = MMSignal.SignalType.Sine;
/// if the type is animation curve, the curve to consider
[MMEnumCondition("SignalType", (int)MMSignal.SignalType.AnimationCurve)]
public AnimationCurve Curve = new AnimationCurve(new Keyframe(0, 0), new Keyframe(1, 1));
/// if the type is MMTween, the tween to consider
[MMEnumCondition("SignalType", (int)MMSignal.SignalType.MMTween)]
public MMTween.MMTweenCurve TweenCurve = MMTween.MMTweenCurve.EaseInOutQuartic;
/// the selected mode (multiply or additive)
public GeneratorItemModes Mode = GeneratorItemModes.Multiply;
/// the phase of the signal
[Range(-1f, 1f)]
public float Phase = 0f;
/// the frequency of the signal
[Range(0f, 10f)]
public float Frequency = 5f;
/// the amplitude of the signal
[Range(0f, 1f)]
public float Amplitude = 1f;
/// the offset of the signal
[Range(-1f, 1f)]
public float Offset = 0f;
/// whether or not to vertically invert the signal
public bool Invert = false;
}
/// <summary>
/// A reorderable list type used to store generator items
/// </summary>
[System.Serializable]
public class MMRadioSignalGeneratorItemList : MMReorderableArray<MMRadioSignalGeneratorItem>
{
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 65443987bd9048f408777b8d8f4c1994
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: