using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Serialization;
namespace UnityAtoms
{
///
/// Generic base class for Variables. Inherits from `AtomBaseVariable<T>`.
///
/// The Variable value type.
/// Event of type `AtomEvent<T>`.
/// Event of type `AtomEvent<T, T>`.
[EditorIcon("atom-icon-lush")]
public abstract class AtomVariable : AtomBaseVariable,
ISerializationCallbackReceiver
where E1 : AtomEvent
where E2 : AtomEvent
{
///
/// The Variable value as a property.
///
/// Get or set the Variable value.
public override T Value { get { return _value; } set { SetValue(value); } }
///
/// The inital value of the Variable.
///
[SerializeField]
private T _initialValue = default(T);
///
/// The value the Variable had before its value got changed last time.
///
///
public T OldValue { get { return _oldValue; } }
[FormerlySerializedAs("oldValue")]
[SerializeField]
private T _oldValue;
///
/// Changed Event triggered when the Variable value gets changed.
///
public E1 Changed;
///
/// Changed with history Event triggered when the Variable value gets changed.
///
public E2 ChangedWithHistory;
protected abstract bool AreEqual(T first, T second);
private void OnEnable()
{
if (Changed == null) return;
Changed.Raise(Value);
}
///
/// Reset the Variable to its `_initalValue`.
///
/// Set to `true` if Events should be triggered on reset, otherwise `false`.
public override sealed void Reset(bool shouldTriggerEvents = false)
{
if (!shouldTriggerEvents)
{
_oldValue = _value;
_value = _initialValue;
}
else
{
SetValue(_initialValue);
}
}
///
/// Set the Variable value.
///
/// The new value to set.
/// `true` if the value got changed, otherwise `false`.
public bool SetValue(T newValue)
{
if (!AreEqual(_value, newValue))
{
_oldValue = _value;
_value = newValue;
if (Changed != null) { Changed.Raise(_value); }
if (ChangedWithHistory != null) { ChangedWithHistory.Raise(_value, _oldValue); }
return true;
}
return false;
}
///
/// Set the Variable value.
///
/// The value to set provided from another Variable.
/// `true` if the value got changed, otherwise `false`.
public bool SetValue(AtomVariable variable)
{
return SetValue(variable.Value);
}
public void OnBeforeSerialize() { }
public void OnAfterDeserialize() { _value = _initialValue; }
#region Observable
///
/// Turn the Variable's change Event into an `IObservable<T>`. Makes the Variable's change Event compatible with for example UniRx.
///
/// The Variable's change Event as an `IObservable<T>`.
public IObservable ObserveChange()
{
if (Changed == null)
{
throw new Exception("You must assign a Changed event in order to observe variable changes.");
}
return new ObservableEvent(Changed.Register, Changed.Unregister);
}
///
/// Turn the Variable's change with history Event into an `IObservable<T, T>`. Makes the Variable's change with history Event compatible with for example UniRx.
///
/// The Variable's change Event as an `IObservable<T, T>`.
public IObservable> ObserveChangeWithHistory()
{
if (ChangedWithHistory == null)
{
throw new Exception("You must assign a ChangedWithHistory event in order to observe variable changes.");
}
return new ObservableEvent>(
register: ChangedWithHistory.Register,
unregister: ChangedWithHistory.Unregister,
createCombinedModel: (n, o) => new ValueTuple(n, o)
);
}
#endregion // Observable
}
}