0
\$\begingroup\$

I've been writing my own game engine and I was wondering the correct way to handle my game objects. Each game object is different. The only thing they have in common is a set of operations to handle their components. With that said, each game object will have different components that do different things. Ex: game object 1 has input, physics and display components; object2 has only a display component. I was wondering if it was best to

  1. Loop around the list of objects and call an "update" on each of them and then run each "update" for each component the object holds; or
  2. Have a list of components in my game loop and check for each component if they have the current component. If so run it, otherwise move on...

I see benefits and harm to both strategies.

  • Benefit of 1 is that there isn't a lot of overhead, but things might get out of sync;
  • Strategy two is basically the opposite of 1...

For sake of simplicity I'm not putting how I'll handle the gameloop tick and I'm using a generic language.

Example of code for 1:

gameLoop() {
  forloop on each game object as obj {
    obj->update()
  }
}

//obj
update() {
  foreach component as component {
    component->update()
  }
}

Example of code for 2:

gameLoop() {
  input = &event
  forloop on each game object as obj {
    if (obj->canHandleInput())
       obj->handleInput(&event)
  }
  forloop on each game object as obj {
    if (obj->hasPhysics())
       obj->updatePhysics()
  }
  forloop on each game object as obj {
    if (obj->canDraw())
       obj->Draw()
  }
  //audio...
  //other components
}

What is the currently the most accepted way to handle objects in a game loop?

\$\endgroup\$
  • \$\begingroup\$ The main flow of a game program is usually (1) handle input, (2) update physics, (3) draw. Can't you give each game object a method corresponding to these, even if that method is just to do nothing? Also, I'm not sure what you mean about "things getting out of sync". Can you elaborate? \$\endgroup\$ – GoldenGremlin Feb 7 '18 at 13:29
  • \$\begingroup\$ If I hard code the game flow to those 3 behaviors it will need to check anyway if the game object has the component. So this would be a mix of strategy 1 and 2. Is that correct? \$\endgroup\$ – tupan Feb 7 '18 at 13:32
  • 2
    \$\begingroup\$ Some common approaches to component update ordering are contrasted in this answer, which might be useful to you. Just note that your component system doesn't have to be "perfect" according to other dev's theories to be useful for your game. There's no one Right Way™ to build a component system for your game. Absent specific, profiled performance problems, I'd recommend focusing on the architecture patterns that you find most intuitive, suited to the way you like to work, and convenient for you to write/maintain. \$\endgroup\$ – DMGregory Feb 7 '18 at 14:25
  • \$\begingroup\$ That's excellent. I actually bought the book (two weeks ago) you recommended in your answer. :) \$\endgroup\$ – tupan Feb 8 '18 at 3:22
2
\$\begingroup\$

Both approaches should result in the same result, so your choice really comes down to what makes the most sense architecturally.

But first, your example for approach #2 is incorrect. Each system should have a collection of components, so you do not need to have multiple loops over your game objects. That is:

foreach physicsComponent in physicsComponents {
    physicsComponent.update()
}
....

The advantage of #2 is it gives you more flexibility in how to implement system-specific updates. For example, for a physics-heavy game, you might perform a clustering pre-processing step so that you detect collisions only on pairs of nearby objects. It's also cache-friendly as you're repeating a small bit of code over lots of data in one go.

But the advantage of #1 is that you have more flexibility in how systems interact with each other. Suppose you have an animation system and you want to avoid updating it for far-away objects, since the player won't see them at all. But your physics system might depend on the animations as well - let's say your game is a fighting game where character animations change the physics shapes. You can easily handle this if you update on a per-game-object basis, whereas if you went with #2 you'll get a messy tangle of inter-system dependencies.

\$\endgroup\$
  • \$\begingroup\$ About method #2: In your case how would the component know about the data of the object hold? When I add a component to the object it really adds the object to an array of the component? \$\endgroup\$ – tupan Feb 8 '18 at 3:19
1
\$\begingroup\$
gameLoop() {
  forloop on each game object as obj {
    obj->update();
  }
}

//obj
update() {
  foreach component as component {
    component->update();
  }
}

No, not all components require an update. Instead, Write granular systems which handle tasks common to a subset of components, such as updating position by velocity, or computing your graphics transform from position.

Your game loop becomes:

void gameloop() 
{
    for ( auto s : m_systems )
    {
        s->update();
    }
}

Within each system, you have customised loops that only work with a small subset of components, as mentioned before.

It looks like your understanding of this has a few gaps, so I would recommend doing some more reading on Entity Component Architecture, before doing any more work on your engine. I think you will find it illuminating.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.