Tested with Unity 2022.3.14f1 LTS
You can find the API documentation here.
A Signal is a ScriptableObject which holds a value and triggers a UnityEvent when a new value is assigned.
Because ScriptableObjects are a good choice to create a sane architecture for games made with Unity. They allow you to nicely decouple systems and avoid direct references between scene objects. For an in depth explanation I would highly recommend watching Richard Fine's and Ryan Hipple's talks.
If you store a value in a ScriptableObject you might want to get notified when the value changes. On the other hand it can be useful to keep the last value an event was invoked with around. Signals are a solution for both use cases.
Copy everything somewhere into your project's Asset folder.
Create a class for the signal:
[UnityEngine.CreateAssetMenu]
public class FloatSignal : Signal<float> { }
By default signals will trigger the OnChanged event whenever a new value is assigned. By overriding the ValidateValue method you can validate the value and/or add a check to avoid unnecessarily triggering the event. By default ValidateValue will use the Equals method for this check.
If you want to have a nice inspector create an editor class for your signal and override the ValueField method:
[UnityEditor.CustomEditor(typeof(Signal<float>))]
public class FloatSignalEditor : SignalEditor<float>
{
protected override float ValueField(float value) => EditorGUILayout.DelayedFloatField(value);
}
By inheriting from SignalListener you can create a Component that listens to a signal's OnChanged event and propagates it:
public class FloatSignalListener : SignalListener<float> { }
See Examples folder.
Signals was inspired by Ryan Hipple's talk about game architecture with ScriptableObjects.