I'm a freshman in college going for my computer science degree... I've programmed plenty the last several years but just lately I've been getting more into theoretical ideas about organizing code, design patterns, differences in languages, etc.
I have a Java class, so I've dropped my C++ research/development and moved into Java and JOGL (Java OpenGL). It's wonderful! But that's beside the point.
I want to make a small role-playing game, but this question really applies to any sort of game. How do you organize the game objects in a way that is structured, like the Model-View-Controller pattern? It looks to be an amazing pattern, very widely used and makes a lot of sense, but I'm having trouble figuring out how to implement it.
For instance, I need to keep track of a GL object for drawing to the screen. I have to have classes that implement MouseListener, MouseMotionListener, MouseWheelListener, and KeyListener (or one class, an all-in-one input manager). And I have to put my game data somewhere where all these different classes can access and modify it; if someone presses a button on the keyboard, the input managing class needs to somehow perform the action that the key is mapped to; when a frame needs to be drawn, the graphics class needs to find a way to loop through all the different 'things' and draw them all.
And my biggest issue, the GUI; where does it tie into it all? It's something like the input, but not quite, and it needs to both set and get pieces of data from the actual game simulation... And complicating it even MORE is if I decide to try and add networking, which (similar to the GUI) also needs to have access to a lot of the data for modifying and reading...
Oh, I'm just all confused. I don't know how to make all this work together in an object-oriented fashion... It's easy enough writing things that clearly fit the patterns, but when you have tons of things happening all tied to one game loop, modifying each other and the game data and so on, ... I don't even know any more. Maybe I'm just making this a bigger deal than it actually is.
Has anyone else felt this way? Please offer some clarity to my situation so I can spend less time worrying and not knowing where to start!
-Ricket
Edit: Found a nice diagram that might help me figure this all out... Source: (beware, PS file!) http://www.tucs.fi/publications/attachment.php?fname=TR553.ps.gz
http://img10.imageshack.us/img10/6278/mvcdiagramgamesbl5.png
Edit2: I also like this guy's explanation of how he planned his MVC game: http://interactivesection.wordpress.com/2007/11/19/dum-de-dum-drum-my-first-mvc-game-development/
Edit3: Another great article! http://dewitters.koonsolo.com/gamemvc.html
I feel with you I remember when I first discovered MVC I tried to cram everything into it. I did indeed make a game that utilized MVC pattern. What I have found later though was that what I did was overkill. I tried to fit pretty much every single class I made into one category in MVC.
What I suggest is to read "Design Patterns" by the gang of four. There are a lot of useful patterns besides MVC. Sometimes it doesn't make any sense to use MVC at all. Especially for games I am not sure if MVC is such a good idea. The reason being that you don't want to display a game object in many different ways (views), but you want to reuse a drawing code for many different types of game objects.
For my own 2D game engine I used the strategy pattern quite actively. The game objects, like the player and the monsters I called a Sprite. I let the drawing of the sprite be handled by a strategy pattern. That is when I called sprite.draw() I would do something like this:
The benefit of this approach is that you can share a view object between several sprites. Because typically there will be a lot of e.g. monsters which will look the same but which will be a different positions and possibly behave different.
So behavior I would also use a strategy pattern which would be a object which contains code describing behavior. That way I can apply the same behavior to several monsters at different location. So each frame I would call an update() function to update position orientation and what monster does.
There are loads of variations of this. In my current implementation I have even separated out currentPosition, speed, orientation and advance() into a separate object called MotionState. This is so I can build a search trees of possible positions and orientations when doing path searching algorithms. Then I don't want to carry with me information about how to behave each update or how sprite should be drawn.
All of your listeners and handlers need to go inside the Controller class, state of the objects on screen (e.g. position, color, etc.) should be a part of your Model classes and whatever code that is drawing things on screen will be part of the View.
You're getting along there. basically, ask yourself the question "which code would change if I had to change some part of the program?"
If it would change the way it looks without changing basic data, then it's in the view. If it is data that could be viewed in many ways, it's the model. And if it's how you play, then it's the control.
So if it's whether you draw an "axe" with two blades or one, it's view. If it's how many hit points damage you inflict with an axe, it's model. And if it's whether you swing the axe by typing "s" or by right clicking, it's control.
The MVC concept of centralizing user interaction logic is a good model for game development.
I've done a little work with Flash game development. Here is an article about object pools in Flash. The concept is cross-platform and may give you some ideas.
You're right to be concerned with all the stuff going on at one time. Depending on your game design, your game loop can have a lot to deal with. This is where you'll learn all the dirty optimization tricks, often the hard way :)
There are many ways to organize your code- one option might be to write a GameManager class as a Singleton. All game objects tie back to it for management and user interaction. The GameManager handles all user input and dispatches messages to its object pool. You can use interfaces to define common communication patterns between game objects and the GameManager.
As far as performance optimization goes, threading is very powerful. Asynchronous operation can ensure that you're not wasting those precious cycles.
My way of thinking of MVC is as MDUC
Model
Display
User-input Controller
The model contains the domain model objects
The display shows the current state and behaviour of the domain model objects on-screen.
The user-input controller handles all the user inputs.
It's exactly the same pattern, but the names are just ever so slightly more descriptive, so I find what responsibilities each part of the pattern has is clearer, and so the meaning of the pattern is more memorable.
Once you see that you are splitting data and model operations from displaying, from the user's inputs, it's easier to see where to group what in your own code.
It might help you to think of the Model as a kind of game API. What would your game be reduced to if there were no UI at all for the game ordained from the beginning? You mention that what you have in mind is an RPG, so in this case you can imagine having the player character, his/her inventory, spells, abilities, NPCs, and even things like the map and combat rules all being part of the model. It is like the rules and pieces of Monopoly without the specifics of how the final game displays that or how the user is going to interact with it. It is like Quake as an abstract set of 3D objects moving through a level with things like intersection and collision calculated but no rendering, shadows, or sound effects.
By putting all of those into the model the game itself is now UI agnostic. It could be hooked to an ASCII text interface like Rogue games have, or a command line UI akin to Zork, or a web based, or 3D UI. Some of those UIs might be a terrible fit depending upon the game mechanics, but they would all be possible.
The View layer is the UI dependent layer. It reflects the specific choice of UI you went with and will be very much dedicated to that technology. It might be responsible for reading the state of the model and drawing it in 3D, ASCII, or images and HTML for a web page. It is also responsible for displaying any control mechanisms the player needs to use to interact with the game.
The Controller layer is the glue between the two. It should never have any of the actual game logic in it, nor should it be responsible for driving the View layer. Instead it should translate actions taken in the View layer (clicking on buttons, clicking on areas of the screen, joystick actions, whatever) into actions taken on the model. For example, dropping an item, attacking an NPC, whatever. It is also responsible for gathering up data and doing any conversion or processing to make it easier for the View layer to display it.
Now, the way I've described it above is as though there is a very distinct event sequence driving the game that is probably only really appropriate for a web game. That's because that's what I've spent my time on lately. In a game which is not driven by a user's request and a server's response like the web (e.g. a game running on the user's machine) you would probably want to make sure that the Model layer implemented the Observer pattern well. For example, if actions take place in the Model because time is passing then you might not want to have the View layer constantly polling the Model for updates. Instead by using the Observer pattern the Model could notify any observers of changes to Model objects as they happen. That could in turn be used to prompt immediate update to the View to reflect the change.
Then if 60 seconds passing resulted in some repairs happening for the player's base, the base could effect the repairs and immediately notify any Observers attached to it that the base has updated. The View could be attached as an Observer and note that it needs to re-display the base because its state has changed. The notification itself might have included enough information to update the View or it might have to turn around and consult the model in order to update, but the result will be the same.