This package provides utilities for implementing game architecture which is oriented around ScriptableObject
assets and game events. Most of these ideas are based on Unite2017.
- Game events - allows transferring of data between scripts using
ScriptableObject
event assets. - Game event listeners - listener components which allow subscribing to various events.
- Mutable objects - eases up sharing of mutable data via
ScriptableObject
assets.
This package can be installed by using the Unity Package Manager. To install this package, add the following to manifest.json
:
{ "dependencies": { "com.chark.unity-scriptable-objects": "https://github.com/chark/unity-scriptable-objects.git#upm" } }
Example usage of game events and mutable objects can be found in Assets/Samples directory. These samples can also be imported via Unity Package Manager.
Example usage of Game Event assets Example of a setup Game Event Listener component
Game events are scriptable objects (Right Click -> Create -> Game Events -> ...) which can be subscribed to via listener components (Add Component -> Game Events -> ...). Events allow to decouple scripts and instead rely on intermediate ScriptableObject
assets for communication.
Available game events:
GameEvent
- simple event which doesn't accept any arguments.BoolGameEvent
- event with abool
argument.IntGameEvent
- event with anint
argument.FloatGameEvent
- event with afloat
argument.StringGameEvent
- event with astring
argument.Vector2GameEvent
- event with aVector2
argument.Vector3GameEvent
- event with aVector3
argument.TransformGameEvent
- event with aTransform
argument.GameObjectGameEvent
- event with aGameObject
argument.
Example usage of Mutable Objects
Mutable objects are used for storing and editing data on ScriptableObject
assets at runtime. This data can be referenced, observed and used as a bridge by various scripts. Mutable objects are useful in situations where ScriptableObject
data needs to be reset when the active scene changes.
Available mutable objects:
MutableBool
- encapsulates abool
value.MutableInt
- encapsulates anint
value.MutableFloat
- encapsulates afloat
value.MutableString
- encapsulates astring
value.MutableVector2
- encapsulates aVector2
value.MutableVector3
- encapsulates aVector3
value.
Each mutable object has a ResetType
property. This allows specifying when data in the mutable object should be reset. The following modes are available:
None
- do not reset (default).ActiveSceneChange
- when the active (focused) scene changes.SceneUnloaded
- when the current scene gets unloaded.SceneLoaded
- when the scene is loaded.
In some situations, built-in game events might not suffice. For example if a custom type needs to be passed as an argument to the event. In this case, a custom game event can be created which would carry all the necessary data.
To create a custom game event, first create a regular UnityEvent
:
[Serializable] public class CustomEvent : UnityEvent<Custom> { }
After that is ready, create a game event by extending GameEvents.Generic.ArgumentGameEvent
:
[CreateAssetMenu(fileName = "CustomEvent", menuName = "Game Events/Custom Event")] public class CustomGameEvent : ArgumentGameEvent<Custom> { }
Finally, create a game event listener by extending GameEvents.Generic.ArgumentGameEventListener
:
[AddComponentMenu("Game Events/Custom Game Event Listener")] public class CustomGameEventListener : ArgumentGameEventListener<CustomGameEvent, CustomEvent, Custom> { }
, add a custom editor so that the event could be raised, and the listeners which reference the event get displayed in the inspector.
[CustomEditor(typeof(CustomGameEvent))] public class GameObjectGameEventEditor : ArgumentGameEventEditor<CustomGameEvent, Custom> { protected override Custom DrawArgumentField(Custom value) { var fieldValue = EditorGUILayout .ObjectField(value, typeof(Custom), true); return fieldValue as Custom; } }
In some cases, littering the script code with loads of MutableObject
references can be inconvenient. To avoid this, a single object can be used which encompasses multiple fields.
To create a custom mutable object, extend MutableObjects.Generic.MutableObject
and override ResetValues()
method, e.g:
[CreateAssetMenu(fileName = "MutableCustom", menuName = "Mutable Objects/Mutable Custom")] public class MutableCustom : MutableObject { [SerializeField] private int health = default; [SerializeField] private int armor = default; [SerializeField] private int xp = default; public int Health { get; set; } public int Armor { get; set; } public int Xp { get; set; } // This will set property values when mutable object is enabled or if the values change in the // inspector. public override void ResetValues() { Health = health; Armor = armor; Xp = xp; } }