Quote:Original post by smasherprog
OOP (object Oriented Programming) is all about organization. For example, should an EnemyNode like you described above know about the Assetmanager? Well, there is a hierarchy of class-to-class knowledge that must be maintained, and some classes should not know about other classes (this is obvious, isn't it?). To use a crazy example, a std::vector<T> should not have knowledge of the class EnemyNode because the vectors JOB is to just hold "things" regardless of their type --thank you for templates!
So, your EnemyNode SHOULD have knowledge of how to load itself and SHOULD have knowledge of how to do that. So, it SHOULD have knowledge of the AssetManager, otherwise it cannot load itself.
That's a not-entirely-unreasonable approach, but it's not the only one, the "most OOP" one, or probably the best one, either; particularly if you are concerned with having the extensibility to support many model formats.
When we talk about "organization" in an OOP sense we're not talking about putting all the stuff that "feels" like it should go together into one class, we're talking about cohesion and decoupling. These two concepts are basically the crux of the "One class, one responsibility" mantra in object-oriented programming.
The responsibility of an EntityNode (assuming it to be a node in a scene graph) is simply to represent the visual aspect of the entity within the scene. It probably doesn't even hold the actual model data (after all, you don't want to duplicate model data for each instance of an enemy or something) so, why then, would it make sense for it to know how to load something which it does not own?
Then we're left with the model class, whatever that may be. The responsibility of the model class is to represent model data to the underlying graphics API (whether that be OpenGL, Direct3D, or something higher-level, like a scene graph or API abstraction layer.) Even that does not require that the model class know how to load itself, only that it has been loaded at some point.
Loading the model is yet another separate responsibility -- just think about wanting to support another model format, or a new version of an existing format. Why should this require changes to the model class, whose responsibility it is to represent the loaded data to the graphics API? Depending on how well your classes are encapsulated, such changes might cause a massive amount of recompilation to occur, which is something to be avoided.
As for how to structure it and when to use it, I, myself, have either a single, global asset manager (per resource type) whose reference is passed down to each gamestate or I have multiple resource managers (per resource type) owned by the gamestate. In either case resources are loaded at the beginning of each gamestate and none of the resources know anything about the asset manager itself. Loading is accomplished by separate loader classes (function objects) or functions, and specified through a function argument template. That can be cleaned up a bit with the factory pattern if it gets too ugly.
[Edited by - Ravyne on October 16, 2010 11:19:08 PM]