Having a Component class, with Start(), Update(), etc is very simple and makes a very clean code
I'm not sure this is true. In my code, Components are simple data structures without any functionality. They just keep some info about this GameObj.
For instance:
class GraphicsComponent: public Component{
public:
unsigned int gameobj_id;
float posx, posy, posz;
float scaling;
std::string material_name;
}
My Systems have Init(), Update(), etc, and will update the Components during those functions. in Engine::StartRunning() I call every System's Init() function. Then, when I start my gameloop, I call every System's Update() function over and over again until someone tells me to stop.
class GraphicsSystem: public System{
public:
void Init(){
// *set up initial GameObj components* //
}
void Update(float delta_time){
HandleSystemMessagesAndInput();
// *do stuff with components* //
}
std::vector<GraphicsComponent> gfx_comps;
};
Different Systems will keep 'their data' about the GameObjs (it's all inside that Component), but they will have functions implementing their functionality. For example, PhysicsSystem will have a PhysicsSystem::HandleCollisions( PhysicsComponent *phys_comp_a, PhysicsComponent *phys_comp_b) function.
I still keep a global container of GameObjs for convenience, but that's kind of taboo. However, I find it useful to hang a GameObj's Components on a GameObj struct for intra-System bailouts. In reality I only really use this during Component add/remove (each System does its own Component adds/removes) and I would warn you against thrashing the cache by doing it too often.
P.S. This link has some good discussion about the tradeoffs in using different approaches: http://gameprogrammingpatterns.com/component.html