Sign in to follow this  
Mephs

Game engine architecture

Recommended Posts

Hey all, Now I know this is the kind of question which has been asked loads of times. I also know through extensive searching (several days worth of searching for an answer!) that it's the kind of question that very rarely gets a decisive answer... so I've sat and worked out exactly what it is that causes my problem and I think I've distilled the question down to the point of hitting the nail on the head, which may help get a more concisive answer from someone a little more knowledgable! So anyhoo.... my question is regarding communication between classes interacting in the main game loop. Like many others, I've gotten caught in the trap of dividing my game elements into distinctly separate components such as input/sound/characters/levels etc. This in itself is not a bad thing, but when you then realise that the input component needs to pass messages to the character component to tell them to move.... the character component then needs to check with a physics component to see what the results of moving are (collision, free movmement, etc), the physics component needs to check this data with the level component which itself queries the terrain/scenery it contains. Now this is all well and good, but requires that each class either stores a pointer to the classes it is (semi) related to, or requires that it stores a pointer to the parent class to which it is made a friend so that it can access its' member classes. This, in my mind, is messy.... the links between classes are often obscure at the best of times, and I'm forever going back to the initialise function of a class to add in an argument that will pass in a pointer to the required class.... then you've got to add a stored pointer to the class in your private variables. This gets more and more messy the more levels of classes you have to go through to obtain a pointer to the class you need to access. You could instead create a chain through the classes that calls the function you want for you, but then you need to code a CheckForCollision(x,y,z) type call for every class in the chain and for every function you wish to access, which is nightmarish! So it's: a) confusing when you have obscure links b) a pain in the backside when you have to trawl through a couple of levels of classes repeating above process just to allow classes to communicate. c) when rewriting code it is less reusable because storing pointers to other classes requires explicit knowledge of how the classes work in order to use their functionality. Our classes become dependant upon the functionality of other classes and can no longer be dropped directly into another engine because all of the dependant areas need to be re-written. The method of adding a pointer to the parent class and making the child a friend class of the parent makes it easier to access other components of the parent, but feels very much like it goes against the object oriented ethos. So, summing the problem up.... the difficulty is in setting up communications between classes that if drawn in a hierarchy, would be on the same level. A solution that appears more elegant would be some kind of a messaging system to request and send data through some kind of interface, so only the interface needs reprogramming upon starting a new project, but I'll be damned if I can think of a solution without major flaws in it. So are we really doomed to be writing code that is hard to reuse because there is no better way? Is it less of an issue than I think it is with the standard method, or is there some mystical magical method I'm unaware of?

Share this post


Link to post
Share on other sites
Instead of letting the the topical classes interact with each other, have a game class which act as an supervisor. Something like this:

// Inside the Game-class
while( true )
{
_player.update( delta_time );

// Player is derived from PhysicalObject
_physics.applyPhysics( _player ); // the _physics-object takes care of checking
// and compensating for collisions

if( _input.keyPress() == key_up )
_player.setState( accelerate );
}


This solution has worked for me so far. It may not be the best, but it is easy to follow and it doens't require complex relations between classes.

Share this post


Link to post
Share on other sites
Here are my 2c about this problem that bothers me as well.

First, I believe that you should make your modules (physics, terrain, input etc.) as generic as possible, not aiming at a specific game but enabling as much capabilities as possible. This way you would have generic modules at your disposal.

The next thing to do is to really treat these as black boxes and NEVER rely on one another. The input module will never know about the physics, and the physics module will never know about the terrain. How do you do it? You have another module - your ENGINE module. This one interacts with all the modules but keeps them from interacting between themselves. The interaction takes place based on familiar data structures. For example, you should have a structure, defined in a common level (like the engine for example), that will describe an input event. You will also have a structure that will define a physics outcome of some sort, etc. This will behave like a contract between the engine and its modules.

This way you can do the following:

1. As long as the contracts remain intact, you can change the engine and the modules as much as you like, and nobody gets hurt.
2. If you do need to change a contract, you will know that you have at most caused a change in a link between the engine and N modules. These changes can sum up to N links - but they will never be N^2 links (which might be the case when "everybody is talking to everybody").


I believe this is a fair way to go about doing things. Naturally it has its own flaws, like centralism, and having data defined by the engine instead of the client modules. However, as I believe that the main client here is the engine and the modules are just its pawns, I think this might be a good way to go.

Waiting to hear other ideas :-)

Share this post


Link to post
Share on other sites
Hmm, I actually hadn't considered simply removing a level from the hierarchy. That's not a bad solution actually, but what bothers me about it is that there is no categorisation. It feels correct to have certain aspects of the engine dealt with entirely separately.

I suppose the topical nature of some classes is the cause of the problem they try to resolve as they add an unnecessary level of abstraction which I had never really considered removing before. I would worry a little however with this method, that too much work is being taken on by the game supervisor class.

Well, certainly the best answer I've seen to this question so far, but I'd appreciate anyone else confirming that this is how they deal with things or pointing out any negative implications to this method, not that I want to pick fault, but I want to make sure I'm doing things as well as I can :)

Thanks,

Steve

*EDIT* DadleFish, thanks for your reply also! That suonds just like the kind of interface method I was thinking of myself. I think I've certainly got some thinking to do now, it's been great to see both opinions so quickly :)

Share this post


Link to post
Share on other sites
Hey,

I've been having similar problems, hopefully if i explain how my engine works it may help.

Until recently i've been structuring my classes so that they can interact with each other, this was bad for 2 reasons:

1. The code gets messy quickly
2. Code could not be easily reused

So when I decided to give an engine another go I did some research, the most useful articles I found were the Enginuity series by Superpig. They describe a number of complex techniques, of which I selected a few. I used his Singleton class, and the Task Based approach to the engine. This means that Input / Sound / Video etc. are all tasks which have Start/Update/Stop method. They can be suspended and resumed, and are controled by a kernel class.

So now in my engine, anything that I only need a single instance of is derived from the Singleton class. This includes: the game log, the main game timer, the texture manager, the physics environment, the kernel, and the application class.

Anything that needs regular updating in the game loop is derived from the task class; the physics, video, sound, input etc.

Although my engine is still in its early stages, everything is tidy, bugs are easier to find and most importantly everything is modular and can be dropped into another project.

Another tip is: Do not be afraid of static functions and classes. Use them wisely but remember they are there.

Hopefully that might give you some ideas,

Luke.

Share this post


Link to post
Share on other sites
What you can do is, first declare a mother class, let's say the "game" class and then have child classes underneath it and all messages go through the mother class, which makes it understandable.

Sorry for the vague description... but if you need more info, please feel free to mail me: thedatabandit@hotmail.com

Cheers,
-Zubair_

Share this post


Link to post
Share on other sites
Quote:
Original post by databandit
Sorry for the vague description... but if you need more info, please feel free to mail me: thedatabandit@hotmail.com

Cheers,
-Zubair_

...or we can use this forum!

Share this post


Link to post
Share on other sites
Forgive me if I'm being dense, but the Enginuity articles, while being very good, and something I'd certainly like to implement, actually do not help with allowing easy communication between classes? Perhaps that wasn't the intention, but I still ask, as if it does have relevance to my query, it would certainly help if I understood exactly how it is relevant!

So far, I think the engine interface style class seems the best solution... that way, we still have to go through the process of building the links... but all the code for the links is in a common place. This means that if we do have to add in new modules to an engine and remove old ones, we simply slot them in, add any new links in the engine interface class and the newly added classes, and we needn't touch a line of code in that which has already been created unless it needs to interact in a different way with the new component. If it does need to interact with the new component, all rewritten code will revolve around the engine interface class only.

Take our previous example, say we wish to add in floor-plate switches to our moving around a map situation. We create a new class to represent interactive map elements. With the suggested system, we simply pass a EngineInterface pointer to the interactive objects class containing the floor-plate switch object. Now the switch needs to query the physics module to determine if anything is pressing on it. We implement in our EngineInterface class a function such as IsAnythingPressingOnSwitch(). We then let the EngineInterface worry about obtaining that data via querying the character engine for all characters within a given radius to determine if they are on top of the switch or not, and the switch never even has to know how the character class works.

If we then in future include a class representing objects that can be pushed onto the switches, we simply alter the EngineInterface IsAnythingPressingOnSwitch() to also check with the ObjectManager class for objects within radius. We never need ever touch the switch class in any way to let it know how to deal with the existence of the new class.

So anyhoo, I guess I'm simply restating what was said previously by DadleFish, by way of a more solid example, but it seems to make sense to me :P

Cheers,

Steve

*EDIT* please ignore the fact that switches and boxes are both interactive elements that should be in the same class (little mistake of mine!)... I think the point is still made ;)

Share this post


Link to post
Share on other sites
As others mention, pretty much any time you have a behavior that needs two [or more] other behaviors to work, it belongs in a class/object "above" those two other behaviors.

To the example:

Quote:

Take our previous example, say we wish to add in floor-plate switches to our moving around a map situation


Okie dokie.

Quote:

We create a new class to represent interactive map elements.


I'm not certain that you can abstract all the different interactive map parts this way, and I'd start by making a base interface class, not a full fledged class; but that's an implimentation detail.

Quote:

With the suggested system, we simply pass a EngineInterface pointer to the interactive objects class containing the floor-plate switch object.


No, bad. What you do is have the EngineInterface pointer 'create' the interactive object and put it into a list, or have a mediator [which is a level above the engine] create the interactive object and attach it to the upper level part. [or better, see below] Remember, ownership flows down hill.

You might still need a 'parent' or 'owned_by' pointer in the lower class, but the idea is to make the 'lower' classes handle less and less problems so that the lowest can handle a simple problem easily. The 'higher' classes combine these until a really big problem, like a game, becomes managable code.

Quote:

Now the switch needs to query the physics module to determine if anything is pressing on it.


And then you've dependancy again.

Personally, I would try something like this:

engine contains map.
engine creates floor plate, adds to map.
engine creates image/model representing floor plate,
engine links image data to floor plate data [boost::weak_ptr, reference, bald ptr],
adds to lower rendering module,
forgets it.
engine creates physics representing floor plate,
engine links physics object callback/trigger to something it owns...
(likely a member function of the engine floor plate)[boost::function, boost::weak_ptr]
adds to lower physics module,
forgets it.


Then the rendering part can focus on rendering the model, and only knows/cares about the model. The physics can focus on 'triggering' the plate, and ignore how it's rendered. The engine knows about both, but can safely ignore how the rendering and triggering is done. Those are problems solved by 'lower' parts.

Share this post


Link to post
Share on other sites
So essentially, what you're saying is that we should create seperate models of everything, i.e. the physics part of the engine should deal with physics and physics only.... the AI engine AI only such that if the AI needs to access terrain data, the terrain data should be included in the AI model as a fundementally separate entity from the actual terrain data.

I can see the benefits of such a method, but surely this causes just as many problems? Okay, so the engine knows that there are 3 versions of the terrain, 1 in the AI class, 1 in the physics class and 1 in the rendering class, but we now have to ensure that 3 separate models of the terrain are kept synchronised with one another and 3 times the memory consumption. I suppose to solve the synchronisation issue every change must be made in the base engine on a base object, which would then look after updating the other representations of its data.

The more I think about it, the more appealing this method is, but I'm still not 100% convinced yet... some more food for thought though.

Thanks!

Steve

Share this post


Link to post
Share on other sites
Okay, I've worked out the problem with this method. So say we want there to be interaction between elements, our physics class has a physics model of the switch and our rendernig class has the rendering info it needs and under normal circumstances they quite happily do their thing, but if we want the player to be able to disable all switches within a radius by using a magical switch disabler device, how do we do so?

We need interaction between input (key press to activate device), objects owned (magical device must be owned) and the physics engine must know not to let the switch activate, even when under normal circumstances it would be activated. Using the suggested method I cannot work out a way that fits in with the ideology and accomplishes the above. I'm not saying it can't be done, but that it leavs me back with the original problem and I can't see a way out :P

Thanks for any help!

Steve

Share this post


Link to post
Share on other sites
how about a messaging implementation

1. execute some class procedures "a some event occured"
2. send event through the event pipeline
3. the eventhandler chooses the right targets and passes the events to these class instances


This completely eleminates the nasty class coupling that is involved with a lot of inter class commmunication implementation which makes classes quite maintainable and reuseable

And actually it does nothing else than calling a memberfunction of a class instance directly inline the event handler and turn on optimizations, this will most likely optimize the additional function call away

Share this post


Link to post
Share on other sites
Quote:
Original post by Mephs
Okay, I've worked out the problem with this method. So say we want there to be interaction between elements, our physics class has a physics model of the switch and our rendernig class has the rendering info it needs and under normal circumstances they quite happily do their thing, but if we want the player to be able to disable all switches within a radius by using a magical switch disabler device, how do we do so?

I would do something like this (pseudocode)

while( game_runs )
{
float dt = getDeltaTime();

if( _input.keyDown( key_that_moves_player ) == true )
_player.setState( MOVE_FORWARD );
// ...and all the other cases
if( _input.keyDown( the_use_key ) && _player.getActiveObject() == magical_switch_disabler_device )
{
// This class contains all switches.
// The method below checks the distances between each swich
// and the player, and disables those within range
_switches.disableSwitchesCloseToPoint( _player.getPos() );
}

// The update method updates the player depending on its state
// i.e. if the state is MOVE_FORWARD it moves forward
_player.update( dt );

// Player is derived from PhysicalObject
_physics.applyPhysics( _player ); // the _physics-object takes care of checking
// and compensating for collision

// rest of updating and rendering etc etc etc
}

We have no links between engine-classes. The input class knows nothing about any other class. The physics class know nothing about other classes, all the _physics object knows is the phyisical representatino of the world, and it can apply the physics to any objects that is sent to it (by reference of course). So in in this example, the _physics-object only corrects the player's position in case the player walked into a wall or something.
The only links are between objects that are gamespecific (like _player, _switches and so on).

In my engine, I have a static Renderer class. Each time an object wants to be rendered it sends a "renderable object" to the renderer, like this:
Renderer::addObject( _player.getPlayerModel() );

Then after each frame, _renderer empties its array of objects to be rendered, and the next game update the _player class will add its model again. Ofcourse it only adds a references to its model. So the Renderer class knows nothing about game-specific objects, it only does what it does in any other game, renders objects sent to it.

Please let me know why this isn't a solution to your problem (if it isn't [smile])

Share this post


Link to post
Share on other sites
I think you may have a valid point, perhaps that is the best way, a combination of the two methods. As far as I understand then, the sum of what has been suggested is to separate the engine into a few key modules categorised only by representation letting no class down the chain dealw ith anything further up the chain unless absolutely necessary (Physics, Visual rep, AI, maybe one or two others), have each module deal only with those things it specifically should, and then keep all game specific elements in the main game loop where they can easily communicate with one another.

I think the key point I see here is that doing something such as keeping players in a character class only makes them harder to talk to and that instead we should just put a representation of them into the standard blocks of the game (physics, AI, etc).

What I still worry about with this method though, is that you'll be doing all the many various tasks of the game engine in the main game loop, surely this will make the main game loop bloated and difficult to work with as everything is lumped into it with no categorisation, it just sounds more correct to have characters managed by a character manager, items managed by an item manager and so on, as they are distinctly seperate elements that just happen to interact together.

Share this post


Link to post
Share on other sites
Hey guys!

As for the key press stuff, I would defenitely have something like this:
(If you want to have a somewhat serious engine you should too)


IOSystem ioSys = new DX9IO(); // or whatever... if you want to load as plugin...

//This will control the player, set the player states
KeyController controller = new KeyController(ioSys);

//Link the controller to the player
GameObject player = new Player();
player.AttachController(controller);

//Insert the player into the scenegraph
sceneGraph.Insert(someParent, player);


//Then you dont have to worry about anything anymore :)
//Just update the root once, and each node will handle
//itself
sceneGraph.root.update(app_time);

//This will make the following actions:
Player::update(app_time) {
//Update all the controllers, that control this object
//In our case only the KeyController...
controllers.update(app_time);
//... do whatever a player might want to...
}

KeyController::update(app_time) {
if(ioSys.GetPressedKeys().Contains(KEY.UP)) {
player.SetState(PLAYER_STATE.MOVE_FORWARD);
}
//etc...
}




Aha, see the power of SceneGraphs ?? ;)
This is actually the stuff a SceneGraph IS supposed to handle, and
not stuff like rendering which should be handled by a spatial
structure.

Hope that helps, if not read some of the articles in the SceneGraph sticky :)

GL!

Share this post


Link to post
Share on other sites
Well, I just had a brainwave... I think I can sum up my problem and solution in a quick easy manner.

In my mind, a player character should look after its updates through:

Player.Update();

My problem is that I'm expecting the player class to internally update itself based upon external influences, this method of thinking is flawed and should be replaced by the following ethos:

Player.Update() updates the player based solely upon the players internal data and not upon any external factors whatsoever, meaning that the Player.Update() function is not all encompassing. Anything external to the players own privately held data should be dealt with by the main game loop such as in the example:

// Player is derived from PhysicsObject
Player.Update();
PhysicsEngine.Process(Player);

In this manner the player class is truly self-contained and if we wish to change the physics engine we simply change the PhysicsObject class to suit the new physics engine, derive the player class from it, and in this case we don't even have to touch the main game loop. In this way, when changing the physics engine we don't change anything about the player class... it still deals with updating itself just as it always has done.

I think this change in thinking is mainly inspired by the realisation that I was in the bad habbit of thinking that Player.Update() has to be self-sufficient and update everything to do with the player when it does not.

Perhaps many others fall into this trap too but can't explain themselves, so I hope this thread helps others!

Cheers,

Steve

Share this post


Link to post
Share on other sites
Quote:
Original post by Mephs
// Player is derived from PhysicsObject
Player.Update();
PhysicsEngine.Process(Player);


I used to do something like this and it didn't work out so well for me. I've found that making the Player object (and every other type of entity) a data-driven class it actually simplifies your problems. Your player (PhysicsObject, whatever) is now just a bunch of variables and doesn't have any methods associated with it. If the game wants to update it, it has to do it itself. So moving the object would involve something like:

PhysicsEngine.MoveObject(Player, Vector(10, 10, 10));

The physics engine would then move the object, checking and updating other objects if any collisions occur and applying the necessary forces on the object. This way, you have a single, central point that the objects can be updated and nothing else can affect the objects. It also plays well for client/server type systems; the physics engine is the single authoritive source of motion and placement and it can ignore a request if it doesn't make sense (for example walking through a wall or leaving the world boundaries).

Share this post


Link to post
Share on other sites
By data-driven, do you mean like a struct, as in having no functions? I wasn't able to find a good example of data-driven classes on google!

See, this is the kind of thing that confuses even (IMO of myself) intermediate level programmers because almost every example I've ever read suggests having a Player.Update() function to take care of updating the player. I think though, that this is because ina small scenario, such a situation is fine.... put it into the context of a bigger program though, and it just doesn't pan out!

That's assuming I'm understanding correctly.

Anyhoo, thanks for the extra insight :)

Steve

Share this post


Link to post
Share on other sites
Quote:
Original post by Mephs
By data-driven, do you mean like a struct, as in having no functions? I wasn't able to find a good example of data-driven classes on google!


Not exactly, but kinda. Your game entities (including types) aren't hardcoded. Instead, you build them out of components at runtime, or use scripts or another datasource to define them. Each component can have functions related to its specific actions, but in general the components provide data and a way of manipulating the data. Take a look at Scott Bilas' presentation here and the discussion on GameArchitect.

The reason I don't like a Player.Update() method is simply because it forces me to start hardcoding things. It forces me to keep pointers to game systems within my entities and encourages bad design because you become accustomed to accessing these core systems every where. Instead I'd just make my entities almost pure data and use a messaging system to update them. If the player wants to move, a MoveEntity event is fired and handled by the physics system. If the entity doesn't have physical properties then the event won't be handled and the game ticks along normally. There's no assumptions within the code that the player entity is of a certain type or can have certain actions performed on it. Simply, if the entity can't do it the revlant system that manages it won't respond to your message requests to perform that action. If you have an Update() method you've instantly committed yourself to the entity being of a certain type and having to manage itself, meaning your game has to later correct any misbehaviour at a later point.

BTW, my thinking has been changed a lot by a book called "Game Coding Complete 2". It's got some great ideas and techniques that are used in huge commercial games (Ultima Online, anyone?). It might be worth a read.

Share this post


Link to post
Share on other sites
I had actually read that gamearchitect link in the past, which goes to show how sometimes things just go over your head ;)

It raises some interesting thoughts though. In my particular game, I want to have the player effectively on rails known as ley lines. Ley lines will be represented by glowing lines in concentric circles. The player can move between these lines and along them but not out into the rest of the environment.

So following this data-driven design, I send a message when the player presss to go left (MOVE_ENTITY). Firstly, when sending the message, would I need to specify a target (TARGET_PLAYER), or should the target just pick up any relevant messages, in which case wouldn't the message be better named MOVE_PLAYER_ENTITY rather than simply an ambiguous MOVE_ENTITY that could be picked up by a scenery object just as easily as the player?

Assuming we specify a target somehow, then the physics engine would pick this up and move the player. How would I specify that the player cannot move off the rails of the "ley lines"? This is not really what I would consider a standard element of a physics module, so where would the handling for this belong?

Should it go in the physics section anyway, despite the fact that it is somewhat game specific? Should I seperate it entirely from the physics engine? I guess perhaps we should have an intermediate module that redirects the players movement along the path and then feeds the results back into the standard physics module. This then leaves the question of what happens if the physics module then encounters a collision and sends the player flying off the track as a response... which breaks everything! Ideally I'd like it to have a standard collision response so existing code I have sitting around could be used without modification, but to direct the force along the ley line rather than in the "correct" direction.

Hope that example makes sense anyhoo.

I definitely like the concept here, but this kind of thing is exactly why I'm struggling to find something I'm 100% happy with :P

Cheers,

Steve

Share this post


Link to post
Share on other sites
Quote:
Original post by Mephs
By data-driven, do you mean like a struct, as in having no functions? I wasn't able to find a good example of data-driven classes on google!


Sorry to go a bit off topic, but I wanted to point out that in C++, my understanding is that the only difference between a struct and class is that a struct has its members public by default, while class has them private by default. Otherwise they are pretty much the same thing.

Share this post


Link to post
Share on other sites
[also OT]True, but I think you also wouldn't really give a struct functions in the same manner as a class... perhaps a save/load function or something to perform some simple data manipulation, but personally I treat them more as custom data types than as classes with public variables.[/also OT]

Share this post


Link to post
Share on other sites
Just wanted to make sure you knew that you could use a struct like a class. As far as i'm aware (other than struct members being public by default) using a class or a struct is mostly a matter of coding style.

Share this post


Link to post
Share on other sites
There's absolutely no need to have 3 separate data instances for AI, Physics and Engine parts. What you have is data, and pointers to it. Also, the AI and Physics aint' going to use same CModel class presented in Engine as data container, but they are going to have their separate classes (e.g CRigidBody for Physics, CAgent for AI) that are going to have a const. pointer to the CModel class (hence, not modifyable!) that they are going to use for their logic. As an example, CRigidBody is going to use CModel to aquire bounding volume for it from the CModel' set of vertices, or its center.

That's all up to it.

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