A designer-friendly, editor-driven Unity3D framework for connecting data and events.
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
Core
Decorators
Editor
Event
Generated
Utilities
Core.meta
Decorators.meta
Editor.meta
Event.meta
Generated.meta
LICENSE
LICENSE.meta
README.md
README.md.meta
Utilities.meta

README.md

SmartData for Unity

A designer-friendly, editor-driven framework for connecting data and events.

Need a flexible way to connect everything in your game without singletons, hard-coding or overly-complex architecture? SmartData might be what you're looking for. It is based on Ryan Hipple's (twitter | github) amazing talk from Unite Austin 2017, which you are strongly recommended to watch before proceeding.

Game Architecture with Scriptable Objects

INSTALLATION

  • Grab SmartData.unitypackage from the Releases page for everything you need!
  • OR, to use the git repository, you'll need our events implementation, Relay[1]. github.com/SixWays/Relay
  • Requires Unity 2018.2 or above.

If you have issues with anything not discussed in this readme, please let us know - but check the wiki first!
SmartData also has a Unity forum thread here for further discussion.

What is SmartData?

Firstly, SmartData is in beta. With that out of the way, SmartData is a framework that uses ScriptableObjects to pass data around a game at the global level. Let's take a common example - showing the player's HP on the HUD. Let's assume the Player and the HUD are prefabs, dynamically instantiated at runtime, rather than placing them in each scene at edit-time and manually dragging references.

Note that the following pros and cons are entirely subjective. And there are many more methods we could use!

Traditional method A - Singletons

Our Player class is a singleton. We instantiate the Player prefab, then the HUD prefab, and the HUD uses Player.instance.hp.

Pros: Easy to code.
Cons: Encourages spaghetti code. Rigid coupling between classes. HUD depends on the Player instance existing. Not exposed to designers.


Traditional method B - Find reference at runtime

We don't like singletons, so instead the HUD searches for the Player using GameObject.Find in Awake().

Pros: Coupling is slightly less rigid.
Cons: Player must be called the right thing. HUD depends on the Player instance existing. Not exposed to designers.


SmartData method

We create a FloatVar asset called PlayerHp. In Player we declare a FloatWriter and in HUD a FloatReader.

In-editor, each script now has a field in which we can drag-and-drop our PlayerHp asset. Now they both refer to the same data.

HUD now has three ways to get the player's health:

  • Get playerHp.value in an update loop - the PlayerHp asset value will stay up-to-date with Player
  • Use the exposed UnityEvent in the editor and check Auto Listen - the event will fire when Player updates the value
  • Use playerHp.BindListener() to register for the event in code when Player updates the value

Pros: No code coupling. HUD can exist without Player (PlayerHp asset always exists). Exposed to designers.
Cons: More complex.


While SmartData takes a little more setup, it's far more flexible, powerful, safe and designer-friendly - and after a couple of uses, that setup is easy.

Now imagine a real codebase. You have dozens of singletons, your code is spaghetti, you need a coder every time a designer wants to get any of that data, and unless you instantiate everything in your scene - in the right order! - your game explodes, making low-level testing and iteration hellish.

With SmartData, global data is just a set of assets. Designers can access it at will with a set of Components, modify its behaviour and select at edit-time what references point to what data. Coders still retain control of their code, specifying read-only or read/write access from a given reference, with attributes to control what options a designer sees in the editor.

SmartData supports any underlying data type via its code generator GUI. It comes with a selection of basic SmartTypes pre-built such as float and string amongst others.

Note that any single SmartType only has one underlying data type. The multi-type editor above is simply for generating multiple SmartTypes at once for convenience.

SmartEvents

EventVars, accessible via EventListener and EventDispatcher references, simply raise events without any data payload. These are particularly useful for game-level events, such as starting, pausing the game, a player dying etc.

SmartComponents

Designers can use components which give code-free access to SmartObjects. Read/Listen components give a list of SmartRefs with UnityEvents. Write/Dispatch components give one SmartRef and the ability to set values and/or dispatch events from UnityEvents or other third-party design tools.

Imgur

Debugging

SmartData includes a visual debugger graph which shows all the current connections between SmartRefs (FloatReader, FloatWriter etc) and SmartObjects (FloatVar etc)[2]. At runtime, it will also animate to show updates and events.

SmartObjects will also show a list of connections in the inspector, and at runtime a list of objects listening to events from code.

NOTE: Plain references to SmartObjects will not show up in the node graph. You must use SmartRefs - e.g. FloatReader, FloatWriter.

Advanced Features

The above is just scratching the surface. SmartData has many other features which will gradually be documented in the wiki.

  • SmartSet - List of data with OnAdd and OnRemove events
    • e.g. a list of all AIs - AIs add/remove themselves and the AI manager (and anything else) listens.
  • SmartMulti - List of SmartVars created on demand
    • e.g. for local multiplayer games - PlayerHp[0-3]
  • Decorators - Like components for SmartObject assets, these modify behaviour
    • e.g. for clamped/ranged values or even automatic network replication
  • Code generation templates
    • Add your own templates to the Generate Types editor to generate custom code for each type.

What is SmartData not?

  • A visual scripting language / editor
  • A coding-free solution
  • Particularly good at runtime-instantiated SmartObjects - yet (see What's Next)
  • The answer to all your problems[3]

What's next?

The first focus will be more documentation and examples, since there's a lot here.

The next major planned feature is SmartGroups - a comprehensive solution for dynamically instantiating SmartObjects. Currently SmartData is all about edit-time data - make assets, link them by hand, profit. At runtime, you can create SmartObjects in code, and link to them in code, and destroy them in code, and unlink from them in code. You may have noticed a pattern.

For example, if you want an OnHit EventVar for every AI spawned, there's no easy edit-time way to specify what will be interested in these events, or how they will be indexed. SmartGroups aim to fix that. More later.

Note that SmartMultis are not intended to supply this functionality - they're a convenience for cases when there will be multiple long-lived instances of something. For example, with local multiplayer, your HUD elements can all reference a single "PlayerHp" FloatMulti asset by index. There's no good way to destroy one of the underlying FloatVars and no way to automatically stop listening to it.

Notes

  • Namespaces are generated for each underlying type. For example, SmartData.SmartFloat.FloatReader.
  • As mentioned, you'll need Relay in your project to use SmartData.
  • If you use Odin Inspector, you must disable it for the SmartData namespace.
  • Userspace code (generated classes etc) is nice and neat. The underlying hierarchy though is crazy complex, largely due to Unity's serialization quirks. It looks horrible, but it's all there for a reason. Sorry in advance.

Credits

Developed and maintained by Luke Thompson (@six_ways | github)
SmartGraph developed by Luca Mefisto (@LucaMefisto | github) based on his UnityEventVisualizer

Acknowledgements

SmartData, as previously mentioned, owes its existence and inspiration to Ryan Hipple (see above)
Development assistance, feedback and ideas provided by Eric Provencher (@prvncher) and Dustin Chertoff (@dbchertoff)

Footnotes

[1] Relay is not linked as a submodule for three main reasons. Firstly, you're fairly likely to be using SmartData as a submodule itself, and sub-submodules tend to confuse lots of git clients. Secondly, if you're already using Relay (you should be, but we're biased) it could get messy. Finally, Relay is pretty stable now so you should be able to grab a zip and forget about it.
[2] The graph is not editable!
[3] but only because nothing ever can be