Insanely huge initial commit

This commit is contained in:
2026-02-21 16:40:15 -08:00
parent 208d626100
commit f74c547a13
33825 changed files with 5213498 additions and 0 deletions

View File

@@ -0,0 +1,95 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
using UnityEngine;
using System.Collections;
using System;
using UnityEngine.UI;
using System.Collections.Generic;
using UnityEngine.Events;
namespace Lofelt.NiceVibrations
{
public class HapticCurve : MonoBehaviour
{
[Range(0f, 1f)]
public float Amplitude = 1f;
[Range(0f, 1f)]
public float Frequency = 0f;
public int PointsCount = 50;
public float AmplitudeFactor = 3;
[Range(1f, 4f)]
private float Period = 1;
public RectTransform StartPoint;
public RectTransform EndPoint;
[Header("Movement")]
public bool Move = false;
public float MovementSpeed = 1f;
protected LineRenderer _targetLineRenderer;
protected List<Vector3> Points;
protected Canvas _canvas;
protected Camera _camera;
protected Vector3 _startPosition;
protected Vector3 _endPosition;
protected Vector3 _workPoint;
protected virtual void Awake()
{
Initialization();
}
protected virtual void Initialization()
{
Points = new List<Vector3>();
_canvas = this.gameObject.GetComponentInParent<Canvas>();
_targetLineRenderer = this.gameObject.GetComponent<LineRenderer>();
_camera = _canvas.worldCamera;
DrawCurve();
}
protected virtual void DrawCurve()
{
_startPosition = StartPoint.transform.position;
_startPosition.z -= 0.1f;
_endPosition = EndPoint.transform.position;
_endPosition.z -= 0.1f;
Points.Clear();
for (int i = 0; i < PointsCount; i++)
{
float t = NiceVibrationsDemoHelpers.Remap(i, 0, PointsCount, 0f, 1f);
float sinValue = MMSignal.GetValue(t, MMSignal.SignalType.Sine, 1f, AmplitudeFactor, Period, 0f, false);
if (Move)
{
sinValue = MMSignal.GetValue(t + Time.time * MovementSpeed, MMSignal.SignalType.Sine, 1f, AmplitudeFactor, Period, 0f, false);
}
_workPoint.x = Mathf.Lerp(_startPosition.x, _endPosition.x, t);
_workPoint.y = sinValue * Amplitude + _startPosition.y;
_workPoint.z = _startPosition.z;
Points.Add(_workPoint);
}
_targetLineRenderer.positionCount = PointsCount;
_targetLineRenderer.SetPositions(Points.ToArray());
}
protected virtual void Update()
{
UpdateCurve(Amplitude, Frequency);
}
public virtual void UpdateCurve(float amplitude, float frequency)
{
Amplitude = amplitude;
Frequency = frequency;
Period = NiceVibrationsDemoHelpers.Remap(frequency, 0f, 1f, 1f, 4f);
DrawCurve();
}
}
}

View File

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

View File

@@ -0,0 +1,97 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
namespace Lofelt.NiceVibrations
{
[RequireComponent(typeof(Text))]
/// <summary>
/// Add this class to a gameObject with a Text component and it'll feed it the number of FPS in real time.
/// </summary>
public class MMFPSCounter : MonoBehaviour
{
/// <summary>
/// The frequency at which the FPS counter should update (in seconds)
/// </summary>
public float UpdateInterval = 0.3f;
protected float _framesAccumulated = 0f;
protected float _framesDrawnInTheInterval = 0f;
protected float _timeLeft;
protected Text _text;
protected int _currentFPS;
static string[] _stringsFrom00To300 = {
"00", "01", "02", "03", "04", "05", "06", "07", "08", "09",
"10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
"20", "21", "22", "23", "24", "25", "26", "27", "28", "29",
"30", "31", "32", "33", "34", "35", "36", "37", "38", "39",
"40", "41", "42", "43", "44", "45", "46", "47", "48", "49",
"50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
"60", "61", "62", "63", "64", "65", "66", "67", "68", "69",
"70", "71", "72", "73", "74", "75", "76", "77", "78", "79",
"80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
"90", "91", "92", "93", "94", "95", "96", "97", "98", "99",
"100", "101", "102", "103", "104", "105", "106", "107", "108", "109",
"110", "111", "112", "113", "114", "115", "116", "117", "118", "119",
"120", "121", "122", "123", "124", "125", "126", "127", "128", "129",
"130", "131", "132", "133", "134", "135", "136", "137", "138", "139",
"140", "141", "142", "143", "144", "145", "146", "147", "148", "149",
"150", "151", "152", "153", "154", "155", "156", "157", "158", "159",
"160", "161", "162", "163", "164", "165", "166", "167", "168", "169",
"170", "171", "172", "173", "174", "175", "176", "177", "178", "179",
"180", "181", "182", "183", "184", "185", "186", "187", "188", "189",
"190", "191", "192", "193", "194", "195", "196", "197", "198", "199",
"200", "201", "202", "203", "204", "205", "206", "207", "208", "209",
"210", "211", "212", "213", "214", "215", "216", "217", "218", "219",
"220", "221", "222", "223", "224", "225", "226", "227", "228", "229",
"230", "231", "232", "233", "234", "235", "236", "237", "238", "239",
"240", "241", "242", "243", "244", "245", "246", "247", "248", "249",
"250", "251", "252", "253", "254", "255", "256", "257", "258", "259",
"260", "261", "262", "263", "264", "265", "266", "267", "268", "269",
"270", "271", "272", "273", "274", "275", "276", "277", "278", "279",
"280", "281", "282", "283", "284", "285", "286", "287", "288", "289",
"290", "291", "292", "293", "294", "295", "296", "297", "298", "299",
"300"
};
/// <summary>
/// On Start(), we get the Text component and initialize our counter
/// </summary>
protected virtual void Start()
{
if (GetComponent<Text>() == null)
{
Debug.LogWarning("FPSCounter requires a GUIText component.");
return;
}
_text = GetComponent<Text>();
_timeLeft = UpdateInterval;
}
/// <summary>
/// On Update, we increment our various counters, and if we've reached our UpdateInterval, we update our FPS counter
/// with the number of frames displayed since the last counter update
/// </summary>
protected virtual void Update()
{
_framesDrawnInTheInterval++;
_framesAccumulated = _framesAccumulated + Time.timeScale / Time.deltaTime;
_timeLeft = _timeLeft - Time.deltaTime;
if (_timeLeft <= 0.0)
{
_currentFPS = (int)Mathf.Clamp(_framesAccumulated / _framesDrawnInTheInterval, 0, 300);
if (_currentFPS >= 0 && _currentFPS <= 300)
{
_text.text = _stringsFrom00To300[_currentFPS];
}
_framesDrawnInTheInterval = 0;
_framesAccumulated = 0f;
_timeLeft = UpdateInterval;
}
}
}
}

View File

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

View File

@@ -0,0 +1,45 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
namespace Lofelt.NiceVibrations
{
/// <summary>
/// Add this component to any object and it'll set the target frame rate and vsync count. Note that vsync count must be 0 for the target FPS to work.
/// </summary>
public class MMFPSUnlock : MonoBehaviour
{
/// the target FPS you want the game to run at
public int TargetFPS;
[Range(0, 2)]
/// whether vsync should be enabled or not (on a 60Hz screen, 1 : 60fps, 2 : 30fps, 0 : don't wait for vsync)
public int VSyncCount = 0;
/// <summary>
/// On start we change our target fps and vsync settings
/// </summary>
protected virtual void Start()
{
UpdateSettings();
}
/// <summary>
/// When a value gets changed in the editor, we update our settings
/// </summary>
protected virtual void OnValidate()
{
UpdateSettings();
}
/// <summary>
/// Updates the target frame rate value and vsync count setting
/// </summary>
protected virtual void UpdateSettings()
{
QualitySettings.vSyncCount = VSyncCount;
Application.targetFrameRate = TargetFPS;
}
}
}

View File

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

View File

@@ -0,0 +1,125 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace Lofelt.NiceVibrations
{
[RequireComponent(typeof(Rect))]
public class MMKnob : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
{
public RenderMode ParentCanvasRenderMode { get; protected set; }
[Header("Bindings")]
public Camera TargetCamera;
[Header("Settings")]
public float MinimumAngle = 45f;
public float MaximumAngle = -225f;
public float MaximumDistance = 50f;
public Color ActiveColor;
public Color InactiveColor;
[Header("Output")]
public bool Dragging = false;
public float Value = 0f;
public bool Active = true;
public Image _image;
protected PointerEventData _pointerEventData;
protected float _distance;
public RectTransform _rectTransform;
protected Vector3 _rotation = Vector3.zero;
protected Canvas _canvas;
protected Vector2 _workPosition;
protected virtual void Awake()
{
_image = this.gameObject.GetComponent<Image>();
_canvas = GetComponentInParent<Canvas>();
ParentCanvasRenderMode = GetComponentInParent<Canvas>().renderMode;
_rectTransform = this.GetComponent<RectTransform>();
SetRotation(MinimumAngle);
}
protected virtual void Update()
{
if (!Active)
{
Dragging = false;
_image.color = InactiveColor;
return;
}
else
{
_image.color = ActiveColor;
}
if (!Dragging)
{
return;
}
Vector2 v1 = Vector2.down;
Vector2 v2 = this.transform.position - GetWorldPosition(_pointerEventData.position);
float angle = Vector2.SignedAngle(v1, v2);
angle = Mathf.Clamp(angle, -130f, 130f);
_rotation.z = NiceVibrationsDemoHelpers.Remap(angle, -130f, 130f, MaximumAngle, MinimumAngle);
_rectTransform.SetPositionAndRotation(this.transform.position, Quaternion.Euler(_rotation));
Value = NiceVibrationsDemoHelpers.Remap(angle, -130f, 130f, 1f, 0f);
}
protected virtual void SetRotation(float angle)
{
angle = Mathf.Clamp(angle, MaximumAngle, MinimumAngle);
_rotation.z = angle;
_rectTransform.SetPositionAndRotation(this.transform.position, Quaternion.Euler(_rotation));
}
public virtual void SetActive(bool status)
{
Active = status;
}
public virtual void SetValue(float value)
{
SetRotation(MinimumAngle);
Value = value;
float angle = NiceVibrationsDemoHelpers.Remap(value, 0f, 1f, MinimumAngle, MaximumAngle);
_rotation.z = angle;
_rectTransform.SetPositionAndRotation(this.transform.position, Quaternion.Euler(_rotation));
}
public void OnPointerDown(PointerEventData eventData)
{
_pointerEventData = eventData;
Dragging = true;
}
public void OnPointerUp(PointerEventData eventData)
{
_pointerEventData = null;
Dragging = false;
}
protected virtual Vector3 GetWorldPosition(Vector3 testPosition)
{
if (ParentCanvasRenderMode == RenderMode.ScreenSpaceCamera)
{
RectTransformUtility.ScreenPointToLocalPointInRectangle(_canvas.transform as RectTransform, testPosition, _canvas.worldCamera, out _workPosition);
return _canvas.transform.TransformPoint(_workPosition);
}
else
{
return testPosition;
}
}
}
}

View File

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

View File

@@ -0,0 +1,354 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
namespace Lofelt.NiceVibrations
{
/// <summary>
/// Add this bar to an object and link it to a bar (possibly the same object the script is on), and you'll be able to resize the bar object based on a current value, located between a min and max value.
/// See the HealthBar.cs script for a use case
/// </summary>
public class MMProgressBar : MonoBehaviour
{
/// the possible fill modes
public enum FillModes { LocalScale, FillAmount, Width, Height }
/// the possible directions for the fill (for local scale and fill amount only)
public enum BarDirections { LeftToRight, RightToLeft, UpToDown, DownToUp }
/// the possible timescales the bar can work on
public enum TimeScales { UnscaledTime, Time }
[Header("General Settings")]
/// the local scale or fillamount value to reach when the bar is empty
public float StartValue = 0f;
/// the local scale or fillamount value to reach when the bar is full
public float EndValue = 1f;
/// the direction this bar moves to
public BarDirections BarDirection = BarDirections.LeftToRight;
/// the foreground bar's fill mode
public FillModes FillMode = FillModes.LocalScale;
/// defines whether the bar will work on scaled or unscaled time (whether or not it'll keep moving if time is slowed down for example)
public TimeScales TimeScale = TimeScales.UnscaledTime;
[Header("Foreground Bar Settings")]
/// whether or not the foreground bar should lerp
public bool LerpForegroundBar = true;
/// the speed at which to lerp the foreground bar
public float LerpForegroundBarSpeed = 15f;
[Header("Delayed Bar Settings")]
/// the delay before the delayed bar moves (in seconds)
public float Delay = 1f;
/// whether or not the delayed bar's animation should lerp
public bool LerpDelayedBar = true;
/// the speed at which to lerp the delayed bar
public float LerpDelayedBarSpeed = 15f;
[Header("Bindings")]
/// optional - the ID of the player associated to this bar
public string PlayerID;
/// the delayed bar
public Transform DelayedBar;
/// the main, foreground bar
public Transform ForegroundBar;
[Header("Bump")]
/// whether or not the bar should "bump" when changing value
public bool BumpScaleOnChange = true;
/// whether or not the bar should bump when its value increases
public bool BumpOnIncrease = false;
/// the duration of the bump animation
public float BumpDuration = 0.2f;
/// whether or not the bar should flash when bumping
public bool ChangeColorWhenBumping = true;
/// the color to apply to the bar when bumping
public Color BumpColor = Color.white;
/// the curve to map the bump animation on
public AnimationCurve BumpAnimationCurve = new AnimationCurve(new Keyframe(1, 1), new Keyframe(0.3f, 1.05f), new Keyframe(1, 1));
/// the curve to map the bump animation color animation on
public AnimationCurve BumpColorAnimationCurve = new AnimationCurve(new Keyframe(0, 0), new Keyframe(0.3f, 1f), new Keyframe(1, 0));
/// whether or not the bar is bumping right now
public bool Bumping { get; protected set; }
[Header("Realtime")]
/// whether or not this progress bar should update itself every update (if not, you'll have to update it using the UpdateBar method
public bool AutoUpdating = false;
/// the current progress of the bar
[Range(0f, 1f)]
public float BarProgress;
protected float _targetFill;
protected Vector3 _targetLocalScale = Vector3.one;
protected float _newPercent;
protected float _lastPercent;
protected float _lastUpdateTimestamp;
protected bool _bump = false;
protected Color _initialColor;
protected Vector3 _initialScale;
protected Vector3 _newScale;
protected Image _foregroundImage;
protected Image _delayedImage;
protected bool _initialized;
protected Vector2 _initialFrontBarSize;
/// <summary>
/// On start we store our image component
/// </summary>
protected virtual void Start()
{
_initialScale = this.transform.localScale;
if (ForegroundBar != null)
{
_foregroundImage = ForegroundBar.GetComponent<Image>();
_initialFrontBarSize = _foregroundImage.rectTransform.sizeDelta;
}
if (DelayedBar != null)
{
_delayedImage = DelayedBar.GetComponent<Image>();
}
_initialized = true;
}
/// <summary>
/// On Update we update our bars
/// </summary>
protected virtual void Update()
{
AutoUpdate();
UpdateFrontBar();
UpdateDelayedBar();
}
protected virtual void AutoUpdate()
{
if (!AutoUpdating)
{
return;
}
_newPercent = Remap(BarProgress, 0f, 1f, StartValue, EndValue);
_targetFill = _newPercent;
_lastUpdateTimestamp = (TimeScale == TimeScales.Time) ? Time.time : Time.unscaledTime;
}
/// <summary>
/// Updates the front bar's scale
/// </summary>
protected virtual void UpdateFrontBar()
{
float currentDeltaTime = (TimeScale == TimeScales.Time) ? Time.deltaTime : Time.unscaledTime;
if (ForegroundBar != null)
{
switch (FillMode)
{
case FillModes.LocalScale:
_targetLocalScale = Vector3.one;
switch (BarDirection)
{
case BarDirections.LeftToRight:
_targetLocalScale.x = _targetFill;
break;
case BarDirections.RightToLeft:
_targetLocalScale.x = 1f - _targetFill;
break;
case BarDirections.DownToUp:
_targetLocalScale.y = _targetFill;
break;
case BarDirections.UpToDown:
_targetLocalScale.y = 1f - _targetFill;
break;
}
if (LerpForegroundBar)
{
_newScale = Vector3.Lerp(ForegroundBar.localScale, _targetLocalScale, currentDeltaTime * LerpForegroundBarSpeed);
}
else
{
_newScale = _targetLocalScale;
}
ForegroundBar.localScale = _newScale;
break;
case FillModes.Width:
if (_foregroundImage == null)
{
return;
}
float newSizeX = Remap(_targetFill, 0f, 1f, 0, _initialFrontBarSize.x);
newSizeX = Mathf.Lerp(_foregroundImage.rectTransform.sizeDelta.x, newSizeX, currentDeltaTime * LerpForegroundBarSpeed);
_foregroundImage.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, newSizeX);
break;
case FillModes.Height:
if (_foregroundImage == null)
{
return;
}
float newSizeY = Remap(_targetFill, 0f, 1f, 0, _initialFrontBarSize.y);
newSizeY = Mathf.Lerp(_foregroundImage.rectTransform.sizeDelta.x, newSizeY, currentDeltaTime * LerpForegroundBarSpeed);
_foregroundImage.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, newSizeY);
break;
case FillModes.FillAmount:
if (_foregroundImage == null)
{
return;
}
if (LerpForegroundBar)
{
_foregroundImage.fillAmount = Mathf.Lerp(_foregroundImage.fillAmount, _targetFill, currentDeltaTime * LerpForegroundBarSpeed);
}
else
{
_foregroundImage.fillAmount = _targetFill;
}
break;
}
}
}
/// <summary>
/// Updates the delayed bar's scale
/// </summary>
protected virtual void UpdateDelayedBar()
{
float currentDeltaTime = (TimeScale == TimeScales.Time) ? Time.deltaTime : Time.unscaledDeltaTime;
float currentTime = (TimeScale == TimeScales.Time) ? Time.time : Time.unscaledTime;
if (DelayedBar != null)
{
if (currentTime - _lastUpdateTimestamp > Delay)
{
if (FillMode == FillModes.LocalScale)
{
_targetLocalScale = Vector3.one;
switch (BarDirection)
{
case BarDirections.LeftToRight:
_targetLocalScale.x = _targetFill;
break;
case BarDirections.RightToLeft:
_targetLocalScale.x = 1f - _targetFill;
break;
case BarDirections.DownToUp:
_targetLocalScale.y = _targetFill;
break;
case BarDirections.UpToDown:
_targetLocalScale.y = 1f - _targetFill;
break;
}
if (LerpDelayedBar)
{
_newScale = Vector3.Lerp(DelayedBar.localScale, _targetLocalScale, currentDeltaTime * LerpDelayedBarSpeed);
}
else
{
_newScale = _targetLocalScale;
}
DelayedBar.localScale = _newScale;
}
if ((FillMode == FillModes.FillAmount) && (_delayedImage != null))
{
if (LerpDelayedBar)
{
_delayedImage.fillAmount = Mathf.Lerp(_delayedImage.fillAmount, _targetFill, currentDeltaTime * LerpDelayedBarSpeed);
}
else
{
_delayedImage.fillAmount = _targetFill;
}
}
}
}
}
/// <summary>
/// Updates the bar's values based on the specified parameters
/// </summary>
/// <param name="currentValue">Current value.</param>
/// <param name="minValue">Minimum value.</param>
/// <param name="maxValue">Max value.</param>
public virtual void UpdateBar(float currentValue, float minValue, float maxValue)
{
_newPercent = Remap(currentValue, minValue, maxValue, StartValue, EndValue);
if ((_newPercent != BarProgress) && !Bumping)
{
Bump();
}
BarProgress = _newPercent;
_targetFill = _newPercent;
_lastUpdateTimestamp = (TimeScale == TimeScales.Time) ? Time.time : Time.unscaledTime;
_lastPercent = _newPercent;
}
/// <summary>
/// Triggers a camera bump
/// </summary>
public virtual void Bump()
{
if (!BumpScaleOnChange || !_initialized)
{
return;
}
if (!BumpOnIncrease && (_lastPercent < _newPercent))
{
return;
}
if (this.gameObject.activeInHierarchy)
{
StartCoroutine(BumpCoroutine());
}
}
/// <summary>
/// A coroutine that (usually quickly) changes the scale of the bar
/// </summary>
/// <returns>The coroutine.</returns>
protected virtual IEnumerator BumpCoroutine()
{
float journey = 0f;
float currentDeltaTime = (TimeScale == TimeScales.Time) ? Time.deltaTime : Time.unscaledDeltaTime;
Bumping = true;
if (_foregroundImage != null)
{
_initialColor = _foregroundImage.color;
}
while (journey <= BumpDuration)
{
journey = journey + currentDeltaTime;
float percent = Mathf.Clamp01(journey / BumpDuration);
float curvePercent = BumpAnimationCurve.Evaluate(percent);
float colorCurvePercent = BumpColorAnimationCurve.Evaluate(percent);
this.transform.localScale = curvePercent * _initialScale;
if (ChangeColorWhenBumping && (_foregroundImage != null))
{
_foregroundImage.color = Color.Lerp(_initialColor, BumpColor, colorCurvePercent);
}
yield return null;
}
_foregroundImage.color = _initialColor;
Bumping = false;
yield return null;
}
protected virtual float Remap(float x, float A, float B, float C, float D)
{
float remappedValue = C + (x - A) / (B - A) * (D - C);
return remappedValue;
}
}
}

View File

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

View File

@@ -0,0 +1,71 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Lofelt.NiceVibrations
{
/// <summary>
/// This class lets you output the value corresponding to one of the basic signal types it contains. Useful to draw basic signal curves.
/// </summary>
public class MMSignal : MonoBehaviour
{
public enum SignalType
{
DigitalNoise,
Pulse,
Sawtooth,
Sine,
Square,
Triangle,
WhiteNoise
}
/// <summary>
/// Returns the corresponding value based on the selected SignalType for a given time value
/// </summary>
/// <param name="time"></param>
/// <param name="signalType"></param>
/// <param name="phase"></param>
/// <param name="amplitude"></param>
/// <param name="frequency"></param>
/// <param name="offset"></param>
/// <param name="Invert"></param>
/// <returns></returns>
public static float GetValue(float time, SignalType signalType, float phase, float amplitude, float frequency, float offset, bool Invert = false)
{
float value = 0f;
float invert = Invert ? -1 : 1;
float t = frequency * time + phase;
switch (signalType)
{
case SignalType.Sine:
value = (float)Mathf.Sin(2f * Mathf.PI * t);
break;
case SignalType.Square:
value = Mathf.Sign(Mathf.Sin(2f * Mathf.PI * t));
break;
case SignalType.Triangle:
value = 1f - 4f * (float)Mathf.Abs(Mathf.Round(t - 0.25f) - (t - 0.25f));
break;
case SignalType.Sawtooth:
value = 2f * (t - (float)Mathf.Floor(t + 0.5f));
break;
case SignalType.Pulse:
value = (Mathf.Abs(Mathf.Sin(2 * Mathf.PI * t)) < 1.0 - 10E-3) ? (0) : (1);
break;
case SignalType.WhiteNoise:
value = 2f * Random.Range(0, int.MaxValue) / int.MaxValue - 1f;
break;
case SignalType.DigitalNoise:
value = Random.Range(0, 2);
break;
}
return (invert * amplitude * value + offset);
}
}
}

View File

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

View File

@@ -0,0 +1,184 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
using UnityEngine;
using System.Collections;
using System;
using UnityEngine.UI;
namespace Lofelt.NiceVibrations
{
/// <summary>
/// A class to add to an Image or SpriteRenderer to have it act like a button with a different sprite for on and off states
/// </summary>
public class MMSpriteReplace : MonoBehaviour
{
[Header("Sprites")]
/// the sprite to use when in the "on" state
public Sprite OnSprite;
/// the sprite to use when in the "off" state
public Sprite OffSprite;
[Header("Start settings")]
/// if this is true, the button will start if "on" state
public bool StartsOn = true;
/// the current state of the button
public bool CurrentValue { get { return (_image.sprite == OnSprite); } }
protected Image _image;
protected SpriteRenderer _spriteRenderer;
protected MMTouchButton _mmTouchButton;
/// <summary>
/// On Start we initialize our button
/// </summary>
protected virtual void Start()
{
Initialization();
}
/// <summary>
/// On init, we grab our image component, and set our sprite in its initial state
/// </summary>
protected virtual void Initialization()
{
// grabs components
_image = GetComponent<Image>();
_spriteRenderer = GetComponent<SpriteRenderer>();
// grabs button
_mmTouchButton = GetComponent<MMTouchButton>();
if (_mmTouchButton != null)
{
_mmTouchButton.ReturnToInitialSpriteAutomatically = false;
}
// handles start
if ((OnSprite == null) || (OffSprite == null))
{
return;
}
if (_image != null)
{
if (StartsOn)
{
_image.sprite = OnSprite;
}
else
{
_image.sprite = OffSprite;
}
}
if (_spriteRenderer != null)
{
if (StartsOn)
{
_spriteRenderer.sprite = OnSprite;
}
else
{
_spriteRenderer.sprite = OffSprite;
}
}
}
/// <summary>
/// A public method to change the sprite
/// </summary>
public virtual void Swap()
{
if (_image != null)
{
if (_image.sprite != OnSprite)
{
SwitchToOnSprite();
}
else
{
SwitchToOffSprite();
}
}
if (_spriteRenderer != null)
{
if (_spriteRenderer.sprite != OnSprite)
{
SwitchToOnSprite();
}
else
{
SwitchToOffSprite();
}
}
}
/// <summary>
/// a public method to switch to off sprite directly
/// </summary>
public virtual void SwitchToOffSprite()
{
if ((_image == null) && (_spriteRenderer == null))
{
return;
}
if (OffSprite == null)
{
return;
}
SpriteOff();
}
/// <summary>
/// sets the image's sprite to off
/// </summary>
protected virtual void SpriteOff()
{
if (_image != null)
{
_image.sprite = OffSprite;
}
if (_spriteRenderer != null)
{
_spriteRenderer.sprite = OffSprite;
}
}
/// <summary>
/// a public method to switch to on sprite directly
/// </summary>
public virtual void SwitchToOnSprite()
{
if ((_image == null) && (_spriteRenderer == null))
{
return;
}
if (OnSprite == null)
{
return;
}
SpriteOn();
}
/// <summary>
/// sets the image's sprite to on
/// </summary>
protected virtual void SpriteOn()
{
if (_image != null)
{
_image.sprite = OnSprite;
}
if (_spriteRenderer != null)
{
_spriteRenderer.sprite = OnSprite;
}
}
}
}

View File

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

View File

@@ -0,0 +1,122 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
using UnityEngine;
using System.Collections;
using System;
using UnityEngine.UI;
using System.Collections.Generic;
using UnityEngine.Events;
namespace Lofelt.NiceVibrations
{
/// <summary>
/// A component to handle switches
/// </summary>
public class MMSwitch : MMTouchButton
{
[Header("Switch")]
/// a SpriteReplace to represent the switch knob
public Image SwitchKnob;
/// the possible states of the switch
public enum SwitchStates { Off, On }
/// the current state of the switch
public SwitchStates CurrentSwitchState { get; set; }
[Header("Knob")]
/// the state the switch should start in
public SwitchStates InitialState = SwitchStates.Off;
public Transform OffPosition;
public Transform OnPosition;
public AnimationCurve KnobMovementCurve = AnimationCurve.Linear(0f, 0f, 1f, 1f);
public float KnobMovementDuration = 0.2f;
[Header("Binding")]
/// the methods to call when the switch is turned on
public UnityEvent SwitchOn;
/// the methods to call when the switch is turned off
public UnityEvent SwitchOff;
protected float _knobMovementStartedAt = -50f;
/// <summary>
/// On init, we set our current switch state
/// </summary>
protected override void Initialization()
{
base.Initialization();
CurrentSwitchState = InitialState;
InitializeState();
}
public virtual void InitializeState()
{
if (CurrentSwitchState == SwitchStates.Off)
{
if (_animator != null)
{
_animator.Play("RollLeft");
}
SwitchKnob.transform.position = OffPosition.transform.position;
}
else
{
if (_animator != null)
{
_animator.Play("RollRight");
}
SwitchKnob.transform.position = OnPosition.transform.position;
}
}
protected override void Update()
{
base.Update();
if (Time.time - _knobMovementStartedAt < KnobMovementDuration)
{
float time = Remap(Time.time - _knobMovementStartedAt, 0f, KnobMovementDuration, 0f, 1f);
float value = KnobMovementCurve.Evaluate(time);
if (CurrentSwitchState == SwitchStates.Off)
{
SwitchKnob.transform.position = Vector3.Lerp(OnPosition.transform.position, OffPosition.transform.position, value);
}
else
{
SwitchKnob.transform.position = Vector3.Lerp(OffPosition.transform.position, OnPosition.transform.position, value);
}
}
}
/// <summary>
/// Use this method to go from one state to the other
/// </summary>
public virtual void SwitchState()
{
_knobMovementStartedAt = Time.time;
if (CurrentSwitchState == SwitchStates.Off)
{
CurrentSwitchState = SwitchStates.On;
if (_animator != null)
{
_animator?.SetTrigger("Right");
}
if (SwitchOn != null)
{
SwitchOn.Invoke();
}
}
else
{
CurrentSwitchState = SwitchStates.Off;
if (_animator != null)
{
_animator?.SetTrigger("Left");
}
if (SwitchOff != null)
{
SwitchOff.Invoke();
}
}
}
}
}

View File

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

View File

@@ -0,0 +1,395 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.Events;
using UnityEngine.EventSystems;
namespace Lofelt.NiceVibrations
{
[RequireComponent(typeof(Rect))]
[RequireComponent(typeof(CanvasGroup))]
/// <summary>
/// Add this component to a GUI Image to have it act as a button.
/// Bind pressed down, pressed continually and released actions to it from the inspector
/// Handles mouse and multi touch
/// </summary>
public class MMTouchButton : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IPointerExitHandler, IPointerEnterHandler, ISubmitHandler
{
/// The different possible states for the button :
/// Off (default idle state), ButtonDown (button pressed for the first time), ButtonPressed (button being pressed), ButtonUp (button being released), Disabled (unclickable but still present on screen)
/// ButtonDown and ButtonUp will only last one frame, the others will last however long you press them / disable them / do nothing
public enum ButtonStates { Off, ButtonDown, ButtonPressed, ButtonUp, Disabled }
[Header("Binding")]
/// The method(s) to call when the button gets pressed down
public UnityEvent ButtonPressedFirstTime;
/// The method(s) to call when the button gets released
public UnityEvent ButtonReleased;
/// The method(s) to call while the button is being pressed
public UnityEvent ButtonPressed;
[Header("Sprite Swap")]
public Sprite DisabledSprite;
public Sprite PressedSprite;
public Sprite HighlightedSprite;
[Header("Color Changes")]
public bool PressedChangeColor = false;
public Color PressedColor = Color.white;
public bool LerpColor = true;
public float LerpColorDuration = 0.2f;
public AnimationCurve LerpColorCurve;
[Header("Opacity")]
/// the new opacity to apply to the canvas group when the button is pressed
public float PressedOpacity = 1f;
public float IdleOpacity = 1f;
public float DisabledOpacity = 1f;
[Header("Delays")]
public float PressedFirstTimeDelay = 0f;
public float ReleasedDelay = 0f;
[Header("Buffer")]
public float BufferDuration = 0f;
[Header("Animation")]
public Animator Animator;
public string IdleAnimationParameterName = "Idle";
public string DisabledAnimationParameterName = "Disabled";
public string PressedAnimationParameterName = "Pressed";
[Header("Mouse Mode")]
/// If you set this to true, you'll need to actually press the button for it to be triggered, otherwise a simple hover will trigger it (better for touch input).
public bool MouseMode = false;
public bool ReturnToInitialSpriteAutomatically { get; set; }
/// the current state of the button (off, down, pressed or up)
public ButtonStates CurrentState { get; protected set; }
protected bool _zonePressed = false;
protected CanvasGroup _canvasGroup;
protected float _initialOpacity;
protected Animator _animator;
protected Image _image;
protected Sprite _initialSprite;
protected Color _initialColor;
protected float _lastClickTimestamp = 0f;
protected Selectable _selectable;
protected float _lastStateChangeAt = -50f;
protected Color _imageColor;
protected Color _fromColor;
protected Color _toColor;
/// <summary>
/// On Start, we get our canvasgroup and set our initial alpha
/// </summary>
protected virtual void Awake()
{
Initialization();
}
protected virtual void Initialization()
{
ReturnToInitialSpriteAutomatically = true;
_selectable = GetComponent<Selectable>();
_image = GetComponent<Image>();
if (_image != null)
{
_initialColor = _image.color;
_initialSprite = _image.sprite;
}
_animator = GetComponent<Animator>();
if (Animator != null)
{
_animator = Animator;
}
_canvasGroup = GetComponent<CanvasGroup>();
if (_canvasGroup != null)
{
_initialOpacity = IdleOpacity;
_canvasGroup.alpha = _initialOpacity;
_initialOpacity = _canvasGroup.alpha;
}
ResetButton();
}
/// <summary>
/// Every frame, if the touch zone is pressed, we trigger the OnPointerPressed method, to detect continuous press
/// </summary>
protected virtual void Update()
{
switch (CurrentState)
{
case ButtonStates.Off:
SetOpacity(IdleOpacity);
if ((_image != null) && (ReturnToInitialSpriteAutomatically))
{
_image.sprite = _initialSprite;
}
if (_selectable != null)
{
_selectable.interactable = true;
if (EventSystem.current.currentSelectedGameObject == this.gameObject)
{
if (HighlightedSprite != null)
{
_image.sprite = HighlightedSprite;
}
}
}
break;
case ButtonStates.Disabled:
SetOpacity(DisabledOpacity);
if (_image != null)
{
if (DisabledSprite != null)
{
_image.sprite = DisabledSprite;
}
}
if (_selectable != null)
{
_selectable.interactable = false;
}
break;
case ButtonStates.ButtonDown:
break;
case ButtonStates.ButtonPressed:
SetOpacity(PressedOpacity);
OnPointerPressed();
if (_image != null)
{
if (PressedSprite != null)
{
_image.sprite = PressedSprite;
}
if (PressedChangeColor)
{
_image.color = PressedColor;
}
}
break;
case ButtonStates.ButtonUp:
break;
}
if ((_image != null) && (PressedChangeColor))
{
if (Time.time - _lastStateChangeAt < LerpColorDuration)
{
float t = LerpColorCurve.Evaluate(Remap(Time.time - _lastStateChangeAt, 0f, LerpColorDuration, 0f, 1f));
_image.color = Color.Lerp(_fromColor, _toColor, t);
}
}
UpdateAnimatorStates();
}
/// <summary>
/// At the end of every frame, we change our button's state if needed
/// </summary>
protected virtual void LateUpdate()
{
if (CurrentState == ButtonStates.ButtonUp)
{
_lastStateChangeAt = Time.time;
_fromColor = PressedColor;
_toColor = _initialColor;
CurrentState = ButtonStates.Off;
}
if (CurrentState == ButtonStates.ButtonDown)
{
_lastStateChangeAt = Time.time;
_fromColor = _initialColor;
_toColor = PressedColor;
CurrentState = ButtonStates.ButtonPressed;
}
}
/// <summary>
/// Triggers the bound pointer down action
/// </summary>
public virtual void OnPointerDown(PointerEventData data)
{
if (Time.time - _lastClickTimestamp < BufferDuration)
{
return;
}
if (CurrentState != ButtonStates.Off)
{
return;
}
CurrentState = ButtonStates.ButtonDown;
_lastClickTimestamp = Time.time;
if ((Time.timeScale != 0) && (PressedFirstTimeDelay > 0))
{
Invoke("InvokePressedFirstTime", PressedFirstTimeDelay);
}
else
{
ButtonPressedFirstTime.Invoke();
}
}
protected virtual void InvokePressedFirstTime()
{
if (ButtonPressedFirstTime != null)
{
ButtonPressedFirstTime.Invoke();
}
}
/// <summary>
/// Triggers the bound pointer up action
/// </summary>
public virtual void OnPointerUp(PointerEventData data)
{
if (CurrentState != ButtonStates.ButtonPressed && CurrentState != ButtonStates.ButtonDown)
{
return;
}
CurrentState = ButtonStates.ButtonUp;
if ((Time.timeScale != 0) && (ReleasedDelay > 0))
{
Invoke("InvokeReleased", ReleasedDelay);
}
else
{
ButtonReleased.Invoke();
}
}
protected virtual void InvokeReleased()
{
if (ButtonReleased != null)
{
ButtonReleased.Invoke();
}
}
/// <summary>
/// Triggers the bound pointer pressed action
/// </summary>
public virtual void OnPointerPressed()
{
CurrentState = ButtonStates.ButtonPressed;
if (ButtonPressed != null)
{
ButtonPressed.Invoke();
}
}
/// <summary>
/// Resets the button's state and opacity
/// </summary>
protected virtual void ResetButton()
{
SetOpacity(_initialOpacity);
CurrentState = ButtonStates.Off;
}
/// <summary>
/// Triggers the bound pointer enter action when touch enters zone
/// </summary>
public virtual void OnPointerEnter(PointerEventData data)
{
if (!MouseMode)
{
OnPointerDown(data);
}
}
/// <summary>
/// Triggers the bound pointer exit action when touch is out of zone
/// </summary>
public virtual void OnPointerExit(PointerEventData data)
{
if (!MouseMode)
{
OnPointerUp(data);
}
}
/// <summary>
/// OnEnable, we reset our button state
/// </summary>
protected virtual void OnEnable()
{
ResetButton();
}
public virtual void DisableButton()
{
CurrentState = ButtonStates.Disabled;
}
public virtual void EnableButton()
{
if (CurrentState == ButtonStates.Disabled)
{
CurrentState = ButtonStates.Off;
}
}
protected virtual void SetOpacity(float newOpacity)
{
if (_canvasGroup != null)
{
_canvasGroup.alpha = newOpacity;
}
}
protected virtual void UpdateAnimatorStates()
{
if (_animator == null)
{
return;
}
if (DisabledAnimationParameterName != null)
{
_animator.SetBool(DisabledAnimationParameterName, (CurrentState == ButtonStates.Disabled));
}
if (PressedAnimationParameterName != null)
{
_animator.SetBool(PressedAnimationParameterName, (CurrentState == ButtonStates.ButtonPressed));
}
if (IdleAnimationParameterName != null)
{
_animator.SetBool(IdleAnimationParameterName, (CurrentState == ButtonStates.Off));
}
}
public virtual void OnSubmit(BaseEventData eventData)
{
if (ButtonPressedFirstTime != null)
{
ButtonPressedFirstTime.Invoke();
}
if (ButtonReleased != null)
{
ButtonReleased.Invoke();
}
}
protected virtual float Remap(float x, float A, float B, float C, float D)
{
float remappedValue = C + (x - A) / (B - A) * (D - C);
return remappedValue;
}
}
}

View File

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

View File

@@ -0,0 +1,49 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
namespace Lofelt.NiceVibrations
{
public class MMUIShaker : MonoBehaviour
{
public float Amplitude;
public float Frequency;
public bool Shaking = false;
protected Vector3 _initialPosition;
protected Vector3 _shakePosition;
protected RectTransform _rectTransform;
protected virtual void Start()
{
_rectTransform = this.gameObject.GetComponent<RectTransform>();
_initialPosition = _rectTransform.localPosition;
}
public virtual IEnumerator Shake(float duration)
{
Shaking = true;
yield return new WaitForSeconds(duration);
Shaking = false;
}
protected virtual void Update()
{
if (!Shaking)
{
_rectTransform.localPosition = _initialPosition;
return;
}
else
{
_shakePosition.x = Mathf.PerlinNoise(-(Time.time) * Frequency, Time.time * Frequency) * Amplitude - Amplitude / 2f;
_shakePosition.y = Mathf.PerlinNoise(-(Time.time + 0.25f) * Frequency, Time.time * Frequency) * Amplitude - Amplitude / 2f;
_shakePosition.z = Mathf.PerlinNoise(-(Time.time + 0.5f) * Frequency, Time.time * Frequency) * Amplitude - Amplitude / 2f;
_rectTransform.localPosition = _initialPosition + _shakePosition;
}
}
}
}

View File

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

View File

@@ -0,0 +1,51 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace Lofelt.NiceVibrations
{
public class Pagination : MonoBehaviour
{
public GameObject PaginationDotPrefab;
public Color ActiveColor;
public Color InactiveColor;
protected List<Image> _images;
public virtual void InitializePagination(int numberOfPages)
{
_images = new List<Image>();
for (int i = 0; i < numberOfPages; i++)
{
GameObject dotPrefab = Instantiate(PaginationDotPrefab);
dotPrefab.transform.SetParent(this.transform);
dotPrefab.name = "PaginationDot" + i;
_images.Add(dotPrefab.GetComponent<Image>());
}
foreach (Image image in _images)
{
image.color = InactiveColor;
image.rectTransform.localScale = Vector3.one;
image.rectTransform.localPosition = Vector3.zero;
image.SetNativeSize();
}
}
public virtual void SetCurrentPage(int numberOfPages, int currentPage)
{
for (int i = 0; i < numberOfPages; i++)
{
if (i == currentPage)
{
_images[i].color = ActiveColor;
}
else
{
_images[i].color = InactiveColor;
}
}
}
}
}

View File

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