views:

211

answers:

4

I have an idea of organising a game loop. I have some doubts about performance. May be there are better ways of doing things.

Consider you have an array of game components. They all are called to do some stuff at every game loop iteration. For example:

GameData data; // shared
app.registerComponent("AI", ComponentAI(data) );
app.registerComponent("Logic", ComponentGameLogic(data) );
app.registerComponent("2d", Component2d(data) );
app.registerComponent("Menu", ComponentMenu(data) )->setActive(false);
//...
while (ok)
{
//...
app.runAllComponents();
//...
}

Benefits:

  1. good component-based application, no dependencies, good modularity
  2. we can activate/deactivate, register/unregister components dynamically
  3. some components can be transparently removed or replaced and the system still will be working as nothing have happened (change 2d to 3d)(team-work: every programmer creates his/her own components and does not require other components to compile the code)

Doubts:

  1. inner loop in the game loop with virtual calls to Component::run()
  2. I would like Component::run() to return bool value and check this value. If returned false, component must be deactivated. So inner loop becomes more expensive.

Well, how good is this solution? Have you used it in real projects?

+3  A: 

C++ programmers have way too many fears about the overhead of virtual functions. The cost of the virtual call is probably negligible compared to whatever the function does. A boolean check is not very expensive either.

I'd say do whatever results in the easiest-to-maintain code. Optimize later only if you need to do so. If you do find you need to optimize, eliminating virtual calls will probably not be the optimization you need.

Kristopher Johnson
Your priorities are correct. But in practice, virtual calls are really slow. When I was writing particle system, one virtual call per particle was too slower than one call per particle system.
topright
Right, the important thing may be how many virtual function calls does your program need to make per second. 100,000? No problem. But 10 million may be a noticeable fraction of total CPU time.The other issue is how much work you get done per function call. As long as most virtual calls do a nontrivial amount of work, there's no problem.
Qwertie
+4  A: 

In most "real" games, there are pretty strict requirements for interdependencies between components, and ordering does matter.

This may or may not effect you, but it's often important to have physics take effect before (or after) user interaction proecssing, depending on your scenario, etc. In this situation, you may need some extra processing involved for ordering correctly.

Also, since you're most likely going to have some form of scene graph or spatial partitioning, you'll want to make sure your "components" can take advantage of that, as well. This probably means that, given your current description, you'd be walking your tree too many times. Again, though, this could be worked around via design decisions. That being said, some components may only be interested in certain portions of the spatial partition, and again, you'd want to design appropriately.

Reed Copsey
This is not exactly the answer on my question, but very useful one. Thank you.
topright
@topright: Your question sounded more like a "is this design acceptable"... I tried to give you some things to consider with your current design, as described.
Reed Copsey
I voted for your answer.
topright
+1  A: 

I used a similar approach in a modular synthesized audio file generator.

I seem to recall noticing that after programming 100 different modules, there was an impact upon performance when coding new modules in.

On the whole though,I felt it was a good approach.

James Morris
+1  A: 

Maybe I'm oldschool, but I really don't see the value in generic components because I don't see them being swapped out at runtime.

struct GameObject
{
   Ai* ai;
   Transform* transform;
   Renderable* renderable;
   Collision* collision;
   Health* health;
};

This works for everything from the player to enemies to skyboxes and triggers; just leave the "components" that you don't need in your given object NULL. You want to put all of the AIs into a list? Then just do that at construction time. With polymorphism you can bolt all sorts of different behaviors in there (e.g. the player's "AI" is translating the controller input), and beyond this there's no need for a generic base class for everything. What would it do, anyway?

Your "update everything" would have to explicitly call out each of the lists, but that doesn't change the amount of typing you have to do, it just moves it. Instead of obfuscatorily setting up the set of sets that need global operations, you're explicitly enumerating the sets that need the operations at the time the operations are done.

IMHO, it's not that virtual calls are slow. It's that a game entity's "components" are not homogenous. They all do vastly different things, so it makes sense to treat them differently. Indeed, there is no overlap between them, so again I ask, what's the point of a base class if you can't use a pointer to that base class in any meaningful way without casting it to something else?

dash-tom-bang
1. I am inspired by the work of Jeff Plummer "A FLEXIBLE AND EXPANDABLE ARCHITECTURE FOR COMPUTER GAMES". He describes data-driven architecture with components that do not know about each other and communicate via Data Storage and message queues.
topright
2. Also I believe using such components is a flexible approach. It allows you to control dynamically what game subsystems should work. You can use such components on any level of abstraction. Game object can be a component. Particle system can be a component. The whole rendering system and AI can be components. Menu or a Game State can be. Etc.
topright
As always, I vote for your answer.
topright
I don't know that book, but just because you *can* do something, it doesn't mean you *should*. Components are flexible, but flexibility is only good if you need or use it. If you don't need it, it actually becomes an impediment. If your components are intended to be truly independent, they shouldn't be communicating with each other anyway. Put another way, if everything in your game is a component, so what? You're going to have a list of things that includes every allocation you make? What's the benefit of that?
dash-tom-bang
Why do you think I do not need such flexibility? :) I do need. I can create task-specific components (for IO, AI) once and use them many times. They can communicate via event queue or by updating data in the Data Storage. So one component checks and updates physical logical values and the other renders objects using these values. These components do not know about each other (and that's good), but they effectively work together (good again).
topright
You can google Plummer's book, it is freely available. He describes all benefits and disadvantages of this approach. I can't say my approach is 100% the same, but as I said, I was inspired by this book.
topright
My statement is only to try to suggest that despite what you think, you don't need that flexibility. However, you are certainly welcome to spend your time adding, maintaining, and debugging that functionality if you wish. I just consider it a waste of time. I will check out Plummer's thesis, all the same, but I'm skeptical of people coming down from the mountain who try to tell me how to do what I've been doing for 15 years.
dash-tom-bang