Ever had that feeling of, fckit, let’s just start over! Over the years, I have ran into this problem so many times, on our own project and client projects. Projects get messy and you might as well start over instead of trying to fix it. The Monolithic Project problem quickly reveals it’s self, especially if more people come onto the project, with no coding standards, etc… in place.
In this document I highlight some of the options we have when it comes to planning (Architecting) the Unity project.
We need to think ahead, and plan.
Scalable Game Development
Unity Project
Art Pipeline
Code
Build Tools
Multi-platform
Externalizing Data
Better GUI
Editor Tools
The Let’sJustDoIt “Pattern”
This is the default way people write code, I call it pattern, since 99% of also course do it this way, hence, a pattern. I dont blame them, each course on YouTube, Udemy, Pluralsight, LinkedIn Learning, all start out exactly the same. “Lets start by making a script for XYZ….”
XGD Pattern
Data - ScriptableObjects are nice, but it has limitations:
Unity Dependant
No easy way to convert from CSV/JSON to scriptable objects.
Linking/Reference ScriptableObjects is basically the same as linking MonoBehaviours
ScriptableObject can be loaded by:
Reference
Resources.Load
Singleton with Resources.Load
Asset Bundles
Clean Architecture
https://michael-martinez.fr/clean-unity-architecture/
https://unity3d.com/how-to/architect-code-as-your-project-scales
https://github.com/umm/cafu_core
https://www.slideshare.net/monry84/clean-architecture-for-unity
https://www.youtube.com/watch?v=8Hy4JvtfUb8
https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html
https://pusher.com/tutorials/clean-architecture-introduction
https://dev.to/bosepchuk/why-i-cant-recommend-clean-architecture-by-robert-c-martin-ofd
https://www.freecodecamp.org/news/a-quick-introduction-to-clean-architecture-990c014448d2/
https://www.amazon.com/Clean-Architecture-Craftsmans-Software-Structure/dp/0134494164
https://gist.github.com/ygrenzinger/14812a56b9221c9feca0b3621518635b
https://michael-martinez.fr/clean-unity-the-controller-manager-issue/
ECS
Unite Europe 2016 - ECS architecture with Unity by example
https://www.youtube.com/watch?v=lNTaC-JWmdI&t=2s
Entity system architecture with Unity - Unite Europe 2015
https://www.youtube.com/watch?v=1wvMXur19M4&t=2s
Reactive
UniRx Reactive Extensions for Unity
https://github.com/neuecc/UniRx
Design Patterns
https://www.oodesign.com/
http://gameprogrammingpatterns.com/
https://jacksondunstan.com/articles/3092
https://unity3d.com/learn/tutorials/modules/intermediate/scripting/coding-practices?playlist=17117
https://learn.unity.com/learn/search?k=%5B%22q%3AScripting%22%5D
http://unite.schellgames.com/Unite_2011_Scalable_Game_Development.pptx
MVC
Model - game logic
View - Graphics, 3D models, etc..
Controller - Interface to the model
From a user’s perspective
View
User Action -> Controller
Read state -> Model.State
Controller
Write State -> Model.State
Call Functions - > Model.function
Model
State
Functions
MVCS
References
http://www.rivellomultimediaconsulting.com/unity3d-mvcs-architectures-strangeioc/
Robot Swarm
Reactive Programming
http://www.rivellomultimediaconsulting.com/unity3d-reactive-extensions-1/
uFrame
https://github.com/InvertGames/uFrame-MVVM
https://www.assetstore.unity3d.com/en/#!/content/14381
StrangeIoC
https://github.com/strangeioc/strangeioc
https://www.assetstore.unity3d.com/en/#!/content/9267
Entitas
https://github.com/sschmid/Entitas-CSharp
https://www.assetstore.unity3d.com/en/#!/content/87638
https://github.com/sschmid/Entitas-CSharp
https://youtu.be/1wvMXur19M4
https://youtu.be/lNTaC-JWmdI
UniRx
Zenject
Entity–component–system
https://en.wikipedia.org/wiki/Entity%E2%80%93component%E2%80%93system
https://en.wikipedia.org/wiki/Entity%E2%80%93component%E2%80%93system
Singleton Pattern
Examples: Audio Manager
private static AudioManager instance;
public static AudioManager Instance
{
get { return instance; }
}
void Awake()
{
instance = this;
}
Create a reusable Singleton pattern using T
Beware of Singleton abuse!
Some call it an anti-pattern
Thin Component Pattern
Model should be separate from Unity
Example:
Controller
VechileComponent : MonoBehavior
Handles all unity related functions
Model
Driver
Attributes
Operations
Weapon System
Attributes
Operations
MVVM
Model
View
ViewModel
Or rather
View
UI
UI Logic (Code Behind)
Data Binding <-> ViewModel
Commands <-> ViewModel
ViewModel
Notifications -> View
Presentation Logic
Model
Business Logic (Game Logic)
Entities
References
http://www.what-could-possibly-go-wrong.com/bringing-mvvm-to-unity-part-1-about-mvvm-and-unity-weld/
http://www.what-could-possibly-go-wrong.com/bringing-mvvm-to-unity-part-2-property-and-event-bindings/
https://forum.unity.com/threads/mvvm-databinding-and-lobby-toolkit.232526/
Data-Driven Design (DDD)
Techniques and strategies for data-driven design in game development
http://web.eecs.umich.edu/~soar/Classes/494/talks/Schumaker.pdf
Data-driven and component-based game entities
https://archive.fosdem.org/2012/schedule/event/536/104_Thomas_Kinnen_-_Data-Driven_and_Component-Based_Game-Entities_-_Slides.pdf
Component-Based Design (CBD)
References: https://en.wikipedia.org/wiki/Component-based_software_engineering
https://www.youtube.com/watch?v=1YGVP6wsxj0
ScriptableObjects
Unite Europe 2016 - Overthrowing the MonoBehaviour tyranny in a glorious ScriptableObject revolution
https://www.youtube.com/watch?v=VBA1QCoEAX4
https://www.youtube.com/watch?v=VtuSKmfrFDU&t=10s
https://www.youtube.com/watch?v=raQ3iHhE_Kk&t=46s
Unity Scriptableobject Architecture
References
https://github.com/jheiling/unity-signals
https://www.schellgames.com/blog/insights/game-architecture-with-scriptable-objects
https://github.com/roboryantron/Unite2017
https://www.slideshare.net/RyanHipple/game-architecture-with-scriptable-objects
https://www.google.com.au/search?q=unity+scriptableobject+architecture&safe=off&rlz=1C5CHFA_enAU772AU772&tbm=isch&tbo=u&source=univ&sa=X&ved=0ahUKEwjj16L99t7bAhXItpQKHQaJBQUQsAQIsQE
1:04:29
Unite Austin 2017 - Game Architecture with Scriptable Objects
15:33
Unity3D - Using ScriptableObject for Data architecture / sharing
https://www.youtube.com/watch?v=8TIkManpEu4
Event subscriber/listener pattern
A.K.A Messaging System
EventManager
using UnityEngine;
using UnityEngine.Events;
using System.Collections;
using System.Collections.Generic;
public class EventManager : MonoBehaviour {
private Dictionary <string, UnityEvent> eventDictionary;
private static EventManager eventManager;
public static EventManager instance
{
get
{
if (!eventManager)
{
eventManager = FindObjectOfType (typeof (EventManager)) as EventManager;
if (!eventManager)
{
Debug.LogError ("There needs to be one active EventManger script on a GameObject in your scene.");
}
else
{
eventManager.Init ();
}
}
return eventManager;
}
}
void Init ()
{
if (eventDictionary == null)
{
eventDictionary = new Dictionary<string, UnityEvent>();
}
}
public static void StartListening (string eventName, UnityAction listener)
{
UnityEvent thisEvent = null;
if (instance.eventDictionary.TryGetValue (eventName, out thisEvent))
{
thisEvent.AddListener (listener);
}
else
{
thisEvent = new UnityEvent ();
thisEvent.AddListener (listener);
instance.eventDictionary.Add (eventName, thisEvent);
}
}
public static void StopListening (string eventName, UnityAction listener)
{
if (eventManager == null) return;
UnityEvent thisEvent = null;
if (instance.eventDictionary.TryGetValue (eventName, out thisEvent))
{
thisEvent.RemoveListener (listener);
}
}
public static void TriggerEvent (string eventName)
{
UnityEvent thisEvent = null;
if (instance.eventDictionary.TryGetValue (eventName, out thisEvent))
{
thisEvent.Invoke ();
}
}
}
Event Listener
using UnityEngine;
using UnityEngine.Events;
using System.Collections;
public class EventTest : MonoBehaviour {
private UnityAction someListener;
void Awake ()
{
someListener = new UnityAction (SomeFunction);
}
void OnEnable ()
{
EventManager.StartListening ("test", someListener);
EventManager.StartListening ("Spawn", SomeOtherFunction);
EventManager.StartListening ("Destroy", SomeThirdFunction);
}
void OnDisable ()
{
EventManager.StopListening ("test", someListener);
EventManager.StopListening ("Spawn", SomeOtherFunction);
EventManager.StopListening ("Destroy", SomeThirdFunction);
}
void SomeFunction ()
{
Debug.Log ("Some Function was called!");
}
void SomeOtherFunction ()
{
Debug.Log ("Some Other Function was called!");
}
void SomeThirdFunction ()
{
Debug.Log ("Some Third Function was called!");
}
}
Event Caster
using UnityEngine;
using System.Collections;
public class EventTriggerTest : MonoBehaviour {
void Update () {
if (Input.GetKeyDown ("q"))
{
EventManager.TriggerEvent ("test");
}
if (Input.GetKeyDown ("o"))
{
EventManager.TriggerEvent ("Spawn");
}
if (Input.GetKeyDown ("p"))
{
EventManager.TriggerEvent ("Destroy");
}
if (Input.GetKeyDown ("x"))
{
EventManager.TriggerEvent ("Junk");
}
}
}
References:
https://www.youtube.com/watch?v=0AqG1fDhPT8
Finite State Machines (FSM)
Panda BT
https://www.assetstore.unity3d.com/en/#!/content/33057
PlayMaker
https://hutonggames.com/
decorator pattern
https://en.wikipedia.org/wiki/Decorator_pattern
Passive View
https://martinfowler.com/eaaDev/PassiveScreen.html
Testing
Quote on debugging
“Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.”
- Brian Kernighan
MonoBehaviour
Set Assembly Folders
Good pattern to debug
Debug.Log(nameOfComponent + “ message “, this );
Delete Debug.Log when no you release
Solve warnings and errors
Write own Debug system, can disable it globally
Make error handling LOUD, cause
Unit testing (NUnit)
Easy way to test functions on components
[ContextMenu(“Attack”)]
private void TestAttack(){
…
}
Right click the component to set the function, this also works in edit mode (without playing)
Integration Testing
Profile and Analyser
Project Management
http://initiative.online/p/demystifying-unity-for-large-projects-6-rules/
Folder Structure
ProjectName
Unity
Library
Project Settings
Assets
Code
Editor
Game
Test
Content
Art
Audio
Effects
Scenes
Test
Documents
RawAssets
Version Control
BitBucket
GitFlow
Use blame
Estimations
Estimation = Original estimation * = PI
uFrame
https://assetstore.unity.com/packages/tools/visual-scripting/uframe-game-framework-14381
Pokemon Go
Was a new genre
Dependency Injection
Normal Polymorphism
IOC (Inversion of Control) Polymorphism
Traditional Dependency Injection
Zenject
Uses a GameState system
Ideas
Create a JSON file structure for GUI
Unity Packages
Marklight
https://assetstore.unity.com/packages/tools/gui/marklight-unity-presentation-framework-37466
Zenject
https://assetstore.unity.com/packages/tools/zenject-dependency-injection-ioc-17758
Introduction
Context is everything! The users of games are not the same as the users of apps
Current
Dotted lines are symbolic
SOLID
Single Responsibility
Open-Close
Liskov Substitution
Interface Segregation
Dependency Injection
Dependency injection
https://unity3d.com/unity/features/job-system-ECS
https://blogs.unity3d.com/2014/05/07/dependency-injection-and-abstractions/
http://wiki.unity3d.com/index.php/Dependency_injection
https://github.com/modesttree/Zenject
http://strangeioc.github.io/strangeioc/
https://www.oodesign.com/dependency-inversion-principle.html
Promises
Links
https://github.com/Real-Serious-Games/c-sharp-promise#understanding-promises
http://www.what-could-possibly-go-wrong.com/promises-for-game-development/
Push or Pull
Low level pulls data from high level, but the issue is, it doesn’t know when.
Subscribe on Awake
Unsubscribe on Destroy
Inheritance vs Interfaces
What it is VS what it can do
Lazy vs Eager
Game uses eager
Abstraction
Virtual or abstract methods
Generic
TrackViewBase
…
TrackViewImage : TrackViewBase
Lis
Custom Samplers
Seperate Input Modules
C# Indexers
Partial Class
Unity Architecture
Scriptable Objects
Unity ScriptableObjects
Unite Europe 2016 - Overthrowing the MonoBehaviour tyranny in a glorious ScriptableObject revolution
https://www.youtube.com/watch?v=VBA1QCoEAX4&t=2s
Unite Austin 2017 - Game Architecture with Scriptable Objects
https://www.youtube.com/watch?v=raQ3iHhE_Kk
General
Use
[SerializeField]
private TYPE NAME;
Component Abuse
Either too many or too little components
Make a system has to be a component
Unity Project Static
Project Components
Unity-dependent systems
Unity-independent systems
Unity
.Net
Flux
Its only the views that change….
Tic Tac Toe
Player makes a move — puts a X somewhere on the board
The system needs to check if the move is legal — whether the slot is free. That is done by running a set of rules on the board model.
If it is NOT free — the ADD_ITEM_FAILURE action should be dispatched, thus keeping the currentPlayer property without change.
If it is free — the ADD_ITEM_SUCCESS action should be dispatched
The boardReducer should update the board.
The gameRuntimeReducer should update the current player
If the second player is AI — the AI manager should fire up the CALCULATE_NEXT_MOVE action
After the next move is calculated, the TRY_ADD_ITEM should be fired, resulting in a succesfull board update and switching control to the other player.
State
{
board:{}, //Current state of the board
players:[], //Player objects, each player has a name and colour
currentPlayer:{}, //Who is the current player to make a move?
time:DateTime, //How much time passed since game start?
steps:int //How many steps were taken until now?
}
Actions
actions/moves //TRY_ADD_ITEM, ADD_ITEM_SUCCESS, ADD_ITEM_FAILURE - player makes a move - add item to board
actions/rules //RUN_RULES - to run rules on board to determine if someone won.
actions/board //CLEAR_BOARD
actions/game // GAME_START, GAME_END,…
actions/AI //CALCULATE_NEXT_MOVE
Reducers
boardReducer //updates the board model
gameRuntimeReducer //Updates game runtime - currentPlayer, time, steps, etc.
https://github.com/mattak/Unidux
Design Patterns
Singleton Pattern
Examples: Audio Manager
private static AudioManager instance;
public static AudioManager Instance
{
get { return instance; }
}
void Awake()
{
instance = this;
}
Create a reusable Singleton pattern using T
Beware of Singleton abuse!
Some call it an anti-pattern
Flexible Software Architecture
MVC
Model - game logic
View - Graphics, 3D models, etc..
Controller - Interface to the model
From a user’s perspective
View
User Action -> Controller
Read state -> Model.State
Controller
Write State -> Model.State
Call Functions - > Model.function
Model
State
Functions
MVVM
MVP
MVC
Model
The model class only stores the data
View
The view only displays data
View can be MonoBehaviour or UIBehavior
https://docs.unity3d.com/ScriptReference/EventSystems.UIBehaviour.html
Updates when the data changes
Receive events from controllers.
Controller
The controller only manipulates the data
Start with View
Model
Ask the question, what is the object?
Controller
Reads data
Resources
NOTE!: XGameDev template document
Course:
https://www.udemy.com/unity-model-view-controller/learn/v4/t/lecture/6981038?start=0
Thin Component Pattern
Model should be separate from Unity
Example:
Controller
VechileComponent : MonoBehavior
Handles all unity related functions
Model
Driver
Attributes
Operations
Weapon System
Attributes
Operations
MVVM
Model
View
ViewModel
Or rather
View
UI
UI Logic (Code Behind)
Data Binding <-> ViewModel
Commands <-> ViewModel
ViewModel
Notifications -> View
Presentation Logic
Model
Business Logic (Game Logic)
Entities
Testing
Quote on debugging
“Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.”
- Brian Kernighan
MonoBehaviour
Set Assembly Folders
Good pattern to debug
Debug.Log(nameOfComponent + “ message “, this );
Delete Debug.Log when no you release
Solve warnings and errors
Write own Debug system, can disable it globally
Make error handling LOUD, cause
Unit testing (NUnit)
Easy way to test functions on components
[ContextMenu(“Attack”)]
private void TestAttack(){
…
}
Right click the component to set the function, this also works in edit mode (without playing)
Integration Testing
Profile and Analyser
Project Management
Folder Structure
ProjectName
Unity
Library
Project Settings
Assets
Code
Editor
Game
Test
Content
Art
Audio
Effects
Scenes
Test
Documents
RawAssets
Version Control
BitBucket
GitFlow
Use blame
Estimations
Estimation = Original estimation * = PI
uFrame
https://assetstore.unity.com/packages/tools/visual-scripting/uframe-game-framework-14381
Pokemon Go
Was a new genre
Dependency Injection
Normal Polymorphism
IOC (Inversion of Control) Polymorphism
Traditional Dependency Injection
Zenject
Uses a GameState system
Ideas
Create a JSON file structure for GUI
Unity Packages
Marklight
https://assetstore.unity.com/packages/tools/gui/marklight-unity-presentation-framework-37466
Zenject
https://assetstore.unity.com/packages/tools/zenject-dependency-injection-ioc-17758
References
https://www.youtube.com/watch?v=q9aeNtKKXeo
https://github.com/jbruening/ugui-mvvm
https://www.codeproject.com/Articles/100175/Model-View-ViewModel-MVVM-Explained
https://wiki.nus.edu.sg/display/TitanomachyRTS/Architecture+Design+for+User+Interface
https://localwire.pl/uframe-mvvm-and-separation-of-concerns/
https://github.com/peterloos/Wpf_TowersOfHanoi/tree/master/TowersOfHanoi
https://www.youtube.com/watch?v=q9aeNtKKXeo
https://github.com/jbruening/ugui-mvvm
https://www.codeproject.com/Articles/100175/Model-View-ViewModel-MVVM-Explained
https://wiki.nus.edu.sg/display/TitanomachyRTS/Architecture+Design+for+User+Interface
https://localwire.pl/uframe-mvvm-and-separation-of-concerns/
https://github.com/peterloos/Wpf_TowersOfHanoi/tree/master/TowersOfHanoi
https://www.toptal.com/unity-unity3d/unity-with-mvc-how-to-level-up-your-game-development
https://forum.unity.com/threads/unity-best-architecture-and-design-pattern.424786/
https://www.gamasutra.com/view/feature/132649/the_case_for_game_design_patterns.php?page=2