After various attempts, careful considerations and long meditations under an authentic ancient japanese sakura from the naruto period... I decided to roll my own lolECS.
It does what I need, which is nice, though it is not internally as optimized as Artemis.
- Uses Universaly Unique Identifiers which auto-instantly solves the id problem mentionned in the previous post : it allows insertion of foreign entities without ids collision headaches.
- Uses a messaging system to communicate : strong decoupling - systems don't have to know each others, they just send and listen to messages they are interested in.
- Systems are abstract and treated like services you can plug concrete systems in a static/singleton class GameSystems : very easy to implement client and server - they have different implentations of the same set of systems. (eg: a client would not have the same physics system implementation than the server).
- Commands are special kind of messages : they are actions that need to be executed in the game world - this will prove very useful for debugging, console commands, scripting (if need to) and more importanly networking (the server will send mostly commands to clients).
I could throw some UML diagram but the structure is pretty much like the in the previous episode.
The only thing interesting is the specialized Postman system which handles messaging and subscribing for other systems.
RS2 ECS in practice
I create entities with the EntityManager, then build them via an EntityFactory which is a registry of EntityBuilders. For instance the crate builder knows what component to add and how to set them up to make an entity that behaves and look like a crate. I prefer the factory approach to prototypes/clones/templates as you can more easily add variations or conditional building (eg: not all crates may look or weight the same). The concrete builders are specific to RS2, but the Factory, ECS and most components and systems are part of my engine which I hope to re-use for other awesome games.
In code, creating, building, spawning and shooting a crate from the camera look like this:
|CrateBuilder : building crates since overused meme date.|
|Would someone please insert an original caption here? No caption no fun.|
Note the use of command messages to spawn and shoot the entity.
And the result when I shoot a bunch of crates at a wall:
|"Advanced Crate Shooting" game or "Blocky Zombies" game? Make up your mind damn it!|
Note that the crates are savagely stacked, as we now have real ultimate physics(*) thanks to jbullet. It will be fun to collapse a bunch of crates on unsuspecting npcs :p
There is negligible fps loss when the crates are at rest, but a noticeable drop in fps when a lot of crates are moving and colliding. We'll see how it runs in a real game situation.
If you don't know what BTs are you can find some articles there.
They are often presented like more advanced or specialized HTN/HFSMs, but to me they remind me a lot of LISP program trees. Which leads neatly to the idea of using genetic programming to evolve AIs. Surely someone will or has already catch on that!?
Anyway for RS2 AI I'm considering using behavior trees. So I designed and implemented a Behavior Tree package for my engine.
|Behavior Tree. UML you see. Haiku captionee.|
(Diagram made with DIA)The only things of note are :
- the use of a generic IBtContext which :
- allows one instance of a behavior tree to be shared for many usages (similar to a flyweight pattern).
- allows to narrow the context for concrete uses.
- a clear separation of Terminals (leafs) vs Composites (inner nodes) and Conditions (predicates) vs Actions.
Since I implemented a generic BT package, I can use it for other purposes. For instance I could use BTs for scripting some entities (doors, levers, whatnot). This would fit nicely into a CpBehaviorTree Component :D
(*) which as you may know is functionaly equivalent to Real Ultimate Power but applied to games. Man, this gets me so pumped!
Day 47 update and exercise for the reader: There are two big flaws in this BT design, which I have now fixed. They would produce incorrect behavior at runtime. Can you spot them? Hint: context.
End of post.