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
ScriptableObjectevent assets. - Game event listeners - listener components which allow subscribing to various events.
- Mutable objects - eases up sharing of mutable data via
ScriptableObjectassets.
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 aboolargument.IntGameEvent- event with anintargument.FloatGameEvent- event with afloatargument.StringGameEvent- event with astringargument.Vector2GameEvent- event with aVector2argument.Vector3GameEvent- event with aVector3argument.TransformGameEvent- event with aTransformargument.GameObjectGameEvent- event with aGameObjectargument.
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 aboolvalue.MutableInt- encapsulates anintvalue.MutableFloat- encapsulates afloatvalue.MutableString- encapsulates astringvalue.MutableVector2- encapsulates aVector2value.MutableVector3- encapsulates aVector3value.
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; } }