0
votes

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 (MonoBehaviours) 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 MonoBehaviours, 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/MonoBehaviors. 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 MonoBehaviours.

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.

1

1 Answers

1
votes

1st MonoBehaviour is the place for your logic not your structure

For structure use ScriptableObject, scriptable object is quite handy think of it as a game object (mono behaviour) without a transform, no start, update, awake, etc. just data model and ... like any class you can add funcitons but nothing that Unity automatically calls.

For Example

[CreateAssetMenu(menuName = "Custom Objects/SimpleObject")]
public class SimpleObject : ScriptableObject
{
    public float myData;
    public GameObject someReference;
    public Vector3 someMoreData;
}

Now you can define your games 'model' seperate from your games logic 'controller?' ... a game wont perfectly fit into a MVC or MVVC paradigm but doesn't mean you cant improve the structure of your game with takaways from it.

There is a great talk on using ScriptableObjects like this and it does highlight there use in promoting testable, modular game structures. https://www.youtube.com/watch?v=raQ3iHhE_Kk

We (Heathen Engineering) also develop a framework built on these concepts ... but I wont self promote here, message me if you want more info on that.