If this is the wrong forum for this question, please direct me to the correct one.
I'm learning Unity, and I've been struggling to follow an overall separation-of-concerns architecture pattern, like MVC, and to make my game unit testable. I've been trying to follow an MVC-ish pattern, where my Unity objects are my views and my game logic is in my model classes.
For instance, for my player character, I consider the Unity object my "view", and I have PlayerCharacterScript
and a PlayerMovementScript
attached to it. They are both Mono-Behaviour
-derived classes which implement Unity-specific behavior, such as determining where the user clicked to move and playing animation when the user takes damage.
Then I have a Player
class (my "model"), which has the game logic, such as causing the player to die when he falls below 0 health. When something happens to the player that requires a visual response, the Player
class calls an Action
, such as OnDeath
, which the PlayerCharacterScript
is listening for. Then PlayerCharacterScript
plays the death animation in response.
In theory this works well and the model classes are easily unit testable. My problem is that in practice it's becoming very annoying to synchronize the models and views (MonoBehaviour
s) getting added to the scene and sending messages back and forth. For instance, if I drag a Goblin
prefab into my scene in the Unity Editor, then when the game starts, that goblin's MonoBehaviour
needs to create its corresponding Goblin
model, add that model to the "scene manager" class, and also set that Goblin
object as the MonoBehaviour
's model.
However, within the game logic of the "scene manager" class, I want to create a goblin in the scene in response to some action. Since that's game logic, it'll be part of a model class (not a MonoBehaviour
). In that situation, I create the model first, and then I have to create the prefab with its associated MonoBehaviour
s, add it to the scene, and register that model with the MonoBehaviour
.
Now I'm stuck with situations where sometimes the MonoBehaviour
creates the model, and sometimes the model creates its prefab/MonoBehavior
s. I also have to remember that every time I create any sort of new game object prefab, I have to put some boilerplate code in it somewhere so that the Unity object creates its model. Another problem is that my models can't ever create new objects that are derived from MonoBehaviour
if they need to have their Awake
or Start
methods called, because that doesn't work during unit tests.
Pursuing this kind of model/view architecture seems like it's becoming a lot more trouble than it's worth, and it would be easier to just put everything, game logic included, in MonoBehaviour
s.
I've looked around for advice on this topic and all I've found are a few posts talking about how to make game logic unit testable, but none of them address the problem of how much of a jumbled mess the code becomes if the platform isn't designed with the separation of display logic and game logic in mind, as Unity appears not to be.
I'd love to hear from any experienced Unity developers about whether I should keep going with this separation of game logic from Unity logic, or whether it's ultimately not worth it.