3
\$\begingroup\$

Bear with me this will take some explaining...

I'm trying to design my game as close to Model-View-Controller design principles as possible. At least in and so far as I understand those principles.

I have two relevant classes in my View and Model respectively (with an irrelevant-in-this-case playerInput class acting as the controller)

BattleSerializable (My model that handles battle logic) BattleView (My view that handles battle display stuff)

BattleSerializable has a method called DoDamage that subtracts health from a player. BattleView has a method DoDamageView that calls the model's method (DoDamage) and then renders a number on the screen to indicate the amount of damage done.

So far so good.

But there's a friendly fire penalty! In the sense that if you do damage to an ally, you also take damage.

Ok, so now I can go one of three ways:

1) My BattleView can handle the friendly fire logic and call the DoDamage method twice in the case of a friendly fire occurrence, but this goes against what "View" is supposed to do. It doesn't make sense that BattleView should handle friendly fire logic. It should handle view logic only.

2) My BattleSerializable class can handle the friendly fire logic, but now I have to return a complex custom return object instead of a simple integer to handle all the state that changed. This seems needlessly complex or, at the very least, in-eloquent.

3) Instead of calling my model method from the view method, I could have the model run independently and, from the view, "poll" the Model every frame for changes and then render combat numbers if a change is detected. This seems inefficient and in-eloquent to me as well.

What is the preferred way to design this?

\$\endgroup\$
8
\$\begingroup\$

You are correct that it's not the View's job in an MVC architecture to implement any game mechanics like friendly fire.

But whether it's the controller's job or the model's job to implement game mechanics is a matter of debate.

There are basically two philosphies here:

Thin Model

In a thin model MVC architecture, the model is just a dumb data-structure and the game mechanics are implemented in the controller(s):

  • The view should just visualize what happens in the model and provide the UI through which the player gives commands.
  • The model should not implement game mechanics either. It should just be concerned with storing and maintaining the state of the game.
  • Implementing the actual game mechanics should be the job of the controller.

For example, when the user makes an input through the view like "My character A uses attack B on enemy C", that input is handled by the BattleController. The battle controller calculates the damage and calls the appropriate methods on the model, like DoDamage(enemyC, 10) and DoDamage(allyA, 5).

Fat Model

In a fat model MVC architecture, the model is smart and implements the game mechanics itself:

  • The view still visualizes what happens in the model and provides the UI.
  • The controller acts like a glue between view and model. It receives user input from the view and translates it into commands for the model.
  • The model accepts those commands, handles the game mechanics, modifies the game state and informs the view about it.

For example, the user does some clicks on the view, the controller interprets these clicks and realizes they mean: "Player wants character A to perform attack B on enemy C" and sends that command to the model by calling a method like model.doAttack(attackB, characterA, enemyC);.

The model then determines what that means. It looks up what attack B does, sees that it does 5 damage on the user and 10 damage on the target, calculates that damage, applies it to these entities, checks if they are still alive and then tells the view to visualize all that.


Which one you choose is up to you. Personally I would prefer to use a thin model with smarter controllers when I had a game with lots of complicated game mechanics but where all these mechanics end up interacting with all game entities in the same way (I would also call these controllers "Systems" and claim I am doing ECS). But if I had rather simple basic game mechanics but lots of gimmicky entities which twist these rules by using unique mechanics, I would prefer to put more logic in the model so the entities can handle their own logic through polymorphy.

Also keep in mind that design patterns are just suggestions how you can structure your game, not immutable laws. If you feel that diverting from them makes for a cleaner architecture in your specific case, by all means, divert from them.


My BattleSerializable class can handle the friendly fire logic, but now I have to return a complex custom return object instead of a simple integer to handle all the state that changed. This seems needlessly complex or, at the very least, in-eloquent.

The communication from the view to the model shouldn't happen through return values at all.

You don't know what model changes a player action will trigger. It is possible that it results in a whole cascade of changes. An AoE attack damages one enemy, poisons another, kills a third, the killed enemy explodes, the explosion kills off the first enemy, etc. etc.. How are you going to tell that story to the view? You would have to return a whole array of complex custom objects. But wait, what about model changes which are not triggered by the player? The enemy actions, for example? How do you communicate those to the view when the view wasn't the one who made the method call?

What you should do instead is have the model communicate with the view explicitly. There are different ways to do that:

  • Push-Event communication: When something happens in the model, the model calls methods from the view to inform it about these events.
  • Pull-Event communication: The model keeps a queue of events. The view empties that event queue and visualizes the actions it finds in it.
  • Polling: The view iterates the whole model and updates its visualization of the game state. This often requires that the view keeps a separate model so it can detect changes. This pattern is called Model - View - ViewModel.
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.