for( auto& object : gameObjects ) { Renderer::draw( object, viewCamera, interpolationRatio ); }
With composition, you should have a separate list of just the Renderable objects, and only loop over those:
for(auto& renderable : renderables) { Renderer::draw(renderable, viewCamera, interpolationRatio); }
The point of composition here is to (somewhat ironically) decompose your GameObject into its component parts. The only thing the renderer needs is the render info; it needs nothing from the GameObject other than its Renderable component.
Another way to think about: rather than your system pulling Renderables out of the list of game objects, a game object should push its Renderable into the systems. Invert your dependencies.
You really really don't want that update pattern you posted. It doesn't scale, it's slow, it's messy, and it's _more complicated_ than needed so you aren't even really saving yourself any effort by using it. :)
Remember, you might not even want to walk components in a simple list, because that means you aren't doing any kind of efficient scene graph walking and culling. So even if you didn't use components, you'd still want entirely separate lists between "all game objects" and "game objects organized in a spatial partioning data structure." :)
The one tricky case that tends to lead people to tie components and gameobjects together is the transform matrix/data. e.g., game logic needs to know where things are, graphics needs to know where things are, and physics controls where things are. However, those can still all be separated fairly cleanly. The most naive way is to make a Transform component and just have your Renderable and Physics components hold references to the Transform component when initialized. For a simple engine like you're working on, I'd start there.
The key point here: put your components into their own lists if they need to be walked or iterated over. That's basically a part of ECS, but is waaaaaaay simpler than a "full" data-driven ECS. It can be as simple as this (using some globals because it's a short example and I'm lazy):
// nice simple GameObject with static composition, just like you wanted
GameObject::GameObject() {
// transform is a separate object so it can be shared between modules
// without introducing a dependency on GameObject
_transform = make_unique<Transform>();
// renderable is a completely stand-alone object with a dependency
// on transform (and whatever resources it needs) and nothing else,
// though note that this shouldn't be in GameObject probably since
// you might have objects that have no visuals, e.g. trigger zones
// or sound sources
_renderable = make_unique<Renderable>(*_transform);
}
void Renderer::render(Camera& camera) {
// renderable is only walking the known renderables, so if some GameObject variant
// has no renderable, it won't be in this list, and there's no need to query every
// possible GameObject variant for a Renderable
for (auto& renderable : gRenderables)
draw(renderable->getMesh(), renderable->getTransform(), camera);
}
// NOT how I'd recommend registering Renderables in real code, but it suffices for the example
Renderable::Renderable(Transform& transform) : _transform(transform) { gRenderables.insert(this); }
Renderable::~Renderable() { gRenderables.erase(this); }
What you should take away from this is that using composition _simplifies_ code. And you don't need to go anywhere near any ECS framework nonsense to get 90% of the benefits of composition.