Fun Tower Defense
This is a simple "Fun Tower Defense" (FTD) game.
- Unity 2017.x
- C# Programming
- Custom MVC Architecture
- Mostly new code
- Dependencies: Thanks to DOTween and Bendangelo for some helpful existing code.
RMC namespace is mine too and refers to the name of the GIT repo).
To Play Game
- Open Unity 2017.x
- Press Play
To Increase Difficulty
The game is pretty easy by default. This is to help illustrate the core project concepts without frustrating the reviewer.
Want increased difficulty? Use the Unity inspector to view and update the instances within
To View Source
The architecture of MVC divides the core project elements into 3 tiers; Model, View, Controller. This separation of concerns is a helpful tool to support celebrated principles of readable, scalable software including decoupling, SRP, and KISS.
- This contains the app's data. Exposes a public API to the data.
- It knows nothing about the larger context of the application.
- Dispatches events (e.g. when data changes)
- It displays the app's data (e.g. renders graphics and audio)
- This knows little about the larger context of the application.
- Listens to events (e.g. when data changes), but does not change the data. Dispatches events (e.g. when the user clicks the screen)
- This Manipulates the app's data (e.g. reduce player health). It also connects the user's input from the View into changes in the model.
- It knows much about the larger context of the application.
- Listens to high-level events (e.g. when the player dies) and translates that into meaningful consequences
The classic approach to MVC was not created with Unity in mind. In
FunTowerDefense some modifications to the architecture exist...
BaseModelsubclass (which holds runtime state) may optionally reference a
BaseModelConfig(which holds easily tunable settings) of type
ScriptableObject. For example the
BaseViewextends MonoBehaviour. For example, the
TurretViewsits on the
TurretPrefab. Of the MVC concerns, the View is the most closely connected with Unity.
- In theory, this can run outside of the MVC (such as a standalone demo/test scene for artists to preview). Complying with this is optional, but it is helpful to have some such scenes.
- This knows about the
Modelbut not the
View. For example, the
TurretControlleris called by the
TurretViewbut not vice versa. Some other MVC frameworks agree, but many do not. This is an experiment and has pros.
This custom MVC facilitates the roles of several team members.
Game Designer (Model Config)
The workflow is very smooth for a game designer to play the game and tweak tuning values. See images above. Some recommended steps...
- Create a new config
Unity -> Assets -> Create -> FTD...or duplicate an existing config.
- Select an existing config in
- Modify config values through
- Bonus: With light programming skills, the Game Designer can update the
BaseModelConfigsubclass. For example, set new C# defaults, validate values with OnValidate(). With more programming skills the Game Designer can add/remove values and integrate them into the related
BaseModelsubclass or other MVC concerns.
- The system supports liberal use of the helpful
Prefabconcept. Artists are free to update the visuals of the prefabs; models, particles, textures.
- Thanks to how the View is set up. As needed, a prefab can be run in its own standalone scene (outside of MVC). For example, a fictitious
MainCharacterPrefabcan run in the Main.unity scene with full functionality, yet in a standalone scene still be previewable (e.g. showing idle breathing animation. Previewing in a standalone scene aids rapid development.
- Bonus: With light programming skills, the Artist can update the
BaseModelConfigsubclass related to their related View. This aids meaningful dialog with other team members about programmatic variations to the art. For example, a fictitious
MainCharacterPrefabcould have one unchanging look from an FBX model and related texture, yet the character's hat color could be fed programmatically from the config.
Programmer (Model / Controller)
- Once the project is setup, adding new features is so easy. It's remarkable that once the worry about 'how' to add a new feature is removed (because of the prescriptive nature of MVC), adding features becomes a lighter and more playful experience for the programmers.
- The significant things that happen in the game (events) are so much more open, any system can react to them. An example is that once a
Turrettakes damage (a feature that required for a core mechanic), any other system (audio, particles, UI) can easily tap into that event to add polish. Furthermore, responsibility for such polish can be delegated effectively to the team.
- With a high-level overview of the project, the Programmer can maintain and update all code and assets more easily thanks to the separation of coding concerns and thoughtful separation of code from assets.
- Bonus: The MVC framework's documentation and consistent approach help onboard new junior and senior programmers to the team.
- Bonus: Want to add a new MVC element? Copy about 5 classes from
./Assets/Scripts/Runtime/RMC/Core/Templates/MVC/and to get started easily.
Here are some musing about MVC in general and about this custom MVC implementation.
Pros / Benefits
- Easy onboarding of new staff and easy discussion about projects with common workflows and shared vocabulary and design-patterns.
- Easier refactoring since the project is testable and since modifications never modify the whole project monolithically.
- The separation of coding concerns helps projects scale.
- Easy to have multiple views of the same data (e.g. in-game experience, overhead map of objectives, and character inventory)
- The design is prescriptive. The solution for adding a new feature or a whole new system is known. Having the codebase follow a consistent structure aids each member of the team to be effective.
Cons / Solutions
- Like any architecture, there is a learning curve to MVC.
- It takes 'many classes' (about 5) to add a new MVC Element (e.g.
Turret) to the game. To speed the process one can copy from
./Assets/Scripts/Runtime/RMC/Core/Templates/MVC/or copy the classes of an existing similar system.
- The custom MVC framework uses
UnityEventsalmost exclusively (vs C# events or other options). I started with this thinking it would help Game Designers and Artists to perform some non-programming tasks more easily (e.g. wire up a button to an existing method using the UnityEvent in the Unity Inspector). That is still possible, but I did not end up doing that at all. See more thoughts on C# Events vs UnityEvents.
Possible Future Features
- The custom MVC framework does not distinguish between Models with a view and those Models that don't have a view. Idea: Some systems treat them uniquely and solve the latter with a
ViewModel. That could have benefits.
- The custom MVC element lifecycle is stable but has limitations. For example, several Views that are instantiated on the same frame cannot access each other predictably. Due to this small-scale FTD, this was not an issue. Idea: Expose something like
Locator.OnViewAdded<V>().AddEventListener(l)so a View can wait properly (a frame?) for predictable access.
Locatorworks and properly prevents undue access to other concerns. However, adding an Inversion-Of-Control (IoC) system could give much more flexibility. However, IoC convolutes the lifecycle readability. It's more challenging to intuit when an injected reference lives and dies. See IoC for more.
- Using interfaces more liberally would decouple the contract between concerns (e.g. between
TurretController, a new
ITurretControllercould be added).
- The custom MVC has a concept of
GameEventsfor general messaging. This works really well. However, replacing it or adding to it with a Command Pattern would offer valuable features like queuing, reversing, and replaying Commands.
- How will this approach fit with the new Unity 2018 ECS Feature?
- How will this approach fit with the new Unity 2017 Timeline Feature?
The case AGAINST MVC with Unity
In the interest of full disclosure, many junior and experience programmers oppose using MVC for Unity.
- MVC is designed for 2D GUI of data-driven apps, and not for 3D games. It does not scale to the complexities of multimedia and 3D.
- MVC's View is theoretically not stateful with data. However, in Unity, the view (especially
MonoBehaviour) has its concerns spread into Model and Controller. So much of Unity's view's value is its data model (in particular
gameObject.transform) and its controller functionality (e.g. physics, collision, and more).
- MVC does not work well with Unity's traditional Entity-Component-System. This is similar to the last point. I'm not speaking about the new Unity 2018 ECS, but the classic ECS that is as old as Unity; aka use of
There are a few classic challenges with the unit-test testability of Unity Games.
Games are different from many other types of software because a good amount of the code relates to 2 areas; handling input and rendering UI (3d models, 2d sprites, audio, etc...). These 2 areas are notoriously hard to test.
Unity games rely heavily on UnityEngine.MonoBehaviour (i.e. The "GameObject"). At runtime, we depend on its execution model (e.g. Awake, Start, Update), which do not perform predictably in isolation during edit-time testing.
With this Custom MVC solution, we can isolate the more test-friendly concerns to help us test better. A beneficial workflow of test-driven-development (TDD) in FTD begins with testable Models.
The project includes Unit Testing
./Assets/Scripts/Tests/ which focuses on the
In production, its recommended that the team set a goal for code coverage (e.g. every public method of every subclass of
I created this package to remove SOME of the dependency on UnityEngine.GameObject. Now the
IWorldTransform and its
Position are used instead.
A larger, future refactor could further reduce dependencies on UnityEngine. However, striking a balance between ease-of-use (more UnityEngine) and testability (less UnityEngine) is recommended. Working with Unity instead of against it has relative advantages.
Interestingly, because I refactored to add the `RMC.Core.Proxies' after the game was already complete and working, a single commit b7b16c1a7b290121a28a2265dd02d310b33e47d6 is available to study impact on the codebase. Very fun. Check it out!
This project complies with RMC coding standards and includes templates at
./Assets/Scripts/Runtime/RMC/Core/Templates/ for use as new classes are created. It is recommended that each team develop their own policy and buy-in (or not) regarding coding standards. See more about coding standards.
- The flower-boxing is admittedly verbose. The spirit is to encourage consistent ordering of new features added over the lifetime of the codebase.
Thanks to the thoughtful and generous community around software (especially Unity) for contributing to free and open learning resources.
MVC / Unity
- MVC (and Model View Presenter)
- Gamasutra: MVC in Unity
- A MVC Pattern for Unity
- Unity With MVC
- C# Events vs UnityEvents
- Forget About MVC In Unity
- And many more...