Separating game logic, input and display

Started by
6 comments, last by jolid 13 years, 6 months ago
Hey guys, before I get going with my actual question, let me just put everything in context a bit. I'm making a board game with pieces that have various abilities, but the actual game mechanics are not very important. My main problems come with designing the relationships between the various subsystems of the program.

The most important issue is separating the actual game logic from the display. The display will be coded last depending on how much time I have, so I should be able to 'plug-in' any sort of display that I want. I searched around and saw that the Model View Controller pattern is a good way to achieve this and I have created a test program to test this design. It worked really well. I have been able to attach a graphical (SDL) view and a text view to my game simultaneously and see both updated simultaneously. I have also created two different input types (controllers) - a text input and a SDL input.

For reference, here is a basic class diagram of the classes that I am using:
2i6jfnl.png
And this is the original gamedev wiki article on MVC that got me started:
http://wiki.gamedev.net/index.php/Observer_pattern

Here is the test program that I am using, just to demonstrate the basic setup that I have going:
#include "Game.h"#include "TextDisplay.h"#include "GraphicDisplay.h"#include "GraphicController.h"#include "TextController.h"int main( int argc, char* args[] ){	// Create a new Game. Maybe this can even be done in the controller class	// using a TextSetup or GraphicSetup	Game* game = new Game;	// Create different displays	Display* textDisplay = new TextDisplay(game);	Display* graphicDisplay = new GraphicDisplay(game);	// Create controllers for the game	Controller* textController = new TextController(game);	Controller* graphicController = new GraphicController(game, dynamic_cast<GraphicDisplay*>(graphicDisplay));	// Attach the displays to the game	game->AttachDisplay(graphicDisplay);	game->AttachDisplay(textDisplay);	// Control the game with the controller	graphicController->Execute();	// textController->Execute();	delete textController;	delete textDisplay;	delete graphicDisplay;	delete game;	return 0;}


Now some subtle problems start creeping in. This is mostly due to the inherent differences between console input/output flow than frame-based, event driven graphic interfaces.

With the MVC model, all views are only updated when the model decides they need to. However, when using SDL, everything needs to be rendered every frame. To accomplish this, I have passed a reference to a GraphicDisplay to my GraphicController, so that it's Render() method can be called every frame. This is already starting to look dodgy, because the controller should ultimately not have to care about the view. Any suggestions on how I can incorporate a SDL input/rendering system into the MVC pattern?

My second problem is that of graphical input. The MVC pattern ultimately separates input (controller) from display (view). However, in the case of clicking on a piece on the board to select it / target another piece / etc, the graphics and the input are ultimately very tightly coupled. Who should be responsible for what? How do you separate the two? Is it even possible? I've thought the problem through but I haven't managed to arrive at an elegant solution.

Please feel free to ask if you need anything clarified. I'd love to see some input on how to tackle this design problem :)
Advertisement
If I'm reading your description correctly, you can separate the controller and view in the graphical display by having the display maintain itself until the model decides something needs to change. I'd image a board game could just continue showing the last frame, adjusting for input (eg: mouse movement, selection highlighting) -- though arguably that kind of behavior should be handled by the model.

Realistically, particularly for complex graphical environments, you'll need a "graphics model" of some kind to handle all the extra processing the visual representation needs. Much of that (if not all) can be decoupled from the game logic but it still has to happen somewhere. In other applications, I've included that code towards the 'view' end of MVC. The renderer (if you know what I mean) needs to keep track of ongoing animations or visual cues or whatever but my game routine doesn't care.

My way of figuring out how to handle generic input is to figure out what I need to do (using the application) and what my logic needs to know. I'll use chess as an example:

Playing the game in text, I say '3A to 4B'.
Playing the game visually, I click a piece and click the square to move.

My game loop needs to know piece or original location, and new location.

I have a one step (text) and two step (graphic) system that needs to be standardized for my game logic. So, I can add a "piece selection" step to the text display (making it two steps), where I send 'selected piece', receive possible locations, then send new location; or I leave it at one step (A to B, OK or NO) and leave the visual cues to that display.

The two step solution is probably the purest MVC solution, but I'd use whichever fit best. Don't get too hung up on an elegant solution if you can find one that makes sense for you.
Quote:before I get going with my actual question..

First - a better format for a post is: ask a question and then provide the background you think would be helpful to answer the question.
Quote:all views are only updated when the model decides they need to.

Only by the definition of MVC you've chosen. You mention The model-view-controller pattern without mentioning where you got that particular pattern and what benefit you expect to get from implementing it. From what I've read, the MVC pattern was originated to aid in server-client apps on the web.

In general, there's nothing wrong with the view requesting info from the model when it's told to render, even if it's every frame. I would suggest that you not get wrapped in the "purity" of the pattern unless it really causes problems.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

Quote:Original post by Buckeye
From what I've read, the MVC pattern was originated to aid in server-client apps on the web.

It was actually made to manage GUI applications.

Quote:In general, there's nothing wrong with the view requesting info from the model when it's told to render, even if it's every frame. I would suggest that you not get wrapped in the "purity" of the pattern unless it really causes problems.

That is actually the pure version. The view should ask the model for information so that it can render itself. Whether it does this by polling once per frame at render time or by cacheing new values when notified of updates by the model is an implementation detail. None of this requires the controller.

Hi guys, thanks a lot for your input. Sorry for only getting back a day or two later but I had an exam today and I had to try my best to bury this program from my mind :).

jolid, you mention only rendering the last frame until the game state changes (a piece is moved or whatnot). I thought about that, but ultimately I'd like to add some animations and effects, in which case you would need a constant rendering loop.

You also mention designing your input based on what the game itself needs to know. I think this is a very important point that I missed, despite it being seemingly obvious. I think I'm trying to over-engineer everything to be too general, too abstract and too clean. To handle every case that might pop up. I think it would be a better approach to just design exactly how the game should operate, and then make it do just that, instead of trying to build "building blocks" for future designs.

Buckeye, I always figured it's better to get a context before you dive into the meat and potatoes, but ok. I'm not trying to be hostile, but why do you rate it's better to give details first and context later? Once again, advice to just screw designing it "perfectly". Right.

Kylotan, you say that "polling once per frame at render time" does not require the controller, but in this case, it does. "Once per frame" means "in the SDL loop". The controller has the SDL loop to handle inputs and whatever. They are tied up.

All in all I think I'm just going to let it hang for a bit and try to not worry too much about the design. It's easy to get caught up in a single design and working all sorts of ways around problems in that design but sometimes it's better to just let it rest for a while and come back with a fresh perspective.

My solution in the meantime is to just treat the graphical display and controller as a single entity. It derives from Display and Controller and can be treated as each depending on context. So far it seems to be going ok. Now I'm stuck on designing a good input/event model but I don't want to go too far and create an abomination.

Thanks for the input :)
Quote:I'm not trying to be hostile, but why do you rate it's better to give details first and context later?

Lack of hostility noted. [wink] I've worked in various technical fields for many years and, primarily for technical discussions, starting with the subject of the discussion (not necessarily in "detail") rather than background leading up to an as-yet unknown subject is a straightforward way to establish the content. It helps people establish a mindset (in the good sense) to look through the material.

Posting code first without an indication of what's to follow results in the reader (probably) skipping the first part of the post to find out what're you talking about, and then going back to the code. Bass-ackwards.

General rules for good communication.
1. Tell 'em what you're going to tell 'em.
2. Tell 'em.
3. Tell 'em what you told 'em.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

Quote:Original post by AnthIste
Kylotan, you say that "polling once per frame at render time" does not require the controller, but in this case, it does. "Once per frame" means "in the SDL loop". The controller has the SDL loop to handle inputs and whatever. They are tied up.

That's your problem. :) It's not intrinsic to MVC. The controller is meant to handle your input and change the model accordingly. If you have it doing more than that, then you're not following the original intent of MVC. I would have the SDL loop feed events to the controller. I wouldn't have the controller own the main loop.
I think most MVC (for GUIs) explanations leave out the "you need to design around your input" bit. They rarely say you need to figure out what your internal logic needs to get from the user and there's your model (the logic + open-ended input). Ideally, that bit of code can be totally decoupled from the VC and tested separately.

Since I do a lot of web programming, I like to think of the Model as my application, the View as the page shown to the user, and the Controller the link or <--> between View<-Controller->Model. Again to use chess, the model should take in moves and spit out what happens (eg: move rook->rook takes pawn). The controller takes input (eg: "E5 to E2", or "Tile33821 to Tile43832"), changes it to what the model needs ('BR@E5 to E2'), receives the response ('BR@E5 takes WP@E2'), and finally changes that into whatever the view needs ('Black rook takes white pawn', 'Animate Tile33821 to 33,23,53;Tile33821->AttackPawn'). Your text view may simply echo the response and wait for input, your graphical version may have a castle stomping a screaming pawn into oblivion. The point is that those actions are totally separated from the logic. With a proper MVC, all you need is the input information to easily add new views OR logic. One can even be coded without the other: you use the controller to make sure the back and forth is "as expected."

Where lots of people seem to have trouble is that oftentimes the View requires more code than just GUI. Don't be afraid to add separate code to the View -- for instance, when the page loads 'IMPORTANT_MESSAGE_A' it should flash on top of the page, all others should appear normally. This will require a logic check, but also BELONGS in the View (or an overdesigned Controller). The graphics rendering loop SHOULD animate attacks and movement and such, even if it requires checking logic similar to the Model (that is, doing more or different things depending upon what the Model says). The Model shouldn't be doing any of your graphical work.

That all seems to be a longwinded way for me to recommend overengineering the Controller (!). If you write a solid Model that runs your game and an awesome View/interface (or 4) to show it off, then you can get a bit hacky with the translator/Controller to make them fit together. Your code is still organized and easy to debug* even if the design feels messy.

* - By using this checklist:

Correct data leaving the View? (No: View, Yes: Continue)
Correct data entering the Model? (No: Controller, Yes: Continue)
Correct data leaving the Model? (No: Model, Yes: Continue)
Correct data entering the View? (No: Controller, Yes: View)

You know exactly what piece of the code has the problem and can independently test any section.

This topic is closed to new replies.

Advertisement