Go to file
Jeff Campbell 943451b3d5 Cleaned up code readability, naming style to be consistent
* Add abstract modifier to all generic classes meant not to be instantiated directly as the intent is to specify a pattern for a closed type that can be serialized.
* Added sealed keyword to all closed types. This is an incidental performance improvement for mobile and desktop platforms utilizing il2cpp due to the way unsealed vs sealed virtual methods are handled in generated C++ code.
* Also sealed all inspectors to mark them as closed types.
* Dropped all where constraints to the next line as most of these class declarations break 120-130 characters. This should help improve readability and make this style consistent as it has been in use for the most-complex generic types already, but not for others.
* Dropped all generic type parameters (generally) numbering three or more to the next line to improve readability.
* Where found, added empty lines between property/field declarations in classes to improve readability.
* Extracted several 2x event classes into their own files to match convention established by other event classes.
* Removed unecessary meta files for C# solution.
* Added compiler options file (csc.rsp) file for the Unity project and added global warning ignore for 0649 (Field 'field' is never assigned to, and will always have its default value 'value'). This is necessary since 2018.3 switched the compiler to Roslyn and by design they have decided to not suppress this warning for monobehavior fields that are private, but serialized. This is very widely contested as most developers will not make every field needed to be assigned in the Editor as public (breaks encapsulation, opens surface area for bugs) and this can in some cases generate hundreds if not thousands of warnings. Adding the compiler options file suppresses this warning which also may hide legitimate warnings, but is far the lesser of two evils.
* Moved example scripts not in a namespace to UnityAtoms.Examples.
* Reordered public/private fields and properties to be consistent. Order is as follows; public and private properties followed by public/private fields.
* Renamed private fields to use '_' prefix and marked public fields as private where only used internally. Marked these fields with FormerlySerializedAs attribute to preserve older serialized values already in use.
* Removed redundant initialization of null to reference types as this is their default value.
* Marked implicitly private methods and members without an access modifier as explicitly private.
* Updated unit tests to use new private name field when getting private member field info.
2019-04-07 17:57:52 +02:00
Source Cleaned up code readability, naming style to be consistent 2019-04-07 17:57:52 +02:00
UnityAtomsTestsAndExamples Cleaned up code readability, naming style to be consistent 2019-04-07 17:57:52 +02:00
.editorconfig Squashed commit of the following: 2019-03-17 23:43:20 +01:00
.gitattributes Added .gitattributes file 2019-04-07 11:56:55 +02:00
.gitignore Squashed commit of the following: 2019-03-17 23:43:20 +01:00
LICENSE Added license 2018-11-18 15:56:29 +01:00
LICENSE.meta Squashed commit of the following: 2019-03-17 23:43:20 +01:00
omnisharp.json Squashed commit of the following: 2019-03-17 23:43:20 +01:00
omnisharp.json.meta Squashed commit of the following: 2019-03-17 23:43:20 +01:00
package.json Squashed commit of the following: 2019-03-17 23:43:20 +01:00
package.json.meta Squashed commit of the following: 2019-03-17 23:43:20 +01:00
README.md Updated README 2019-04-05 15:29:55 +02:00
README.md.meta Squashed commit of the following: 2019-03-17 23:43:20 +01:00
Source.meta Squashed commit of the following: 2019-03-17 23:43:20 +01:00
UnityAtomsTestsAndExamples.meta Squashed commit of the following: 2019-03-17 23:43:20 +01:00

⚛️ Unity Atoms

Tiny modular pieces utilizing the power of Scriptable Objects

Read this article on Medium for a great introduction to Unity Atoms.

Influences

Unity Atoms is derrived from and a continuation of Ryan Hipple's talk from Unite 2017. The original source code can be found here.

This talk by Richard Fine is a forerunner to Ryan Hipple's talk during Unite 2016.

Motivation

The general approach to building scripts in Unity often generates a code base that is monolithic. This results in that your code is cumbersome to test, non-modular and hard to debug and understand.

Unity Atoms is an open source library that aims to make your game code:

  • 📦 Modular - avoid scripts and systems directly dependent on each other
  • ✏️ Editable - Scriptable Objects makes it possible to make changes to your game at runtime
  • 🐞 Debuggable - modular code is easier to debug than tightly coupled code

Introduction

Before you start looking into this library you should watch the video above ☝️ and read this article on how to architect your game with Scriptable Objects.

Installation

Prerequisite: Since Unity Atoms is using the Unity Package Manager (UPM) you need to use Unity version 2018.3 >=

There are 2 versions you can install, either the stable version (master branch) or the canary version (latest and greatest - canary branch). Be aware that the canary version might sometimes break.

Stable

Go to your projects Packages/manifest.json and add this: "dependencies": { ... "com.mambojambostudios.unity-atoms": "https://github.com/AdamRamberg/unity-atoms.git", ... }

Canary

Go to your projects Packages/manifest.json and add this: "dependencies": { ... "com.mambojambostudios.unity-atoms": "https://github.com/AdamRamberg/unity-atoms.git#canary", ... }

Usage

Unity Atoms is an event based system that encourages the game to be as data-driven as possible. The 4 most fundamental pieces (atoms) of Unity Atoms are:

  • Variables
  • (Game) Events
  • (Game Event) Listeners
  • Responses

Variables

Variables are data / variables stored as Scriptable Objects. Because Variables are stored as Scriptable Objects they are not part of any scene, but could be instead be seen as part of a global shared game state. Variables are also designed to make it easy to inject (via the Unity Inspector) to your MonoBehaviours.

It is possible to attach an event to a Variable that gets raised when its updated. This makes it possible to write more data-driven code.

It is also possible to attach another event to a Variable that also gets raised when a Variable is changed, but that contains both the old and the new value of the Variable.

Unity Atoms also offer some variations / additions to Variables such as Contants, References and Lists.

Constants

Exactly the same as Variables, but can not be changed via script and therefore does not contain the change events that Variables does. The idea is to use Constants for for example tags instead of hard coding tags in your scripts.

References

References can be toggled between "use as constant" or "use variable" via the Unity Inspector. When a reference is "used as constant" then it functions exactly like a regular serialized variable in a MonoBehaviour script. However, when it is set to "use variable" it functions exactly like a Variable.

Lists

A list is an array of values that is stored as a Scriptable Object. There is the possibility to add Game Events for when the following happens to the list:

  • An item is added to the list.
  • An item is removed from the list.
  • The list is cleared.

Game Events

A game event is a thing that happens in the game that others could listen / subscribe to. Game events are also Scriptable Objects that lives outside of a specific scene. It is possible to raise a Game Event from the Unity Inspector for debug purposes.

Game Event Listeners

A listener listens / observes / subscribes to an event and raises / invokes zero to many responses to that event. Game Event Listeners are Monobehaviours and lives in a scene. See below for more information on the type of responses there are.

Responses

A responses is raised by a listener in response to an event. Responses can live both in the scene as UnityEvents or outside the scene as a Scriptable Object in the shape of a Game Action or a Game Function.

Game Actions

A Game Action is a C# function as a Scriptable Object. A Game Function can be used as a response in a Game Event Listener.

Game Functions

A Game Function is basically the same as a Game Action, but while a Game Actions does not return something a Game Function does.

Mono Hooks

Mono Hooks is a way to make it possible to have Unity lifecycle methods as events. The main reason for this is to make this pattern consistent and possible to use in ALL of your code.

Further Notes

When you start thinking about this pattern you will realize that everything can be explained using the atoms above. The native Unity lifecycle methods can be thought of as variation of the pattern above, where events gets raised and passes a long data (eg. OnTriggerEnter2D) and you write a response to that event.

Examples

Examples can be found in the UnityAtomsTestsAndExamples folder.

Contribution

Would ❤️ if you would like to contribute to the project. Post me a message, create an issue or start working on an existing issue if you want to contribute.

Project structure

  • Source - contains all the source code for the library
  • UnityAtomsTestsAndExamples - this folder is a Unity project folder that contains examples and tests. This folder is not included in the distribution of Unity Atoms.

The reason for this project structure is that we want to include tests and examples in the repo (both needing a Unity project), but there are at the same time currently some restrictions when using the UPM regarding how to import it to your project.

UPM doesn't allow...

  • importing a sub folder in a Git repo.
  • excluding files (using property "files" in package.json) when importing locally using the file syntax (eg. "com.mambojambostudios.unity-atoms-src": "file:../../Source").
  • package.json in subdirectories (only root level)

Current project structure therefore allows for...

  • including an example repo for examples and tests
  • use the local source in the example repo
  • referencing this git repo in another project's manifest file

Pull requests

Pull requests should be made to the canary branch.