Game engine architecture

Started by
31 comments, last by Telastyn 18 years, 5 months ago
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
Cheers,SteveLiquidigital Online
Advertisement
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
http://www.8ung.at/basiror/theironcross.html
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])
[s]--------------------------------------------------------[/s]chromecode.com - software with source code
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.
Cheers,SteveLiquidigital Online
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 statesKeyController controller = new KeyController(ioSys);//Link the controller to the playerGameObject player = new Player();player.AttachController(controller);//Insert the player into the scenegraphsceneGraph.Insert(someParent, player);//Then you dont have to worry about anything anymore :)//Just update the root once, and each node will handle //itselfsceneGraph.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!
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
Cheers,SteveLiquidigital Online
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).
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
Cheers,SteveLiquidigital Online
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.
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
Cheers,SteveLiquidigital Online

This topic is closed to new replies.

Advertisement