As I've touched on earlier, there is no single way of designing an application. It's standard for the big players in the industry to push their own design pattern, and also for open source communities to embrace different architectures. This is both because no problem is the same, so there is always a different solution to fit these problems, and because some design patterns make code easier to understand and to maintain.
Coming from a c# background, I had no problem getting started with Unity programming. I did, however, have some hiccups with how the architecture is organised. Unity does not make many assumptions about the structure of your code, as long as it compiles the engine is happy. This situation brings with it the typical dilemma of having too much choice vs. too little - having this power often makes me a bit confused. In my quest to enlightenment, I stumbled upon Eduardo Dias Da Costa's MVC with Unity Guide, which gives a good insight on how to use the MVC pattern in Unity.
By default, Unity uses the Entity-Component pattern. In this familiar pattern, you start by outlining all the elements (entities) we want in our application. Once this is mapped out, you go in to define the logic and data that each entity should use (components). In c# this would be the equivalent of an object, containing an array or ArrayList of components. Eduardo argues that since developing games is not different from other software development in that you detect input, act upon the data collected only to push this raw or processed information back into the view. You might also store this data or maybe the entire sequence of user inputs in a database. It is no different from any conventional MVC application.
Data, interface and decisions. Models views and controllers. This is the correlation I struggled to apprehend in unity, or rather, how to put MVC on top of the already existing EC pattern Unity is built on. Luckily, the flexibility of MVC allows us to do just this. The caveat with the general MVC pattern laid on top EC in Unity, as Eduardo explains, is the references you need to scatter all over your component and script files. The typical situation in unity is that you must drag files or objects around to attach them to different entry and exit points in your components. If unity crashes, you forget to save some changes, or you modify the file structure or code hierarchy, reference-hell will reign upon your poor soul. This makes it obligatory to have a single root reference object in where you can programmatically assign references. Because MVC encourages modularity, and each object having its own view, controller and model scripts, we also encounter a problem once we want to reuse code. We want to have the ability to have highly reusable scripts encapsulated so we can attach them to any entity. Eduardo came up with a pattern called AMVCC.
- Application - A single entry point to your application and container of all critical instances and application related data.
- MVC - ...
- Component - Small, well-contained script that can be reused.
Usually, then, follows a discussion or insecurity about where something belongs in what part of the MVC structure, often referred to as MVC sorting. Eduardo goes ahead to provide a very helpful guide to just this problem, see under. Keep in mind that analysing a problem beforehand is something totally different than tackling the problem head on.
- Hold the application’s core data and state, such as player health or gun ammo.
- Serialize, deserialize, and/or convert between types.
- Load/save data (locally or on the web).
- Notify Controllers of the progress of operations.
- Store the Game State for the Game’s Finite State Machine.
- Never access Views.
- Can get data from Models in order to represent up-to-date game state to the user. For example, a View method player.Run() can internally use model.speed to manifest the player abilities.
- Should never mutate Models.
- Strictly implements the functionalities of its class. For example:
- A PlayerView should not implement input detection or modify the Game State.
- A View should act as a black box that has an interface, and notifies of important events.
- Does not store core data (like speed, health, lives,…).
- Do not store core data.
- Can sometimes filter notifications from undesired Views.
- Update and use the Model’s data.
- Manages Unity’s scene workflow.