Skip to content

Instantly share code, notes, and snippets.

@DraperDanMan
Last active November 9, 2021 11:08
Show Gist options
  • Select an option

  • Save DraperDanMan/fcc753f4849850815926c6e3e408b169 to your computer and use it in GitHub Desktop.

Select an option

Save DraperDanMan/fcc753f4849850815926c6e3e408b169 to your computer and use it in GitHub Desktop.
Float Stack: If you have multiple callsites changing a float an want either the min, max or some other custom value when you ask for the current value. Useful for time-dialation from multiple sources or ducking volume or min/max zoom distances
using System;
using System.Collections.Generic;
using UnityEngine;
using Object = UnityEngine.Object;
public class FloatEffectorStack
{
private readonly Dictionary<Object, float> _effectors;
private readonly Func<float, float, float> _compareFunction;
private readonly float _defaultValue = 0;
public Action<float> Changed;
public float Value => LookupValue();
public FloatEffectorStack(Func<float, float, float> compFunc, float defaultValue = 0)
{
_compareFunction = compFunc;
_defaultValue = defaultValue;
_effectors = new Dictionary<Object, float>();
}
private float LookupValue()
{
float result = _defaultValue;
foreach (var val in _effectors.Values)
result = _compareFunction(result, val);
return result;
}
public void Push(Object owner, float value)
{
if (!_effectors.ContainsKey(owner))
{
_effectors.Add(owner, value);
Changed?.Invoke(LookupValue());
}
else
Debug.Log("Attempted to push object on Float Effector Stack that is already on the stack.", owner);
}
public void Update(Object owner, float value)
{
if (_effectors.ContainsKey(owner))
{
_effectors[owner] = value;
Changed?.Invoke(LookupValue());
}
else
Debug.Log("Attempted to update value on Float Effector Stack for object that hasn't been pushed.", owner);
}
public void Pop(Object owner)
{
if (_effectors.ContainsKey(owner))
{
_effectors.Remove(owner);
Changed?.Invoke(LookupValue());
}
//Fail Silently if you try to pop and it doesn't exist.
}
public void Clear()
{
_effectors.Clear();
Changed?.Invoke(LookupValue());
}
}
@DraperDanMan
Copy link
Author

Usage TimeScale Example:

FloatEffectorStack timeScaleStack = new FloatEffectorStack(Mathf.Min, 1f);
TimeScaleStack.Changed += val => Time.timeScale= val; //do something when the value changes.

timeScaleStack.Push(this, 0.5f); //push this object as effecting the stack.

timeScaleStack.Update(this, 0.2f); //update this object's effect on the stack.

timeScaleStack.Pop(this); //remove this object from effecting the stack.

var timeScale = timeScaleStack.Value; //access what ever the Mathf.Min, value of the stack is.

Update is useful if something is likely to be changing the value a lot. Not that there is much of an overhead of popping and pushing again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment