https://github.com/eyellen/eyellen.unity.observablefields
Simple implementation of observable fields for Unity
https://github.com/eyellen/eyellen.unity.observablefields
observer-pattern unity
Last synced: about 1 month ago
JSON representation
Simple implementation of observable fields for Unity
- Host: GitHub
- URL: https://github.com/eyellen/eyellen.unity.observablefields
- Owner: Eyellen
- License: mit
- Created: 2024-10-13T14:55:38.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2024-12-07T07:29:31.000Z (over 1 year ago)
- Last Synced: 2025-04-08T16:11:40.021Z (about 1 year ago)
- Topics: observer-pattern, unity
- Language: C#
- Homepage:
- Size: 34.2 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Unity Observable Fields
Simple observable fields implementation for Unity that works with an inspector.
# Installation
## Install via UPM (using Git URL)
Open Unity > Window > Package Manager > + > Add package from git URL:
```
https://github.com/Eyellen/Eyellen.Unity.ObservableFields.git
```
Paste and press "Add"
# Summary
`ObservableField` - Does not support inspector and uses only pure C# features.
`UnityObservableField` - Supports inspector, uses C# and Unity events. You can assign Unity events in the inspector.
`IReadOnlyObservableField` - Read only interface for observable fields. Allows to get read only value and subscribe to changes.
`IObservableFieldEvents` - Interface that provides methods to subscribe or unsubscribe from changes.
# Important Notes
- You must call constructor for observable fields, otherwise it will give a `NullReferenceException`. The only exception is if you're going to use `SerializeFieldAttribute` on `UnityObservableField` and as a T parameter you pass a type that has `SerializableAttribute`, i.e. Unity is able to serialize that field.
- If you want Unity events to be called in edit mode make sure to set `UnityEventCallState` to `EditorAndRuntime` in the inspector, it's next to each method reference in the unity event property. If you want C# events to be called in edit mode make sure to add `ExecuteAlwaysAttribute` to your class.
- If you pass your custom type to `UnityObservableField` and want it to appear in the inspector make sure to add `SerializableAttribute` to your type.
- Remember that reference types are reference types, `ObservableField` will not fire events when reference type's members will be changed, it will fire event only if the reference itself is changed. If you need to fire event when complex object is changed prefer using structs.
# Usage
## Declaring observable fields:
```CSharp
using System;
using UnityEngine;
namespace Eyellen.Unity.ObservableFields.Examples
{
public class ObservableFieldDeclaration : MonoBehaviour
{
// ObservableField does not support inspector. If you want it to show up in the inspector, use UnityObservableField.
// Does not appear in the inspector even though it has a SerializeField attribute.
// Uses CSharp events.
[SerializeField]
private ObservableField ObservableBool = new();
// Displayed in the inspector.
// Uses CSharp events and Unity events. Unity events can be assigned in the inspector.
[SerializeField]
private UnityObservableField UnityObservableBool = new();
// Displayed in the inspector since a passed type have Serializable attribute.
[SerializeField]
private UnityObservableField SerializableType = new();
// Does not appear in the inspector because a type passed to a field is not serializable.
[SerializeField]
private UnityObservableField NonSerializableType = new();
}
public class NonSerializedType
{
public string Name;
public string Description;
}
[Serializable]
public class SerializedType
{
public string Name;
public string Description;
}
}
```
Declared `UnityObservableField`s will look like this in the inspector:

## Subscribing to observable field changes:
```CSharp
using UnityEngine;
namespace Eyellen.Unity.ObservableFields.Examples
{
public class ObservableFieldSubscribing : MonoBehaviour
{
// You can subscribe to observable field changes in code and in inspector.
// NOTE: To subscribe on changes in the inspector use UnityObservableField.
private ObservableField Number;
[SerializeField]
private UnityObservableField String;
private void Awake()
{
// ObservableField.
// Subscribing to C# events.
Number.SubscribeOnChange(OnValueChangedEventArgs);
Number.SubscribeOnChange(OnValueChangedTTArgs);
Number.SubscribeOnChange(OnValueChangedNoArgs);
// UnityObservableField.
// Subscribing to C# events.
String.SubscribeOnChange(OnValueChangedEventArgs);
String.SubscribeOnChange(OnValueChangedTTArgs);
String.SubscribeOnChange(OnValueChangedNoArgs);
}
// Method that takes ObservableField.EventArgs as a parameter.
// ObservableField.EventArgs contain previous and current values.
private void OnValueChangedEventArgs(ObservableField.EventArgs args)
{
Debug.Log(
$"Call {nameof(OnValueChangedEventArgs)}: Previous value - {args.Previous}. Current value - {args.Current}"
);
}
// Method that takes previous and current value as a parameters.
private void OnValueChangedTTArgs(T previous, T current)
{
Debug.Log(
$"Call {nameof(OnValueChangedTTArgs)}: Previous value - {previous}. Current value - {current}"
);
}
// Method that takes no parameters.
private void OnValueChangedNoArgs()
{
Debug.Log($"Call {nameof(OnValueChangedNoArgs)}");
}
}
}
```
Inspector:
`Use Unity Events` - indicates if Unity events will be called. If has false value Unity events will not be called even if they were assigned.

If you want to use Unity events, check `Use Unity Events` and `Events` foldout will pop up:

Click on `Events` foldout and there are 4 Unity events:
1. Passes `ObservableField.EventArgs` as a parameter
2. Passes `Previous` and `Current` values as a parameters
3. Passes `Current` value as a parameter
4. Passes no parameters

## Using IReadOnlyObservableField
```CSharp
using UnityEngine;
namespace Eyellen.Unity.ObservableFields.Examples
{
public class UsingIReadOnlyObservableField : MonoBehaviour
{
// You can use IReadOnlyObservableField if you want to allow readonly value on you observable field
// but want to protect it from changes from outside the class.
// Private observable field.
// Can't be accessed outside the class.
[SerializeField]
private UnityObservableField _float = new();
// Public IReadOnlyObservableField.
// Can be accessed outside the class.
// Provides only readonly Value getter and methods to subscribe to change event.
public IReadOnlyObservableField Float => _float;
}
}
```
## Implementing Getter/Setter's
```CSharp
using UnityEngine;
namespace Eyellen.Unity.ObservableFields.Examples
{
public class ObservableFieldGetterSetters : MonoBehaviour
{
// You can add Getter/Setter like behaviour to observable fields and specify Get/Set logic.
// Getter/Setter behaviour works fine with an inspector.
// Getter/Setter's are passed into a field constructor as a Func
// where first value is input value and the second one is processed result.
// Here we implemented setter that clamps passed value between 0 and 10.
[SerializeField]
private UnityObservableField ObservableInt =
new(default, value => Mathf.Clamp(value, 0, 10));
// Here we implemented getter that simply returns the passed float number as a negative while keeping original value as positive.
[SerializeField]
private UnityObservableField ObservableFloat = new(default, null, value => -value);
}
}
```
# License
MIT