I am planning to dive into game deving and try some interesting approaches. I can afford experimenting because I do not plan to release a full-blown game anyway, I just want to keep my brain busy between some boring s&%t I program for living.
So I found some interesting articles and forum posts which basically convinced me that component based entity system is something awesome if I implement my entities as simple property bags without behavior at all. Then I can avoid inter-component dependencies, hierarchies and what not else. As the entities are just a bunch of component properties which get added to them as needed, I can easily store the state of my entities in files, SQL, send over network etc.
In such a hypothetical system the entire game behavior and basic systems are implemented in some kind of singleton subsystems. Those subsystems use some mechanism to track when there is any work to do on some particular component. MovementSubsystem, PathfindingSubsystem, AISubsystem and so on. Subsystems care only about entities which have the corresponding components. RenderingSubsystem ignores all entities, which have no mesh, nor sprite, nor light components. MovementSubsystem cares only about the Position component. I guess, you got the idea.
Everything seems pretty clear to me (although I am sure I'll have gazillion questions while implementing this in C++), except scripting.
Let's say, I want my entire game logic to be scripted (with Lua or C#/Mono, I guess). The game engine itself should not know anything about particular game, the engine just can supply some optimized algorithms, like pathfinding, some predefined generic AI algorithms etc.
Now how do I implement the scripting part?
Let's say, I have some ScriptingSubsystem which is a host for all game logic subsystems. To access entire engine from scripts, the ScriptingSubsystem should be as a gateway to all other subsystems. But there should be only one way: game engine itself should never know anything about any particular script which runs inside the ScriptingSubsystem.
Now in a scripting language I can implement game specific subsystems. For example,I have some imaginary CriminalitySubsystem and game entities have a Criminality component which is just a single integer or float property.
When my game initializes, I call ScriptingSubsystem and say: hey, call all the scripted subsystems and pass them all the in-game entities so each subsystem can register the needed components.
CriminalitySubsystem (which is a Lua or C# script) loops through all passed entities and looks: yes, this one has Criminality, I will add it to my processing list.
Or maybe I could use another approach: I can pass an entity without Criminality component, and the script will add this component for me and register the entity.
Now comes the tricky part. The CriminalitySubsystem should somehow detect some events when the entity does something criminal. For example, each time the user (or NPC) triggers Hit action against some other entity, the CriminalitySubsystem increases Criminality value. And when Criminality value reaches some threshold, the CriminalitySubsystem calls PoliceSubsystem (which also is a script) and tells it: "Register this nasty entity as a criminal and start chasing it all over the town!"
So it seems I'll need also some GameActionsSubsystem which can trigger various game-specific high-level actions, like "hit someone", "escape prison" and so on. Obviously, CriminalitySubsystem depends on this GameActionsSubsystem because CriminalitySubsystem needs to know if in the current game loop iteration there was a "hit someone" action. The GameActionsSubsystem should know nothing about CriminalitySubsystem (to avoid recursive dependencies).
Now there is a problem: how should CriminalitySubsystem find out when the Hit event occured? I have two solutions on my mind:
1) some event-listener or pub/sub system with a MessageManager where one subsystem can publish various messages and other subsystems can subscribe to those events.
2) dirtyness flag for each component. At the beginning of the current game loop iteration I set all entities and all components as dirty=false. If some component changes during the current iteration, it gets dirty=true, so the next subsystem in the processing chain can inspect each component and see if it is dirty and needs something done about it.
How those subsystems know, in what order to process the entities? If I use some pub-sub messaging, I guess, I could implement that in the messaging system itself. Let's say, CriminalitySubsystem needs the GameActionsSubsystem to be present and registered before, so I can do the following pseudocode:
Code: Select all
MessageManager::Register(CriminalitySubsystem::GetSingleton(),
GameActionsSubsystem::HIT,
MessageManager::POSITION_AFTER,
CriminalitySubsystem::TYPE_ID);
But if I use dirtyness, there should be a similar chain anyway, so I process Criminality only after the GameActionSubsystem has done its work.
So, is there anyone here, who have experimented which such a component (property bag) based entity system with singleton behavior subsystems? Did you try implement also the scripting part and how does it all tie together, and how did you solve the chaining of dependent subsystems?
Thanks for any ideas.