Overview

image

Unity package library for sharing collections of data across components and scenes, allowing other components to react when their contents change.

Heavily inspired by the infamous Unite 2017: Game Architecture with Scriptable Objects presentation by Ryan Hipple (GitHub).

Unfortunately Unity does not understand generics in the Editor and Inspectors, so only concrete types can be used. Fortunately, this can be made easy by deriving from a single generic type allowing the same common behaviors.

NOTE: This package is still in development and may have breaking changes in future versions until a stable v1.0.0 release is made.

Changelog

All notable changes to this library will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

[0.2.4] - 2022-12-30

Changed

  • Moved all RuntimeSet<T> classes to UnderLogic.Collections.Sets namespace
  • Moved all RuntimeSetWatcher<T, TSet> classes to UnderLogic.Collections.Sets.Watchers namespace

[0.2.3] - 2022-12-29

Added

  • BoolSet collection
  • BoolSetWatcher component
  • AllowDuplicates property for RuntimeSet collection
  • AddRange(IEnumerable<T>) method for RuntimeSet collection
  • Icons for RuntimeSet collections in the Editor

Changed

  • Add(T) method for RuntimeSet collection optionally allows duplicates
  • TryReplace(T, T) method for RuntimeSet collection now checks for duplicates prior to replacing

[0.2.2] - 2022-12-08

Fixed

  • Missing meta files

[0.2.1] - 2022-12-06

Added

  • TryAdd(int) : bool method to DoubleSet variant
  • TryAdd(float) : bool method to DoubleSet variant
  • TryAdd(int) : bool method to FloatSet variant
  • TryAdd(bool) : bool method to StringSet variant
  • TryAdd(int) : bool method to StringSet variant
  • TryAdd(float) : bool method to StringSet variant
  • TryAdd(double) : bool method to StringSet variant
  • TryAdd(Vector2Int) : bool method to Vector2Set variant
  • TryAdd(Vector2Int) : bool method to Vector3Set variant
  • TryAdd(Vector2) : bool method to Vector3Set variant
  • TryAdd(Vector2Int) : bool method to Vector4Set variant
  • TryAdd(Vector2) : bool method to Vector4Set variant
  • TryAdd(Vector3) : bool method to Vector4Set variant
  • TryAdd(T) : bool method to RuntimeSet<T> base class
  • TryReplace(T, T) method to RuntimeSet<T> base class
  • Docs via mdbook in Documentation~ directory
  • GitHub CI/CD workflows for documentation

Changed

  • Renamed collectionSet serialized field to collection in RuntimeSetWatcher base class
  • Expose Collection getter property in RuntimeSetWatcher base class

[0.2.0] - 2022-12-02

Added

  • RuntimeSetWatcher<T> abstract base class
  • ColorSetWatcher component
  • DoubleSetWatcher component
  • FloatSetWatcher component
  • IntSetWatcher component
  • ScriptableObjectSetWatcher component
  • StringSetWatcher component
  • TransformSetWatcher component
  • Vector2IntSetWatcher component
  • Vector2SetWatcher component
  • Vector3SetWatcher component
  • Vector4SetWatcher component
  • Set Watchers sample scene

[0.1.3] - 2022-12-02

Added

  • InitialItems readonly property to RuntimeSet<T> base class
  • MakeReadOnly() method to RuntimeSet<T> base class

[0.1.2] - 2022-12-01

Added

  • Add(int) method to FloatSet collection
  • Remove(int) method to FloatSet collection
  • Add(int) method to DoubleSet collection
  • Add(float) method to DoubleSet collection
  • Remove(int) method to DoubleSet collection
  • Remove(float) method to DoubleSet collection
  • Add(bool) method to StringSet collection
  • Add(int) method to StringSet collection
  • Add(float) method to StringSet collection
  • Add(double) method to StringSet collection
  • Remove(bool) method to StringSet collection
  • Remove(int) method to StringSet collection
  • Remove(float) method to StringSet collection
  • Remove(double) method to StringSet collection
  • Add(Vector2Int) method to Vector2Set collection
  • Remove(Vector2Int) method to Vector2Set collection
  • Vector2IntSet collection
  • Vector4Set collection
  • ColorSet collection

[0.1.1] - 2022-12-01

Added

  • IntSet collection
  • FloatSet collection
  • DoubleSet collection
  • Vector2Set collection
  • Vector3Set collection

[0.1.0] - 2022-12-01

Added

  • RuntimeSet<T> abstract base class
  • ScriptableObjectSet collection
  • StringSet collection
  • TransformSet collection
  • Sets sample scene

Installation

OpenUPM

OpenUPM is an open source Unity package registry that allows you to easily install thousands of packages.

You can install this library with the following CLI command:

$ openupm add com.underlogic.runtime-collections

Git URL

Starting with Unity 2019.3 you can add packages via git url. You can add this package by the following url: https://github.com/UnderLogic/runtime-collections

Using this method will allow you to update the package through the Unity Package Manager.

Local Package

Alternatively, you can clone the git repository and add the package locally.

Getting Started

Context

To best understand the purpose of this library and the problems it solves, it is highly recommended to watch the Unite 2017: Game Architecture with Scriptable Objects by Ryan Hipple.

Use Cases

Shared Collections

The common case of needing to share collections of data between various components, potentially across multiple scenes. Easy to drag and drop references in the Editor and view/modify them in the Inspector during play mode.

See runtime-variables library in the related-libraries section for working with variable data.

Singleton

The common case of needing a single, global instance of data that can be accessed everywhere. This avoids the common pitfalls of traditional Unity singleton objects.

Event-Based Architecture

The case of only wanting to update or perform actions when necessary (reactively) instead of wastefully computing each frame. This is very common in UI-heavy applications.

See event-channels library in the related-libraries section for working with an event bus.

Samples

The Samples~ folder contains sample scenes showcasing various aspects of the library in action. It is recommended to import and play around with them in Unity to get a feel for how to use the library.

Custom Collections

While this library provides many of the common Unity types you will use, you may want to extend this library with your own custom collections specific to your application. Fortunately, this is rather easy and typically only involves creating a derived class from one of the base classes. You may also add any additional helper properties and methods as you need.

Sets

  1. Create a new class that derives from RuntimeSet<T>, where T should be the type of set.
  2. Ensure the new type is marked with the CreateAssetMenu attribute, so you can create instances in the Editor.
  3. Create any instances of the new variable in your Assets folder.
  4. Configure the isReadOnly, allowDuplicates, and initialItems fields as needed.
  5. Now you can use them throughout your application.

NOTE: While most people create ScriptableObject instances in the Editor, you can create them at runtime as well!

Watchers

  1. Create a new class that derives from RuntimeSetWatcher<T, TSet>, where T should be the underlying type and TSet is the set type.
  2. You can now use the watcher component in your scenes.

Related Libraries

Sets

Overview

Sets are implemented as ScriptableObject instances that can contain a collection of values. They function similar to an array or list but do not allow duplicate values to be added by default.

They are observable and provide events when items are added or removed.

RuntimeSet<T>

Abstract base class that all other runtime sets derive from.

Implements ICollection<T> and IEnumerable<T> interfaces.

Description

Represents an observable set of T values that can be shared and modified throughout the application. By default, the set does not allow duplicate values but this can be overriden.

Serialized Fields (Inspector)

  • isReadOnly : bool - Whether the set can be mutated.
  • allowDuplicates : bool - Whether the set can contain duplicate values.
  • initialItems : List<T> - Initial list of items, will be re-applied on restart.
  • items : List<T> - The current items in the set.

NOTE: Any duplicates in the initialItems will not be preserved when copied to items during OnEnable() (unless allowDuplicates is true).

Public Properties

  • IsReadOnly : bool (get) - Whether the set can be mutated.
  • AllowDuplicates : bool (get) - Whether the set can contain duplicate values.
  • InitialItems : IReadOnlyCollection<T> (get) - Read-only view of the initial items for the set.
  • Count : int (get) - The number of items currently in the set.
  • this[int] : T (get) - Returns the item in the set by index, zero-based.

Public Events

  • ItemAdded : UnityAction<T> - Raised when an item is added to the set.
  • ItemRemoved : UnityAction<T> - Raised when an item is removed from the set.
  • ItemsChanged : UnityAction - Raised when an item is added or removed from the set.

Public Methods

  • Contains(T) : bool - Returns whether the set contains the value T provided.
  • IndexOf(T) : int - Returns the index of the value T within the set, or -1 if not found.
  • TryGet(int, out T) : bool - Attempts to get an item by index and returns the item as an out parameter. Returns whether an item was found.
  • Add(T) - Adds a value T to the set. If the set already contains the value, it is ignored.
  • AddRange(IEnumerable<T>) - Adds a range of values to the set. If the set already contains a value, it is ignored.
  • TryAdd(T) : bool - Attempts to add a value T to the set, returns whether an item was added.
  • Remove(T) : bool - Attempts to remove a value T from the set. Returns whether an item was removed.
  • TryReplace(T, T) : bool - Attempts to replace one value T with another T within the set. Returns whether an item was found to be replaced, and whether the replacement was successful.
  • Clear() - Removes all items from the set. Will raise events for each item removed.
  • CopyTo(T[], int) - Copies the items from this set to another T[] array.
  • MakeReadOnly() - Marks the set as readonly, useful for freezing the collection after initialization.
  • GetEnumerator() : IEnumerator<T> - Get an enumerator that can be used to iterate over the set.
  • RaiseItemsChanged() - Manually raises the ItemsChanged event, useful for forcing refreshes on observers.

NOTE: Trying to modify a readonly set will result in an InvalidOperationException being thrown.

NOTE: Duplicate values are ignored when adding to the set, unless AllowDuplicates is set to true.

BoolSet

Derives from RuntimeSet<T>.

Description

Represents a set of bool values that can be shared and modified throughout the application.

This class does not have any additional members.

ColorSet

Derives from RuntimeSet<T>.

Description

Represents a set of Color values that can be shared and modified throughout the application.

This class does not have any additional members.

DoubleSet

Derives from RuntimeSet<T>.

Description

Represents a set of double values that can be shared and modified throughout the application.

Public Methods

  • Add(int) - Adds a signed int value to the set.
  • Add(float) - Adds a float value to the set.
  • TryAdd(int) : bool - Attempts to add a signed int value to the set. Returns whether an item was added.
  • TryAdd(float) : bool - Attempts to add a float value to the set. Returns whether an item was added.
  • Remove(int) : bool - Removes a signed int value from the set. Returns whether an item was removed.
  • Remove(float) : bool - Removes a float value from the set. Returns whether an item was removed.

FloatSet

Derives from RuntimeSet<T>.

Description

Represents a set of float values that can be shared and modified throughout the application.

Public Methods

  • Add(int) - Adds a signed int value to the set.
  • TryAdd(int) : bool - Attempts to add a signed int value to the set. Returns whether an item was added.
  • Remove(int) : bool - Removes a signed int value from the set. Returns whether an item was removed.

IntSet

Derives from RuntimeSet<T>.

Description

Represents a set of int values that can be shared and modified throughout the application.

This class does not have any additional members.

ScriptableObjectSet

Derives from RuntimeSet<T>.

Description

Represents a set of ScriptableObject values that can be shared and modified throughout the application.

This class does not have any additional members.

StringSet

Derives from RuntimeSet<T>.

Description

Represents a set of string values that can be shared and modified throughout the application.

Public Methods

  • Add(bool) - Adds the string representation of a bool value to the set.
  • Add(int) - Adds the string representation of a signed int value to the set.
  • Add(float) - Adds the string representation of a float value to the set.
  • Add(double) - Adds the string representation of a double value to the set.
  • TryAdd(bool) - Attempts to add the string representation of a bool value to the set. Return whether an item was added.
  • TryAdd(int) - Attempts to add the string representation of a signed int value to the set. Return whether an item was added.
  • TryAdd(float) - Attempts to add the string representation of a float value to the set. Return whether an item was added.
  • TryAdd(double) - Attempts to add the string representation of a double value to the set. Return whether an item was added.
  • Remove(int) : bool - Removes the string representation of a bool value from the set. Returns whether an item was removed.
  • Remove(int) : bool - Removes the string representation of a signed int value from the set. Returns whether an item was removed.
  • Remove(float) : bool - Removes the string representation of a float value from the set. Returns whether an item was removed.
  • Remove(double) : bool - Removes the string representation of a signed int value from the set. Returns whether an item was removed.

NOTE: The string representations will be formatted using CultureInfo.CurrentCulture.

TransformSet

Derives from RuntimeSet<T>.

Description

Represents a set of Transform values that can be shared and modified throughout the application.

This class does not have any additional members.

Vector2IntSet

Derives from RuntimeSet<T>.

Description

Represents a set of Vector2Int values that can be shared and modified throughout the application.

This class does not have any additional members.

Vector2Set

Derives from RuntimeSet<T>.

Description

Represents a set of Vector2 values that can be shared and modified throughout the application.

Public Methods

  • Add(Vector2Int) - Adds a Vector2Int value to the set.
  • TryAdd(Vector2Int) : bool - Attempts to add a Vector2Int value to the set. Returns whether an item was added.
  • Remove(Vector2Int) : bool - Removes a Vector2Int value from the set. Returns whether an item was removed.

Vector3Set

Derives from RuntimeSet<T>.

Description

Represents a set of Vector3 values that can be shared and modified throughout the application.

Public Methods

  • Add(Vector2Int) - Adds a Vector2Int value to the set.
  • Add(Vector2) - Adds a Vector2 value to the set.
  • TryAdd(Vector2Int) : bool - Attempts to add a Vector2Int value to the set. Returns whether an item was added.
  • TryAdd(Vector2) : bool - Attempts to add a Vector2 value to the set. Returns whether an item was added.
  • Remove(Vector2Int) : bool - Removes a Vector2Int value from the set. Returns whether an item was removed.
  • Remove(Vector2) : bool - Removes a Vector2 value from the set. Returns whether an item was removed.

Vector4Set

Derives from RuntimeSet<T>.

Description

Represents a set of Vector4 values that can be shared and modified throughout the application.

Public Methods

  • Add(Vector2Int) - Adds a Vector2Int value to the set.
  • Add(Vector2) - Adds a Vector2 value to the set.
  • Add(Vector3) - Adds a Vector3 value to the set.
  • TryAdd(Vector2Int) : bool - Attempts to add a Vector2Int value to the set. Returns whether an item was added.
  • TryAdd(Vector2) : bool - Attempts to add a Vector2 value to the set. Returns whether an item was added.
  • TryAdd(Vector3) : bool - Attempts to add a Vector3 value to the set. Returns whether an item was added.
  • Remove(Vector2Int) : bool - Removes a Vector2Int value from the set. Returns whether an item was removed.
  • Remove(Vector2) : bool - Removes a Vector2 value from the set. Returns whether an item was removed.
  • Remove(Vector3) : bool - Removes a Vector3 value from the set. Returns whether an item was removed.

Watchers

Overview

Runtime collection watchers are implemented as MonoBehaviour components that can be used to bind UnityEvent actions to collection change events via the Unity Inspector. This allows the watchers to notify other components without needing to write extra boilerplate code for subscribing and unsubscribing to those events.

It also allows multiple actions to be triggered from a single collection change event.

RuntimeSetWatcher<T, TSet>

Abstract base class that all other runtime set watchers derive from.

Description

Component that watches a RuntimeSet<T> for changes and raises events.

Serialized Fields (Inspector)

  • collection : TSet - The collection to watch for changes.
  • raiseOnAwake : bool - Whether the onItemsChanged event should be raised when Awake() is called.
  • raiseOnEnable : bool - Whether the onItemsChanged event should be raised when OnEnable() is called.
  • raiseOnStart : bool - Whether the onItemsChanged event should be raised when Start() is called.

Public Events (Inspector)

  • onItemAdded : UnityEvent<T> - The actions to perform when an item is added to the set.
  • onItemRemoved : UnityEvent<T> - The actions to perform when an item is remove from the set.
  • onItemsChanged : UnityEvent - The actions to perform when an item is added or removed from the set.

Public Properties

  • Collection : TSet - The collection being watched for changes.

Public Methods

  • RaiseItemAdded(T) - Manually raises the onItemAdded event with the value T provided.
  • RaiseItemRemoved(T) - Manually raises the onItemRemoved event with the value T provided.
  • RaiseItemsChanged - Manually raises the onItemsChanged event.

NOTE: Manually raising these events will only trigger the UnityEvent actions on this component.

BoolSetWatcher

Derives from RuntimeSetWatcher<T, TSet>.

Description

Component that watches a BoolSet for changes and raises events.

This component does not have any additional members.

ColorSetWatcher

Derives from RuntimeSetWatcher<T, TSet>.

Description

Component that watches a ColorSet for changes and raises events.

This component does not have any additional members.

DoubleSetWatcher

Derives from RuntimeSetWatcher<T, TSet>.

Description

Component that watches a DoubleSet for changes and raises events.

This component does not have any additional members.

FloatSetWatcher

Derives from RuntimeSetWatcher<T, TSet>.

Description

Component that watches a FloatSet for changes and raises events.

This component does not have any additional members.

IntSetWatcher

Derives from RuntimeSetWatcher<T, TSet>.

Description

Component that watches a IntSet for changes and raises events.

This component does not have any additional members.

ScriptableObjectSetWatcher

Derives from RuntimeSetWatcher<T, TSet>.

Description

Component that watches a ScriptableObjectSet for changes and raises events.

This component does not have any additional members.

StringSetWatcher

Derives from RuntimeSetWatcher<T, TSet>.

Description

Component that watches a StringSet for changes and raises events.

This component does not have any additional members.

TransformSetWatcher

Derives from RuntimeSetWatcher<T, TSet>.

Description

Component that watches a TransformSet for changes and raises events.

This component does not have any additional members.

Vector2IntSetWatcher

Derives from RuntimeSetWatcher<T, TSet>.

Description

Component that watches a Vector2IntSet for changes and raises events.

This component does not have any additional members.

Vector2SetWatcher

Derives from RuntimeSetWatcher<T, TSet>.

Description

Component that watches a Vector2Set for changes and raises events.

This component does not have any additional members.

Vector3SetWatcher

Derives from RuntimeSetWatcher<T, TSet>.

Description

Component that watches a Vector3Set for changes and raises events.

This component does not have any additional members.

Vector4SetWatcher

Derives from RuntimeSetWatcher<T, TSet>.

Description

Component that watches a Vector4Set for changes and raises events.

This component does not have any additional members.