Sign in to follow this  
MaartenM

Grasping MVC (V - C separation)

Recommended Posts

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?

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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 -- Panda3D
Controller --+


Then it's no problem to raycast.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
In this case the card selection depends on how the card are rendered. So i would create a layer of abstraction using the Decorator Pattern.

Intead of the controller look for keyboard or mouse i would make a generic controller that interprets game commands...

class GenericController
{
protected:
void selectcard ( CARD card );
};

Now i would make a Decorator controller . This decorator would interpret the mouse click and send the generic game messages to the generic controller. This decorator controler should know the View but only he!

class 2DViewToGenericController
{
public:
2DViewToGenericController ( GenericController controller, 2DView view ) : _controller ( controller ), _view(view){}
protected:
void update()
{
if ( _view.IsCard(mouse.position) )
{
_controller.selectcard( _view.getCard(mouse.position) );
}
}
}

This model is expansable because you can make a NetworkControler that interprets TCP packets and talks to the GenericController.

"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?"

To me this solution depends how you are gonna make the animation tracking. If it´s like a timeline with commands just put the command to change the model at te end.

For example.. make a class that receives a Sprite object and change it´s position of a initial position to a final position in a linear way. At the en of the animation this class call a generic class ICommand ( Command Pattern ). Then you pass your concrete command to the animator class. This command can be a decorator to the generic controller and call the appropiate method.

Share this post


Link to post
Share on other sites
Another example that came to my mind.
If your game will have a server the GenericController example that i gave above can work with the NetworkController. Interpret the commands from the network as a decorator to the generic controller.

And the server does not need to render nothing. But you can use a view like: BroadCastSomethingToUsers. I don´t know, just a example. This view serialize the model and send to all users, or just one.

In a Chess game server the server has a NetworkController that move the pieces and the View can serialize the board and send to the other user.

If the View and the COntroller depends on each other you cannot unplug one withou unplug the another... So the system kind of loose some flexibility.

Share this post


Link to post
Share on other sites
Yes. The game loop could be something like..

Input->Update();
Network->Update();

foreach ( IController c in _Controllers )
{
c->Update();
}

foreach ( IView v in _Views )
{
v->Update();
}

And with this approach the controller class respet the open/close principle. We can add behavious to the system without altering classes, only adding classes. And others: Single Responsability ( NetworkController only interpret TCP packets, GenericController only change the model etc... ).

But this approach have one problem. Can be a problem or not depends.
Let´s imagine that the list _Controllers have the followings controllers registered:

<KeyboardandMouseController ( control my player ), HardLevelController ( analysis the model and take some action ), EasyLevelController ( samething )>

In the for loop my information ( the player ) will be updated before the computer players. When the computers player will be updated they will see the modified model by my input. They have a advantage on me!!

That´s why i purpose to use the Memento pattern on the model. It allow me to get a representation of the model before the updates of the models. Every controller see this representation, but modify the real model. This give a simulation of the controllers running in parallel. It´s kind of a transaction.

And a second factor is that the Memento can be used to facilitate the persistance step. Save and Load Games becomes very easy this way.

Share this post


Link to post
Share on other sites
As I say on all the MVC threads here: if the controller is performing the heavy lifting, then you're doing it wrong. Controllers are supposed to be thin and swappable just like Views are.

Traditionally the Controller is for input. The Model is for logic and internal representation. View is for output. The controller should be the thin layer that translates from external events (keypresses, networking, high-level AI) to model-changing operations. It can also notify Views (via a thin interface - it doesn't need to know anything about a View except it's View-ness) that the Model has changed and that it needs to consider updating itself.

Note that these are conceptual divides and not necessarily 3 totally different sets of classes. One object might well implement both the controller and a view interface (eg. for GUI widgets). You may also find that some aspect of the game crosses the M/V/C boundaries multiple times or gets spread across it. For example, AI for a computer player is likely to consist of a controller module that performs high-level AI (based on readings taken from the model) and perform actions on the model which go on to execute low-level AI.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this