Certain coding patterns have emerged in the game’s codebase, many of them influenced by my time spent writing web and client applications. I know some “experts” will get up in arms about how games are different and shouldn’t be written like other types of apps but I tend to disregard philosophical arguments in favor of pragmatism. On a related note, in this reddit thread a couple of people commented on a previous post on using a messaging system in Unity, mentioning it could suffer from performance problem. I must explain: I am not advocating that the patterns I’m using are either the best way, or even the only way to do things in the same code base. Indeed I only use the messenger/mediator pattern where the dependencies are very loose and there isn’t high traffic communication. Additionally I think some of these patterns lend themselves more to the type of game I’m making: turn-based, heavy on events / UI and light on real-time mechanics. With that, let’s have a look at the solution structure:
The sub folders are based on features. I have come find this a more logical and discoverable structure in larger projects, compared to folders that are broken up by type. For example if you have ever worked with
ASP.NET MVC you’ll note that by default Controllers, Views, and Models are 3 separate top-level folders. This is fine initially but once you have tens of controllers, it’s a lot nicer to group all related files (controller, view and model) into the same “feature” folder.
The second thing to note is the sub folders and files. The core game logic lives in classes in the
Entities folder. These are pure C# classes (i.e. not overriding
MonoBehaviour) which do not interact with the Unity engine. There may be texture names as strings or
Vector3s for holding the position of an entity, but there is no direct interaction with Unity classes, renderers, UI, etc. Advantages of this approach are:
- Testability: This isn’t just a pipe dream. I have started strategically unit testing parts of the game logic, and this makes it a breeze because I don’t need to deal with mocking any Unity components.
- Persistence: Once I get to persistence (saving/loading the game) it’ll be a lot clearer what bits need to be saved (entity state) and what doesn’t (presentation state).
- Multiple views: Another nice thing here is that I can have multiple presenters for the same entity object. For example an employee object will have a presenter that deals with its rendering and animation in the game level, and a different presenter that shows his/her avatar and stats in the employee management UI.
The presenters then, are
MonoBehaviours that present one or more entities and can be associated with a prefab. They do all things presentation related (e.g. loading prefabs, positioning game objects, dealing with materials, UI click event handlers, etc). They do not hold any game state, but may contain presentation state (e.g. current animation frame). I use Zenject to inject the entity into the presenter at the time of creation.
Note that the entities are completely unaware of their presenters (like any typical MVC / MVVM implementation). Instead the presenters “watch” the model state and respond accordingly. Here are a couple of ways this can happen:
- For real time state like position, the presenter can continually check the state in the
- For more infrequent updates that are very specific to that entity, it can publish an event which the presenter subscribes to. I’m not a huge fan of events but it’s one of the better options in this scenario. Note that the presenter should unsubscribe from the events in
OnDestroy()to avoid any memory leaks.
- For more ambient / game-level events, both the presenter and/or entity can subscribe to, and publish messages (see this post).
Finally I have a
UI folder which honestly could be folded into
Presenters. It was initially there for bits of UI that strictly support a Canvas with UI events, such as the main menu.
Isn’t this just MVC or MVVM Pattern?
Well, yes and no. The goal here is still separating game from presentation logic. But unlike MVC and MVVM there are no controllers present here, nor any two-way data binding. I don’t think those constructs really make sense for a game (except maybe for UI. There are some Unity assets available for that very purpose).
And the weekly update?
This week has been a little less productive than usual, but I did manage to finish a first draft of the investment mini-game. The company valuation equation is super simplistic and the counter offer systems doesn’t yet have much variety in terms of investor personality, but I think it’s at a state that is playable and ready for feedback.