Sign in to follow this  
Replicon

Let's talk architecture for a minute...

Recommended Posts

Replicon    306
When you guys are designing a new game from scratch, how do you go about architecting the thing? Just to make some clarifications: I'm not really interested in answers like "well, I have my graphics manager, my input manager, my sound manager and my FooBar manager as Singletons...." I'm talking more about game object hierarchy/workflow design (and not how they interface with the hardware). So let's just say you have your favourite game loop setup:
while(!done) {
    if(it's time to update) {
        updateState();
    }
    render(); // or renderInterpolate(percentWithinState) or whatever..
}
So it's easy to visualize how stuff is setup, more or less. You have some collection of game objects, and those get displayed by render(). updateState would do all kinds of neat stuff (collision detection, reading input, updating player characters, doing the AI dance and updating NPC's, carrying forwards any animation that's under way, and so on). That's all fine and dandy, but what I'm trying to wrap my head around is a practical (read: performant and scalable) way to handle all the 'triggering' that happens in the game. Screen shifts, and all that stuff. For instance, in your kung fu fighting game, you won't just be having two characters fight. Once one character dies, a big congratulatory animation will be displayed, and then you get to ...choose your next oponent or something. Or perhaps your RPG character walks through a door and enters the next room. Next room has to load, and your character's position has to reset. Or maybe your RPG guy hits one of those random fights. All these things trigger big changes (in-game context-switches, if you will). Are there some really good design patterns meant for dealing with this stuff? What I've done in the past (and I really haven't written any very complex games) was to have a 'driver' class for each scene type. When the game starts up, I would load the 'Menu' driver, which in turn would load the background, some foreground movement, and the text menu. It would also have its own 'read input' function to handle keyboard bindings. Then, once you select a menu option, it would unload the current driver class and load the appropriate driver class for the next game state (say 'single player game', with some number of opponents or whatever). Although this was pretty nice, and prevented me from having to do that really stupid thing I see in a lot of code where there's a separate game loop hardcoded for each scene type, there are some problems with this approach. For one, it doesn't really scale, but that's easily fixed by making a lot of its functionality more data-driven. The other problem is that it was stateless. There was no concept of nesting (which would come in handy in an RPG where you get thrown into random fight scenes, and then end up back on your merry way). Like, say you are on the world map, from where you enter a dungeon, in which you enter a fight. It's not guaranteed that you can trace your way back once those sub-events finish, without some hackery. Anyway, I've been rambling, so now it's your turn to ramble. What are your favourite design patterns/approaches for this general problem, and what have you learned when writing games that are more complex than Tetris, which consists of a title screen and the game itself?

Share this post


Link to post
Share on other sites
Alpha_ProgDes    6934
you know what? i don't have a clue to the answer to your problem. but! i'm gonna rate you up anyway because this is an excellent question and one i would like to get answers to myself.

cheers! (++OP)

Share this post


Link to post
Share on other sites
Incommunicado    126
Hi!

I am in a hurry at the moment but I really like your question since it bothered me hell of a long time as well. But here is something that might fit in:
http://www.gamasutra.com/features/20050414/rouwe_01.shtml

This is a really nice approach to the overall layout of a gameengine.

CU
Incommunicado

Share this post


Link to post
Share on other sites
iNsAn1tY    476
Quote:
Original post by Alpha_ProgDes
you know what? i don't have a clue to the answer to your problem. but! i'm gonna rate you up anyway because this is an excellent question and one i would like to get answers to myself.

cheers! (++OP)

I'll be very interested in the answers to this too.

Share this post


Link to post
Share on other sites
Zidane    152
Its a very good question and there are no perfect ways of doing.

In the RPG I am writing I plan to do it via something similar to your Driver class. I think driver is misleading so I use the term "Scene". In simple design terms (I am still planning this out by the way) each type of mode in a game is a inherited from the scene base class. Now there is a scene manager class with which you register a scene with. The scene manager class handles the management of these scene objects.

I have scene classes which handle loading rooms, battle scenes, cut scenes and even the pause menu is its seperate scene.

The scene manager class allows you to execute a scene and will automatically hand control back to the scene which executed it. The problem with my approach, which is similar to your problem, is the storing of state throughout different scenes. To handle this I have made the storing of any information not linked specifically to a single scene completly independent of the scene structure. Singletons once again prove there use in this problem, I have a singleton object which is the golbal registar of any application states. It contains methods like GetXXX(). The values are stored in a collection of associative arrays.

This does mean that when a Scene executes another scene it has to reload all the global data it is using, by querying the state singleton.

So in summary:
1) Scenes are a collection of distinct types of parts of the game (battles, rooms, pause menu)
2)A scene manager class allows the scene to be executed and a linked list format allows for the scenes to be linked together (ie a battle can start in a room and you can pause the battle and when you unpause and finish the battle you will be in the room)
3)A state singleton is used to store all global information
4)After a scene loads another scene it has to reload any global information it uses

Now I know this isnt the best way, so Im interested about how up people approach it.

Share this post


Link to post
Share on other sites
James Trotter    432
Quote:
Original post by Replicon
When you guys are designing a new game from scratch, how do you go about architecting the thing?

Just to make some clarifications:

I'm not really interested in answers like "well, I have my graphics manager, my input manager, my sound manager and my FooBar manager as Singletons...." I'm talking more about game object hierarchy/workflow design (and not how they interface with the hardware).

So let's just say you have your favourite game loop setup:


while(!done) {
if(it's time to update) {
updateState();
}
render(); // or renderInterpolate(percentWithinState) or whatever..
}


So it's easy to visualize how stuff is setup, more or less. You have some collection of game objects, and those get displayed by render(). updateState would do all kinds of neat stuff (collision detection, reading input, updating player characters, doing the AI dance and updating NPC's, carrying forwards any animation that's under way, and so on).

That's all fine and dandy, but what I'm trying to wrap my head around is a practical (read: performant and scalable) way to handle all the 'triggering' that happens in the game. Screen shifts, and all that stuff. For instance, in your kung fu fighting game, you won't just be having two characters fight. Once one character dies, a big congratulatory animation will be displayed, and then you get to ...choose your next oponent or something. Or perhaps your RPG character walks through a door and enters the next room. Next room has to load, and your character's position has to reset. Or maybe your RPG guy hits one of those random fights.

All these things trigger big changes (in-game context-switches, if you will). Are there some really good design patterns meant for dealing with this stuff? What I've done in the past (and I really haven't written any very complex games) was to have a 'driver' class for each scene type. When the game starts up, I would load the 'Menu' driver, which in turn would load the background, some foreground movement, and the text menu. It would also have its own 'read input' function to handle keyboard bindings.

Then, once you select a menu option, it would unload the current driver class and load the appropriate driver class for the next game state (say 'single player game', with some number of opponents or whatever).


I noticed an article on game states (http://tonyandpaige.com/tutorials/game1.html) in another thread about game engine design (http://www.gamedev.net/community/forums/topic.asp?topic_id=388490). The game states described in the article sound related to your 'driver'.
I've implemented these game states (a little different from the ones in the article, though) so that I can push onto/pop off a stack in the engine kernel whenever the state changes.

Quote:

Although this was pretty nice, and prevented me from having to do that really stupid thing I see in a lot of code where there's a separate game loop hardcoded for each scene type, there are some problems with this approach.


Well, even with using game states as in the article above, you actually are kind of hardcoding a game loop for each state... Though I don't think it's as big a problem because code gets re-used alot more, and alot of the redundant code gets factored out.

Quote:

For one, it doesn't really scale, but that's easily fixed by making a lot of its functionality more data-driven. The other problem is that it was stateless. There was no concept of nesting (which would come in handy in an RPG where you get thrown into random fight scenes, and then end up back on your merry way).

Like, say you are on the world map, from where you enter a dungeon, in which you enter a fight. It's not guaranteed that you can trace your way back once those sub-events finish, without some hackery.


I suppose a stack of game states would allow this. Without hacks even!

Quote:

Anyway, I've been rambling, so now it's your turn to ramble. What are your favourite design patterns/approaches for this general problem, and what have you learned when writing games that are more complex than Tetris, which consists of a title screen and the game itself?


I haven't written any games more complex than Tetris yet, (I actually never seem to complete any of the bloody projects I start), but I think I'm well on my way to writing a complete game engine with a nice, consistent interface and a good set of features. Anyways, have a look at the game states and see if they help.

Share this post


Link to post
Share on other sites
yaustar    1022
How strange, I have just recently finished a group project that employed both Game states and Gamesutra's MVC. Although a little difficult to get off the ground with the large number of classes that you have to employ for either method, once it gets going, the whole project is very managable as it is nicely modular as it allows one group member to work on a section/state/entity behaviour without affecting another member allowing tasks to be performed in parallel once the central engines and managers are built.

One of the problems with the MVC is that it can get too abstract and to get to the information you need from one class you have to go to the other side of the design to reach it although this is more of a design issue.

Share this post


Link to post
Share on other sites
James Trotter    432
Quote:
Original post by Zidane
Its a very good question and there are no perfect ways of doing.

In the RPG I am writing I plan to do it via something similar to your Driver class. I think driver is misleading so I use the term "Scene". In simple design terms (I am still planning this out by the way) each type of mode in a game is a inherited from the scene base class. Now there is a scene manager class with which you register a scene with. The scene manager class handles the management of these scene objects.

I have scene classes which handle loading rooms, battle scenes, cut scenes and even the pause menu is its seperate scene.


Scene is pretty much the same as what I called a game state here. However I didn't feel the need to add a scene manager and just added the functionality in the engine kernel class. It saves having yet another class (and a singleton at that!), and it made sense.

Quote:

The scene manager class allows you to execute a scene and will automatically hand control back to the scene which executed it. The problem with my approach, which is similar to your problem, is the storing of state throughout different scenes. To handle this I have made the storing of any information not linked specifically to a single scene completly independent of the scene structure. Singletons once again prove there use in this problem, I have a singleton object which is the golbal registar of any application states. It contains methods like GetXXX(). The values are stored in a collection of associative arrays.


I'm sorry, but this sounds dreadfully complex, and quite ugly. What states exactly are you storing? Which ones need to be restored when you change the scene?

Quote:

This does mean that when a Scene executes another scene it has to reload all the global data it is using, by querying the state singleton.

So in summary:
1) Scenes are a collection of distinct types of parts of the game (battles, rooms, pause menu)
2)A scene manager class allows the scene to be executed and a linked list format allows for the scenes to be linked together (ie a battle can start in a room and you can pause the battle and when you unpause and finish the battle you will be in the room)
3)A state singleton is used to store all global information
4)After a scene loads another scene it has to reload any global information it uses

Now I know this isnt the best way, so Im interested about how up people approach it.


I didn't understand how the scenes were linked with a linked list. Perhaps you could explain a bit more? Isn't a stack, where you can push/pop scenes, a more simple and intuitive approach?

Why don't you make the scene clean up after itself when it unloads? Wouldn't that save using a singleton to get all the states and whatnot? This might just be moving the code to another place though, but I think it sounds much cleaner.

Share this post


Link to post
Share on other sites
OrangyTang    1298
IMHO the top level of your game will probably be best based on some kind of finite state machine to control what bits are currently 'active' (eg. are we in a menu state, or a loading state, or a single player game state). Anything more specific than that you'll probably have to start thinking about what your specific game needs.

If you've got an interface heavy game (like an RPG, with maps, inventory screens, quest pages, etc. etc.) then you would probably be well suited to having some kind of MVC approach (either parallel or within a particular state). Your model becomes the actual world data, the view is whatever is currently rendering and the controller would probably be your current state. Depending on the complexity it might be benifitial to have nested state machines.

I wouldn't try to overthink this though - although your general game structure may contain lots of elements of these kind of patterns it doesn't have to be overly explicit or formal. Just keep an eye on your dependancies and make sure that you're not doing the OOP equivilent of a goto and you can usually 'grow' a good solid design from your initial test code. Refactor constantly and you'll end up with a better design than you could of thought up of in the first place. [grin]

Share this post


Link to post
Share on other sites
SpreeTree    396
One way of dealign with this (and is can easily be visualised in the RPG fight system you described) is to have a simple state stack based structure.

Every state in your game (frontend, main game, pause menu, loading etc.) is a discrete state, which can be pushed and popped onto the game state stack at will. So for example, the game starts, you push the front end state, which pushes the main menu state. You choose options, the options menu is pushed, you chose to leave the options, the state is popped, passing the control back to the main menu. Start the game, the whole stack is flushed, and the game state is pushed etc.

With this system you can keep it as simple or as complicated as you wish. For example, when a state is pushed, you can specify if it will update or draw when it is not the top state/in focus. So if you push the game state, and say "Only update when in focus, but draw it all the time", you can push the pause menu, and have a transparent background, showing the game (which is still being drawn, but not updated).

You can take it a step further, and have a popped state stack, which updates states that have recently been popped. That way you can have transition effects between states depending on the state.

The game state manager is the key in this system, which races through the stack every frame, updating/drawing the entry depending on the state. Again, adding some extra functionality allows you to do a wide range of things.

In this system there is no passing of data between the states, as each one acts independantly of every other, the only control being the flags passed when pushed, and how the state manager chooses to deal with thses.

Hope thats useful to you
Spree

Share this post


Link to post
Share on other sites
Replicon    306
Oh wow, thanks for all the quick replies! Looks like what I was doing wasn't at all that far off from what everyone else thinks is a good way to do it, which is always comforting. I had thought of the stack thing in passing, and felt it might be ugly (especially with the parameter passing), but really, the nature of this problem is extremely stack-like to begin with, so it would almost be a crime not to solve it that way haha. You can even implement things like a "split screen" play this way by having a 'split screen' scene wrap two regular game scenes (though performance might suffer somewhat, depending on how it's done).

Has anyone here used a completely different paradigm? (I will read that gamasutra article when time permits, don't worry hehe).

Share this post


Link to post
Share on other sites
leiavoia    960
I have a core interface which wraps a GameState object. Messages and function calls that go to CoreInterface get forwarded to the active GameState.

CoreInterface::AcceptEvent( event e ) {
active_state->AcceptEvent(e);
}


I do make CoreInterface global (*shrug*, so shoot me). The core interface only does "big" stuph like state changes and event handling. You could make it do whatever you think is "big stuph" for your game though.

I handle state changes by hotswapping the active_state inside the core interface. I give the new state a reference to the old state in case it wants to do anything with it (like possibly come back to it later, or do a cool screen-swipe transition).

Share this post


Link to post
Share on other sites
Telastyn    3777
I've never been a fan of explicit game states. It always seems to lead to assumptions, or coding yourself into a box ["wait, transitions will require knowledge of both states!"].

You've almost certainly got some render-tree setup for your UI. Inherit the menu from the UI baseclass, push onto root of tree. The menu is now topmost, and will thus recieve user input. Closing the menu returns the state [just like a traditional stack]. Function composition with regards to the action that opened the menu [bind key: open menu and pause game] handles the vast majority of common cases, and such a system does not preclude you from handling the others, like most fixed gamestate setups I've seen.

Share this post


Link to post
Share on other sites
lazE    124
I recently took a game design class at my university. I am by no means an expert on this topic and, to be honest, I haven't ever finished a game. If you're still interested in listening to me ramble, then read on my friend!

Unfortunately I think part of my discussion will involve some of the stuff that you did not want to hear about...

A lot of it boils down to events. These events are generally spawned by something the user did and need to be handled by something. Lets imagine for a moment that we have an absurdly simple game which basically just allows the user to move in some direction and see this happen on screen.

We're going to need a way of handling input. Hello PlayerController.

We'll need something to handle the rendering. Hello VideoRender.

We'll need something to mediate between the input and the rendering. Hello GameEngine.

The PlayerController can either run in it's own thread or be asked to do something by the GameEngine. Either way, the idea is the same.

THREADED:

void PlayerController::queryEvents() {
while(gameIsRunning) {
if(user hit w)
myEventQueue.push_back(moved forward event)
etc...
}
}

vector<Event> PlayerController::GetEvents const() {
return myEventQueue;
}


I've left out the mutex locks and unlocks for simplicities sake. In an unthreaded version queryEvents wouldn't be in a loop, it would instead just return one event. This controller cares nothing about the rest of the game. He has no job other then to know key bindings and know how to intrepret them. The GameEngine somewhere in it's update loop would just ask for these events and then figure out what to do. We have the beginnings of facilitating entering a dungeon here. I'll get back to this later when I finish the simple example.

So, the GameEngine gets these events from the PlayerController. The GameEngine has an internal state, it's percept of the game. It will update this percept against this new action. If something valid happened, the NEXT percept is updated. If something invalid happened, the event is just ignored. Anything valid that happened is updated against the NEXT percept. Generally we have an old, current and next percept. This allows us to interpolate nicely.

The VideoRender kind of just sits there. It has a local copy of an old and current pecept. The renderer doesnt care about input. It doesnt care about anything, actually other than geometry and it's position and orientation. Periodically the GameEngine will call a function in the renderer called updatePercept which will pass in two new percept objects.

So far things have been easy and over-complicated for the silly kind of game I mentioned. Lets imagine that things got a little but more complicated. Now, we can click on things and interact with them.

Our PlayerController needs to be able to report click events in terms of x,y coordinates on the screen.

The GameEngine needs to be able to interpret these click events. The GameEngine doesn't really do any rendering and so it's kind of hard for it to understand how the x,y effects anything. However, the GameEngine and the VideoRenderer both understand a percept. Now, instead of just updating the VideoRenderer's percept, the GameEngine will also need to ask the VideoRenderer, "Is there anything at these x,y coordinates?". However the VideoRenderer handles it internally is fine (gluUnProject or maybe using OpenGL's built-in picking stuff). The VideoRenderer would report this event in a similar way that the PlayerController did to the GameEngine. Fortunately, the GameEngine and VideoRender can communicate the information easily because they both use the percept so the GameEngine can very easily understand an event from the VideoRendeer that says, "Object o exists at position x, y". Now, we need a way to understand how that object reacts to clicking. I've only ever made RPGs and I have always used scripting languages to encode behavior. So I would figure out what the object is and call a function like, "onClick" and would get a return telling the GameEngine what needs to be done. Lets say a door was clicked and it means we should go to some dungeon. The GameEngine updates the next percept to reflect that we're now in that dungeon. That dungeon too would have a door that would return to the entry point on the previous map.

So we have a pretty simple system that understand very little about eachother but can facilitate fairly complex interactions.

This is just from my limitted experience. I know very little. I hope I was at least somewhat helpful.

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