However, in all my development there has been a common theme: that sense of sickening dread (and I'm being literal here) when it comes to hashing out the game object hierarchy. Starting with the base GameObject, and working down the ever-increasingly-complex tree of inheritance (and multiple inheritance; yay!) down to the final culmination: the ever-so-spaghetti-ish PlayerObject. Since the Player is the first object I really usually get working in the game, that means a LOT of base-code to design, write, test, debug, scrap, re-write, curse at, delete in fury, re-write in chastened humility, and ultimately hate to the depths of my being.
Then I read Evolve Your Hierarchy. At first, it took a couple days for it to percolate into my head. I'd of course heard of plenty of rationalizations for object composition systems, but I'd never given them much shrift. In my mind, I was convinced that struggling with a messy object inheritance hierarchy was The Right WayTM. However, this article got me thinking, and over the next couple days as I worked, toiling over wheeled cauldrons of freshly mixed concrete, I pondered it.
And started to get kind of excited.
My programming style is not exactly what you could call top-down. Although I was taught in college to always, always, ALWAYS have your design on paper, rock-solid and thorough, that system never worked for me. My own mental deficiencies naturally prohibit it. I simply can not visualize the complex systems to completion well enough to get the design down. It's not until I physically begin writing code that I really see all the issues, potential pit-falls, and requirements. I'm a hands-on developer. And so naturally, the "is-a" school of class hierarchy thought simply sucks for me. I spend so much time tweaking the hierarchy, agonizing over where in the tree to put such-and-such functionality, etc... that I commonly abandon the project in frustration or lack of interest.
After reading that article, and doing a bit more reading of different sources, I've started experimenting with component-based systems, entity systems, and the like, and I have really started to understand: this stuff is pretty awesome. And it suits my slap-dash design methodology to a T. No more munging around in the hierarchy, trying to find the hack or kludge or work-around that will make the system function. No more hierarchy, in fact.
I am currently playing with an entity system where all game objects are long integer GUIDs, the central nervous system is a global event pump that prioritizes events and dispatches them to sub-systems, and where object components that define the behavior of objects are managed by event-handling subsystems. And the system is neat. Really neat.
The hardest thing I had to wrap my head around, I think, is the fact that rather than an object (say, a player) being a discrete chunk of data and methods localized in one place, it is now a widely distributed set of sub-objects living in disparate parts of the system, and tied together only by that one piece of shared data: the GUID. No direct communication at all between components of an entity. All linkages are done through the event system.
The part of an object that Takes Damage now can no longer directly affect the part of the object that maintains Health. Instead, it must dispatch a message (TAKE_DAMAGE) and rely on the Health component to listen for that message and modify the health accordingly, in it's turn sending out additional messages as needed (HEALTH_IS_LOW, HEALTH_IS_0, etc...) While the system has introduced some convolution, it is of the standardized sort of convolution, and has greatly simplified the way in which object interactions are handled. It has helped me to finally decouple all of my objects, and has given me an approach that suits my design-as-you-go method.
It has changed my life. It has changed the way I look at coding and development. It has added 16 pounds of muscle mass, whitened my teeth, and enabled me to pick up lots of chicks.
Component/Entity systems rawk.
For the record, my latest system is lighter than all the others. It's in python. It goes like this.
An object has a MAP of components. They're mapped by type. I ask an object for a component like this:
if Health in object.components: object.components[Health].hp += 5.
Type validation comes for free, and I didn't write a single function to handle it.
Component base class (the only base class ever) defines default functions that some components might not need (for ease). One default property is a pointer to the owner object, so components can directly communicate with other components in the same object.
Event dispatching is as simple as a list, like drop_notify. Add a listener: drop_notify.append(obj.listener_func) (bound methods are fun). Call all listeners: for func in drop_notify: func(). Again, I didn't write a single function for the system.
That's it. I practically didn't write any code at all for it to start working!