Grasping MVC (V - C separation)

Started by
13 comments, last by Kylotan 14 years, 10 months ago
Hi, Found this interesting article through gamedev: http://www.mine-control.com/zack/patterns/gamepatterns.html It has the following bit I'd like to ask you something about: "Views are invisible to Controllers and vice-versa." I'm making a card game to learn Panda3D (and Python), and wanted to adopt strict MVC this time. I have the player's view, which renders my cards. I wanted to put all the Panda3D code in that View. Of course I use things like rays in that view that allow me to select objects with the mouse (usually, cards, or for instance, a hand to deal or sort cards). Anyway, how do I know *which* card has been selected by that ray, if I adopt strict MVC? Am I missing somethign here, should some of the selectiond etection go into the controller.. how would you guys implement something like that? I like this model better: http://gamedev.nealen.net/intern/docs/html/Image211.gif But I still have a problem with this? The view can publish (using an observer model or just an event queue) that the user has attempted to select a card. The controller can then decide if that selection will be stored int he model, which in turn will publish a render event back to the view (a glowing effect around the selected card) But again, which card? How can I know what card was selected? How do you do user interaction in 3D like this, using an MVC model?
Advertisement
Quote:Original post by MaartenM

Anyway, how do I know *which* card has been selected by that ray, if I adopt strict MVC?


P: Doctor, when I hit my hand with a hammer, it hurts
D: Stop hitting your hand with hammer

Quote:Am I missing somethign here, should some of the selectiond etection go into the controller.. how would you guys implement something like that?


Apparently, MVC is not ideal choice, and you should avoid strict implementation, or map the engine to strict MVC by providing classes which expose the functionality you need in strict MVC compliant manner.

What are your goals?
- To mess with patterns
- To actually get something done

MVC in general has proven problematic since it requires abstractions which are frequently cumbersome in practice. Java's Swing and AWT, for example, blend the view and controller, despite being MVC.
Well, my goal really is to mess with patterns :)

I just see it as a personal failure that I can't put the theory of the mentioned article and that diagram into practice.

I was at work when writing the question and possibly a bit distracted.

Here's what I'd wanna do, it's very simple for most of you.

Model : Game data with cards, a deck, scores, and things like active player, selected card, game status
Controller: Game logic: assessment of the current game status, takes the player's turns
Views:
All views talk to the Model and the Controller.
Player view: uses Panda3D for rendering to the main window. Continuously renders the model (breathing card players, etc..), and also responds to Model Change Events that are put on the event queue.
AI view: stores the things an AI can see and remember of the game. I would also store an AI's memory and assumptions here - possibly polluted for AI effects. Is artificially slowed down so the AI is less quick to respond to the changed situations.
Score view: etc..
Small overview view: etc..


Now, my question is, if you'd use a design like this, and I really do want to be able to somehow make this design model work, what is the best way to use f.i. raycasting to allow a user to select a card using the mouse? It's easy to select a graphical entity, but how do I keep track of which graphical entities correspond with which model data? Is there usually a database between View and Model that holds this data, a database which is heavily dependent on the Render Engine used?
Quote:Original post by MaartenM

Now, my question is, if you'd use a design like this, and I really do want to be able to somehow make this design model work, what is the best way to use f.i. raycasting to allow a user to select a card using the mouse? It's easy to select a graphical entity, but how do I keep track of which graphical entities correspond with which model data? Is there usually a database between View and Model that holds this data, a database which is heavily dependent on the Render Engine used?


Complexity has no upper bound. You can complicate things needlessly. You can even use a database cluster built on top of Amazon cloud.

How to model it?
class CardModel {  // returns currently selected card  Card getSelectedCard();};


The rest is implementation detail. Don't get too hung up on terminology. Why not make Panda engine the common base of all 3 aspects. Something like:
Model      --+View       --+-- uses -- Panda3DController --+


Then it's no problem to raycast.
Here's my take on it.

Since you should be able to swap out views as needed, say you have a view that renders cards in 2D and one that renders cards in 3D and just for fun you have a view that renders out cards to a console window using ncurses.

If you put the card selection logic in the model then the model would have to be aware of how the view was positioning the cards on the screen. Because this could change depending on the view, putting selection logic here would tightly couple the model to how the views are implemented

If you put the card selection logic in a controller then the controller would have to be aware of how the view was positioning the cards on the screen. Likewise, the controller like the model would have to be tightly coupled to how the views are implemented

If you put the card selection logic in the view that is rendering the cards then that view only needs to be aware of how it renders cards. A 3D view would catch a mouse click and perform raycasting, a 2D view would catch a mouse click and perform a bounds test, a console view would do whatever it needed to do to determine if a card was selected. These views could export a CardSelected event and pass something like a CardID to those observers that subscribe to the CardSelected event.

Necessarily, each view would need to have a way to associate CardIDs from the model to on-screen geometry.

Hope this helps.
The controller class interprets the input information that you have and translates them to models modification.

if ( A button is pressed )
{
player.position ( 0 )
}

That´s the only thing the controller class do.

The model classes only have its methods that change their states and knows how to persist its information ( for a OO approach to persistable object see the Memento Pattern ).

On the other side you have the view classes. The view uses the observer pattern to know if a model changed it´s state. In a real time game this can be ignored if you imagine that in every frame every object can change its states.

And in the mais game class you configure the controllers that will be used and the views. Ideally use some kind of config file, script, something that can be changed.

In this way you can change the KeyboardAndMouseController for something like ReplayController on the config file and now the game can replay some action.

How you are gonna implement this can vary. A list of controllers in the main game class, each model have a pointer to it´s controller and view etc...

The main point is...
Controller interpret the input and change the model
The model controls the persistable information. Save and then load the model should return to the exact same point.
View interpret the model and render it.

The model should not know the concrete type that is controlling it and should not know the concrete class that is rendering it. This way you can change the configuration to change the game behaviour.
Aaron and xunil, you have different approaches.

It seems so odd to make the controller aware of what "input" really is like.
Aaron's approach of publishing input events through the view seems more naturally inclined, but then again, using controllers to drive input has several advantages like xunil showed.

Also, the game is turn-based, the model should not be rendered as it is real-time. The *change events* should be rendered (card floating from hand to table..), and only at the end of that render, the model should be actually changed (from now on, card is no longer drawn in hands). This will ensure that the AI's views are only updated when the new card is lying on the table (the game uses a combination of AI and human players, and speed is important factor in scoring).
But I think the Memento pattern can be used for that easily?

I have a lot to think about. Game design is very intense for the brain.
Thanks.
Quote:Original post by MaartenM

I like this model better:
http://gamedev.nealen.net/intern/docs/html/Image211.gif

But again, which card? How can I know what card was selected?
How do you do user interaction in 3D like this, using an MVC model?


Notice the dotted line going from view to controller it says user gestures. This doesn't mean the view tells the controller "the user stuck his tongue out at me." It is user interacted with card X. How to interpret that interaction falls to the controller\model.

Though Xunil_RJ is also correct keyboard input such as push the left arrow needs little to no translation since it is the controller's job to interpret users input into state update.
Quote:Original post by MaartenM
Aaron and xunil, you have different approaches.

It seems so odd to make the controller aware of what "input" really is like.
Aaron's approach of publishing input events through the view seems more naturally inclined, but then again, using controllers to drive input has several advantages like xunil showed.


I'm a big fan of putting all user interaction events into views. I think we have reached a consensus that rendering/graphics is a view. Sound output can also be a view, such that you could swap out different sound "renderers".

Moreover, I consider user input to be part of user interaction and thusly a view. I have a keyboard view of which controllers observe users' keyboard gestures and a mouse view where controllers can observe users' mouse gestures. Even more abstractly, I have a clock view to which controllers can subscribe. It is as if controllers are watching a clock to know when to act. I can see how a network view would let controllers observe that network traffic has arrived and is ready to be processed, or should the model be changed, ready to be transmitted out.

Reading input directly from a controller leaves out the user gesture link shown in
I've been thinking about this problem the last few days, because I'm working on an application where I need to be able to plug in a view, and unplug it and plug another one, with as minimal fuss as possible. Here's what I've come up with, and hopefully others will critique it for both you and me.

First need a simple way to register to and fire events. This simplest way is to make events objects, unless your language supports events directly (I dunno much about python).

So we have:
Model - Doesn't know about controller or view. Handles data manipulation and logic which is independent of software application.
View - Does not know about controller; Knows about model... how else would it render what it needs to render? (this can be network, ai, etc.). Knows NOT about controller.
Controller - Does not know about view; Knows about model... of course so it can do software application logic, and handle input, followed by model manipulation, followed by view updating. Now in this model, view doesn't actually get update notification from model, the controller, which might update the model 5 different ways, tells the view when it should update, since all system logic is in the controller! Oh but way... "and handle input"? Where does this come from? And...
VC Event collection - View can add listener to and fire events here. So can controller. This is the controller's input source. Both view and controller obviously know about events, but this is the glue which also keeps them separated and independent, so plugging and unplugging is natural.

So we select a card (view MUST know how to select a card because it is very, very view dependent). Fires an event called CardSelectedEvent or whatever, passing parameters as needed. Controller (could be more than 1!) has registered to this event, and does system processing as needed, manipulating model if needed, and telling the view to update, if needed. Voila. Separation and very easy to maintain. It is clear the responsibility of each part of this system, and easy to change functionality in one place without really bad domino effect.

[Edited by - popsoftheyear on June 3, 2009 3:34:57 PM]

This topic is closed to new replies.

Advertisement