Runtime Anchors

Runtime Anchors, very similarly to Shared Values, in the sense that they are a value that is encased in a ScriptableObject. The difference with Shared Values is that, while Values are intended to hold a quantity or some identifier set at edit or runtime, Anchors hold a reference to a GameObject or Component that will only be provided in Play Mode.

A Runtime Anchor is always null when the game starts, and some object needs to write its reference into it to make it usable.

Accessing a Runtime Anchor and finding it's null means the object is not present or has been destroyed. By implementing simple null checks, you can create decoupled systems that can rely on objects from other scenes, and are independent from them if they haven't been instantiated.

You can think of Runtime Anchors like a "promise". The object referencing it already has the reference but not the value, but it can rely on the fact that at runtime the value will be provided by some other object.

Runtime Anchors come in two flavours: individual, and sets. A Runtime Anchor Set is simply a list of Anchors, all contained in one ScriptableObject. See below for usage of both cases.

Sample usages 💡

A typical use for them is a Runtime Anchor with a reference to a Transform (or another component) that represents the player's character. This allows scripts from other scenes to find the player without having to perform stuff like FindObjectOfType<> which only works effectively with components existing in one copy, and is an expensive call anyways.


Individual Runtime Anchors

Individual Runtime Anchors, as opposed to Runtime Anchor Sets, are meant to store only one value.

Creating a new Runtime Anchor

To create a Runtime Anchor, simply position your mouse in the Project View and right click, then Create > ScriptableObject Tools > Runtime Anchors, and then choose the type you want to create.

Referencing a Runtime Anchor in scripts

To reference the Runtime Anchor SO, simply declare a variable of its type, like usual:

public TransformAnchor playerTransform;

and assign it using the Inspector.

Providing a value to a Runtime Anchor

When referencing a Runtime Anchor, providing a value is as simple as calling the Provide() method and passing a correct type as an argument:

private void Start()
{
    myTransform.Provide(transform);
}

This will also notify whoever is watching the Anchor and is listening to the event OnAnchorProvided.

Reading an Anchor's value

To access the value of an Anchor, use its Value property, like this:

public void Update()
{
    transform.LookAt(playerTransform.Value);
}

You can also (and it's good practice) check if the Anchor is null. Instead of doing a null check, you can use its IsSet boolean property, which is faster:

if(playerTransform.IsSet) transform.LookAt(playerTransform.Value);

Unsetting an Anchor

To correctly remove a value from an Anchor, call its Unset() method:

myTransform.Unset();

There is no protection that prevents other objects to unset an Anchor, because Anchors have no concept of "owner".

Calling Unset() also invokes the OnAnchorUnset event, so that objects hooked into that can be notified of the change.

Listening to an Anchor's changes in value

Anchors provide two events to listen to the changes to their value.

  • OnAnchorProvided is called every time the value of an Anchor changes - but not to a null value.

  • OnAnchorUnset is called when someone sets the Anchor to null.


Runtime Sets

Runtime Sets are very similar to individual Runtime Anchors, and only differ in that they have additional tools to manage the list of values that is contained within the set. The list can be accessed using .Values but is not directly writable, but needs to be manipulated using the set's public methods:

  • AddToSet()

  • RemoveFromSet()

  • GetRandomElement()

  • GetRandomElement(T elementToExclude)

Listening to changes in the set's values

Runtime Sets provide three events that objects can listen to:

  • OnElementAdded is called when an element is added.

  • OnElementRemoved is called when an element is removed, including if it's the last element.

  • OnSetEmptied is called only when a set is purposely emptied by calling the method EmptySet().

Note that OnSetEmptied is not called when the last element is removed via OnElementRemoved, to avoid objects firing both events accidentally.

An object that wants to fire OnSetEmptied when the last element is removed can, upon reacting to OnElementRemoved, check that the IsEmpty property is true, and invoke the code manually.

When is the list reset

Because ideally many objects might want to add elements to a set, there might be no object in charge of emptying the set when exiting Play Mode. For this reason, RuntimeAnchorSetBase inherits from the ManagedScriptableObject class. Upon exiting Play Mode, the set will be emptied by the Reset() method.

See the Managed Scriptable Object page for more info.


Extending Runtime Anchors

Adding a new individual Runtime Anchor type

To create a new Runtime Anchor class holding a different type, all you need to do is to create a new C-sharp file, and in it, subclass RuntimeAnchorBase<T> like this (we'll use Rigidbody as an example):

[CreateAssetMenu]
public class TransformAnchor : RuntimeAnchorBase<Rigidbody> { }

Nothing else is needed.

Adding a new Runtime Set type

Similarly to individual Anchors, a new set can be added by just declaring a new class inheriting from RuntimeAnchorSetBase<T>:

[CreateAssetMenu]
public class RigibodyAnchorSet : RuntimeAnchorSetBase<Rigidbody> { }

Last updated