I come from many years of ActionScript and purely object-oriented coding (that’s why I felt strange with iTween‘s gameObject oriented-ness, and built my own object-oriented Unity tween engine – HOTween). Even if I immediately plunged into Unity quite seriously, with my first job being the development of a complex interactive museum, I’m into Unity since one year only. Thus I obviously can’t state that my approach is the best one. It’s just AN approach: I personally feel very comfortable with it, and it’s quite flexible.
Journeyballs uses a mix of centralized approach and in-scene aggregation. Various global managers control all the different aspects of the game (like scoring, saving, event dispatching, etc.), scene-specific “brains” control how each single level is setup and behaves, and gameObject-specific MonoBehaviours power game elements.
I prefer to use centralized approaches where possible, thus I rely heavily on static global managers. Some of them are singletons, and some of those singletons get attached to global (meaning non-destroyable) empty gameObjects in the scene (in case I need some MonoBehaviour power).
Each scene/level contains an empty gameObject, which works as a “brain”. This brain has a series of MonoBehaviours attached, used to set each level’s options while in Unity’s editor. When a level is loaded, the LevelManager queries these settings, and sets them.
One of the most useful sides of the brain is to set special events while in Unity’s editor. Journeyballs in-editor panel connects to the current level’s brain, allowing me to do various stuff. For example, I can select objects and define them as “activators”, then select other objects and set them to be activated by a specific activator. During runtime, these settings will be evaluated each time a level is loaded, and the required classes/MonoBehaviours will be attached to the activators and to their targets.
In short, the brain is not actually a brain (not in the case of Journeyballs at least – I did other projects where it was more brainous). It’s more like a database of behaviors, injected into a specific level after its creation.
This part is simple, and it’s where I fully use Unity’s aggregation workflow. First of all, each game element has a main DestroyableMonoBehaviour attached (which is just a customized MonoBehaviour that allows to control how an object gets destroyed). After that, having an object behave in a specific way simply consists of adding the desired MonoBehaviours to it. For example, a spiky wheel which rotates on its Z axis will have both a “Hazard” MonoBehaviour and a “Rotator” MonoBehaviour attached.