Skip to content

Value Reference

Value Reference is a special type that allows you to pick between a constant value or a scriptable value. They are used in the same way as a Scriptable Value, but in the editor they can be set to either a constant value or a scriptable value. This is useful for when you want to support both.

Value Reference

Using a Value Reference in your code is really straight forward. You can use the Value property to get or set the value of the Value Reference. For example:

Value Reference Example
using Hertzole.ScriptableValues;
using UnityEngine;
public class PlayerHealth : MonoBehaviour
{
// Can be either constant or a scriptable value
public ValueReference<int> health;
public void TakeDamage(int damage)
{
health.Value -= damage;
}
}

Then you can use the events to get notified when the value changes. For example:

Value Reference Event Example
using Hertzole.ScriptableValues;
using UnityEngine;
using UnityEngine.UI;
public class HealthUI : MonoBehaviour
{
// Can be either constant or a scriptable value
public ValueReference<int> health;
public Text healthText;
private void OnEnable()
{
health.OnValueChanged += OnHealthChanged;
}
private void OnDisable()
{
health.OnValueChanged -= OnHealthChanged;
}
private void OnHealthChanged(int oldValue, int newValue)
{
healthText.text = "Health: " + newValue.ToString();
}
}

Remember to unsubscribe from events when you no longer need them. See the events section for more information.

ValueReference<T> supports addressable references, if the addressables package is installed, along with the normal references.

Load Example
using Hertzole.ScriptableValues;
using UnityEngine;
using UnityEngine.AddressableAssets;
public class PlayerHealth : MonoBehaviour
{
// Can be either constant or a scriptable value
public ValueReference<int> health;
private void Start()
{
// Need to check if the value reference is addressable
if (health.IsAddressable)
{
// LoadAddressableAssetAsync will return an
// AsyncOperationHandle<ScriptableValue<T>>
// You can use it however you want, including awaiting it
// in newer versions of Unity or using UniTask
health.LoadAddressableAssetAsync(OnLoaded);
}
}
private void OnDestroy()
{
// No need to check if the value reference is addressable
// Unload the addressable asset when the object is destroyed
health.ReleaseAddressableAsset();
}
// Called when the addressable asset is loaded
private void OnLoaded(AsyncOperationHandle<ScriptableValue<int>> handle)
{
// Check the handle status, it may fail
if (handle.Status == AsyncOperationStatus.Succeeded)
{
handle.Result.Value = 100;
}
}
}

You can always subscribe to the OnValueChanging and OnValueChanged events, even if the addressable asset isn’t loaded yet. The events will be automatically applied to the addressable asset when it’s loaded.

Event Example
using Hertzole.ScriptableValues;
using UnityEngine;
public class PlayerHealth : MonoBehaviour
{
// Can be either constant or a scriptable value
public ValueReference<int> health;
private void Start()
{
// Need to check if the value reference is addressable
if (health.IsAddressable)
{
health.LoadAddressableAssetAsync();
}
}
private void OnEnable()
{
// Subscribe to the value changed event
health.OnValueChanged += OnHealthChanged;
}
private void OnDisable()
{
// Unsubscribe from the value changed event
health.OnValueChanged -= OnHealthChanged;
}
private void OnDestroy()
{
// No need to check if the value reference is addressable
// Unload the addressable asset when the object is destroyed
health.ReleaseAddressableAsset();
}
private void OnHealthChanged(int oldValue, int newValue)
{
Debug.Log("Health changed from " + oldValue + " to " + newValue);
}

You can not set the Value before the addressable asset is loaded. This will result in a warning.

Value Set Example
using Hertzole.ScriptableValues;
using UnityEngine;
public class TimeManager : MonoBehaviour
{
// Can be either constant or a scriptable value
public ValueReference<float> time;
private void Start()
{
// Need to check if the value reference is addressable
if (time.IsAddressable)
{
time.LoadAddressableAssetAsync();
}
}
private void OnDestroy()
{
// No need to check if the value reference is addressable
// Unload the addressable asset when the object is destroyed
time.ReleaseAddressableAsset();
}
private void Update()
{
if (time.IsAddressableLoaded)
{
// Can set the value now
time.Value = Time.time;
}
}
}

IsAddressable is always present, even if the addressables package is not installed. If the package is not installed, it will always return false. If the package is installed, it will return true if the value reference is set to addressable.
IsAddressableLoaded is always present, even if the addressables package is not installed. If the package is not installed, it will always return true. If the package is installed, it will return true if the addressable asset is loaded. It will also return true if the value reference is not set to addressable.