Skip to main content
GameDev.net gamedev.net
🔒 Locked

Model View Controller question

Started by kirkd Aug 28, 2006 at 11:28 PM 8 replies 3.6k views
Original Post
kirkd
kirkd
I'm setting up my game clone using sets of MVC triads. For example, I have a Map class in which the model holds a text file of the game maze and does boundary checking, and the view holds the bitmap and is responsible for drawing to the screen. The controller sits between the two and essentially serves as the access point for the other two and has some logic inside. What I notice is that I seem to need to reproduce the model and view interfaces in the controller so that other classes can access them. Is this typical or do you usually expose the model and view to the outside so that you don't end up just piping a command from the controller to the view/model?? -Kirk edit: Continuing my example, I have an MVC triad for a World object. The WorldController is really the game engine and handles all the logic. It has a MapController object giving access to the maze map. What I find is that the MapController needs to supply access to View functions (such as LoadBitmap, DrawToTargetDC, etc.) and also needs to supply access to model functions (such as LoadMapFile, CheckMapPosition, etc.). Duplicating the interfaces just leads to piping commands: Controller::LoadMapFile("c:\\map") { m_Model->LoadMapFile("c:\\map"); } Controller::DrawToTargetDC(HDC TargetDC) { m_View->DrawToTargetDC(TargetDC); } It seems tedious and wasteful to duplicate the View and Model interfaces in the Controller, but it also seems to defeat the purpose to expose the Model and View objects to the outside. What am I missing??
JohnBolton
JohnBolton
A class should be able to access both the Controller and the View, since you manipulate the Model through the Controller and you access the Model's state through the View. I don't think it is unusual that in many cases the Controller and the View just act as intefaces to the Model, but it if is excessive then perhaps it indicates that the MVC framework is not useful.
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
Emmanuel Deloget
Emmanuel Deloget
A correct implemntation of the MCV framework have the following properties:

* the model knows about noone
* the view knows about the model
* the controler knows about the view and the model

The observer design pattern (more here) is applied as such:

* the controler observes the view
* the view observes the model

There is something wrong in your design - the map controller should not have to draw the world by itself (why does he do that? do you have a more concrete example?).

I see no problem in exposing both the view and the model to the outside. They are not private part of the controler, they are important classes in the project. Remove any of these three classes and your program miss a very important feature. The controler is not the God of your world - it's goal is to manage the user input and to react to it by modifying the world.

In a Windows program, there are some additional difficulties to see the separation line between the view and the conrtoler (mostly because the view also handles the user input). This is not the case in any typical game, where the separation is usually quite clear.

If you have further questions (I understand that I am not very clear), don't hesitate to ask.

Regards,
kirkd
kirkd
Thanks for the responses. My Controllers don't actually do any of the drawing themselves but rather I was passing the call to draw through them to the View. My example wasn't very clear. Here's a more complete example:

My game is a PacMan clone (surprise surprise) and I have the following primary objects:

Map Triad (Model, View, Controller) for the Maze.
Map Triad for the dot locations.
Sprite Triad for PacMan, each ghost, and fruit.
World Triad to collect all things together.

At this point, I'm only dealing with drawing the map and dots. This gives me the following specific classes. I've also put in some of their functionality and methods to clarify.

For the Maze and the Dots:
MapModel
-holds the actual maze. Each (x,y) position in the maze has a long value which corresponds to a particular wall segment. 1=the end of a wall, 2=a central section, 3=an upper left corner, etc.
-CheckPosition(X,Y) - returns a 1 if a wall is at position (x,y), 0 otherwise
-GetPosition(X,Y) - returns the actual value at position (x,y) Used by the view to figure out which segment to draw where.


MapView
-holds a reference to the model
-HBITMAP m_WallBitmap - holds a bitmap containing the graphics for the maze walls.
-DrawToTargetDC(HDC TargetDC) - parses through the model and draws to the target DC the appropriate wall segment from the wall bitmap

MapController
-holds references to the model and view, and connects them


For PacMan, each Ghost, and fruit:
SpriteModel
-contains the location, speed, and state of the sprite. State for ghosts is blue or not blue.

SpriteView
-contains a reference to the SpriteModel
-contains the bitmap for the sprite
-contains an animation sequence for the sprite and manages the animation sequence internally
-determines which section of the bitmap to draw based on the animation sequence and the state of the sprite obtained from the model
-DrawToTargetDC(HDC TargetDC) - draws the sprite at its current location (determined from the model) to the target DC.

SpriteController
-handles requests for the sprite from input or other classes. Delegates to either the Model or the View


WorldModel
-holds the score, the number of time steps, ghost values, rate of ghost release from the pen, duration of powerups, etc.
-very simple

WorldView
-holds the BackBuffer DC and ultimate BitBlts the backbuffer to the screen. this BackBuffer DC is used as the TargetDC for other views.
-Draws the score, number of lives
-very simple

WorldController
-contains references to all the other controllers - MazeController, DotController, all the SpriteControllers
-takes any input (joystick or keyboard) and passes it to the appropriate controller impacted by that input.
-It effectively serves as my GameEngine.
-Update() - this function starts the game update loop and tells other controllers what to do. For example, tell the sprites to erase themselves, tell the sprites to update their locations, tell the sprite to redraw.



So this is where my situation arises. Let's say Windows issued the WM_PAINT command. The Update() method of my WorldController is called. The WorldController now needs to tell the sprites to erase, update, and redraw. BUT, the WorldController only talks to the other Controllers. For example, the SpriteView has a DrawToTargetDC(HDC TargetDC) method that needs to be called to draw the sprite. Since WorldController only talks to the SpriteController, I end up with a SpriteController::DrawToTargetDC(HDC TargetDC) that just passes the call to the View: m_View->DrawToTargetDC(HDC TargetDC).

Likewise, during initialization of the game, I need to call MapModel::LoadMap(string filename). But, since everything outside the Map triad talks to the Controller, I end up with

MapController::LoadMap(string filename)
{ m_Model->LoadMap(string filename); }

It seems that I'm tying the controller to both the specific model and view that I'm using, and them violates the point of the pattern - to decouple the classes.

I hope that clarifies a bit, and sorry for the length of the post. 8^)

-Kirk
kirkd
kirkd
Slid off the end. I thought I'd bump it back up. 8^)
JohnBolton
JohnBolton
It seems to me that you are mixing up the purposes of the controller and view classes. Why does the controller class get the WM_PAINT? The view class should get it. It seems to me the the view class should be responsible for telling the sprites to draw themselves, not the controller.

Also, you should not make the controller the only interface. The view should not be accessed through the controller. If you look at any MVC diagram you will see that only the model is hidden. The user accesses the model though both the controller and the view.

I think you already clear on this, but just in case -- remember that the sprite on the screen is not the model. It is only the view's interpretation of the model. The controller manipulates the model and the view displays the model. You could have another view that doesn't use sprites, and having the second view should not affect in any way the first view, the controller, or the model.
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
kirkd
kirkd
Thanks for the response!

Quote:

you should not make the controller the only interface.


I think this line makes a big difference in my design. I was making everything go through the controller. And, yes, the view and model are completely different entities. I'm using the model strictly to hold details and the view strictly to visualize those details.

Using the WorldController as my Uber-Controller seems to be detrimental at this point. I can get the pieces working very nicely, but the code is ugly. I will likely back off this idea.

One of the issues that I feel I'm facing - maybe by my own design - is that I have multiple models, single view. I have sprite models for PacMan, Ghosts, PowerUps, and Fruit. I have Map Models for the dots and the maze itself. Then I have the World Model which has only basic information like score, number of lives, etc. Ultimately, the target view is the screen, so I really have one view target, but I was trying to delegate drawing independently to Sprite Views, Map Views, and World Views. Finding a design to accomodate this has been a challenge for me. Single model multiple view makes much more sense.

One last question - should the View manipulate the Model directly, or does it merely pull data from the model during visualization? Obviously the Controller has the ability to manipulate the model.

Thanks again!!

-Kirk
kirkd
kirkd
Slid to page 3. Bumped it up again.

kirkd
kirkd
Quote:

You potentially can decompose your main view to several different views - each with their own controller/presenter. In fact, this can make a lot of sense if you have a HUD or an overhead map showing on the screen. Partitioning the views can definitely help. (E.g. BirdsEyeView, PerspectiveView, PersonalStatsView, etc.)


Yes, this is what I've done. I have SpriteViews, MapViews, and a WorldView. The WorldView holds the Backbuffer which is ultimately BitBlt-ed to the screen. In each other view, I set a TargetDC to be this BackBuffer so that when they Draw(), they draw to the Back Buffer. Then the WorldView decorates it a little and Blts it to the screen.


Quote:

When any class starts to become a 'master class' that is a definite code smell. There is nothing about the pattern that insists that there is to be only one controller.


I'm beginning to think that I need to put in a GameEngine class that is essentially a Mediator Pattern. This will define the game loop and delegate out to the various other classes as needed in order to follow my standard game loop:

Erase sprites
Update sprite positions
Check for collisions
Make changes to sprite states (if needed from collisions)
Draw sprites

This mediator would then act as the primary controller but effectively use the other classes to get the work done.

Thanks for the response!

-Kirk

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.