So you seem to have kind of a game view system going on then don't you?
So if I'm understanding right your animation system isn't in a component then? For my purposes I'm thinking of making it a component that just listens to events from it's ID.
I can't say whether my design is solid or not yet, but I like the approach at least. I began under the premise that my components are nothing more than data bags, glorified structures called classes that hold state information for a particular component. They hold pointers to allocated resources, etc but there isn't any logic within them at all. All the logic and behavior has been offloaded into a system class that oversees all components of a particular class. In the component's world, all it has is an entity id (a number) but it has no idea what it means, just it needs to hold onto it. The component system doesn't know anything about the outside world except for the event dispatcher. It works under the premise that I send events and either I get an answer or I don't (in the case of callbacks) or I send events and forget it and move to the next task. Beyond that, a component system and its components work in their own little area of space without a care of what else is happening in the system.
In my system, when events are fired, they have an event id and most events typically have an entity id property or a target/source entity id when we talk about cross-entity interaction. The component systems register with the dispatcher upon start-up and specify what event types they are interested in as well as registering their respective callback handler methods for each event type. When an event is dispatched by the dispatcher, that particular function pointer is invoked in the subsystem. That subsystem statically casts the event object to the appropriate type and then performs the necessary logic that method was designed to do; namely look-up an entity by id and change properties, set dirty flag for state changes so it gets picked up on next game loop, then ends. In short, the components are never accessed externally, only via proxy through events and the component system that knows how to handle those events.
Also what is a good way to manage the event objects produced? They aren't pointers I make them like this:
Event event;
event.type=E_CREDITSSTATE;
event.category=E_GAME;
CEventDispatcher::inst()->sendEvent(event);
That sends to the stateManager (who is registered to listen to game events) an event from the menu state to switch to the credit state. Do I need to delete the event after it gets used or will it go out of scope and disappear itself?
The CEventDispatcher calls all of the IEventHandlers->handleEvent(e) functions in the registration list for that particular category. It's up to the handlers to decide if they ignore the event or not.
Before I get to the event deletion question, the common event dispatch handler method approach above, I personally dislike. It is an easy design pattern none the less and will work, but it typically leads to gigantic switch statements based on some data element that determines how to cast the common event object to a particular type. As I said, it works but not an approach I prefer to support because those methods can get lengthy when you have classes that listen to many events. I tend to use function pointer callbacks instead giving me the flexibility to to know when the function pointer is called that I need to take that base class pointer that I got and statically cast it to event type ABC. It avoids the switch statement concept and (although i haven't ran benchmarks personally), I think the virtual callback is a little less performing than a direct function pointer call. I would certainly consider looking into function pointers for a future pass, but YMMV.
Now for the deleting of events, it depends upon your design; whether your event is immediately dispatched or whether it is queued for dispatch at the next game loop or a future game loop. I use two different methods in my engine to distinguish between events that are to be QUEUED vs SENT/NOTIFY.
The notify() method in my case simply takes the event reference, looks up a function pointer and passes the reference to the function. The function can modify the event parameters as it sees fit and return. The next line in the code that called notify() can inspect the event and maybe get some information that was added by the prior callback; think of it as a glorified callback with return data .
When I invoke the queue() method, I pass the event information the same way as I do to the notify() method; however, the dispatcher makes a copy of the event and stores the copy. The dispatcher does not care whether what I pass is a heap allocated object or a stack allocated object because internally the queue() method always makes a copy and places it's own allocated object into its internal list for dispatch on the next game loop. This way if I passed a pointer into the dispatcher, that pointer is still my responsibility to delete and manage, not the dispatcher. When the dispatcher finally sends that queued event in the future, that allocated object is what the dispatcher is responsible for deleting when it is no longer needed. There are probably other ways to do this that are better, maybe using some form of smart pointers where once the reference reaches 0; it gets deleted automatically, but I'm not at that optimization stage. The point though is who ever creates a pointer should be the one who deletes the pointer. One of the hardest things to manage is who OWNS a pointer .