Home‎ > ‎

Rabbit Holes, Entity Systems, and me

posted Jun 12, 2011, 2:34 PM by Alec Lanter
Well, I was right about the entity system being a rabbit hole.  I've spent more of my free programming time in the past two weeks reading and re-reading whitepapers and design documents than I have thinking about the goals of the game.  On the plus side, though, I've got a much better understanding of what I want to happen in the underlying framework of the game, and I think I've got a basic system that will be usable in a couple of other projects that I want to explore after this one.

We're sticking with a couple of the original design concepts for the Infinity System.  It is still entity based, with the core "thing" in the game being nothing more than an ID reference into an entity repository.  This ID will have components attached to it, which are defined as nothing more than containers of variables with no actual logic.  Game logic still lives mainly in black-box objects referred to as "game systems".  Each game system handles a specific task, such as AI pathfinding, or movement, or combat.

At that point, though, the similarities end.  To drive game logic, each system registers a set of events that it responds to.  An event is basically an entity template that defines one or more components that contain the data for that particular type of event.  Once the source of the event creates and populates the event entity, that event is passed through the event handlers on the entities involved in the event.  Those handlers are allowed to modify data on the event's components, fire new events of their own, or respond that they have handled the event.  Once the handlers are done, if the event is still unresolved, then the system that registered as the generic handler for that event is notified and resolves the event.  This allows entity specifications to modify the way game systems apply their logic to a given entity.

For example, suppose a medium freighter is firing its laser turret on an attacking pirate fighter.  A LaserAttack event is raised, with the freighter as the actor, and the pirate ship as the target.  The event's component also specifies that the source of the attack is the laser turret entity installed on the freighter.  The combat system is given the event, and then checks for a defined handler on each entity in a specified order.  The freighter first, then the turret, then the pirate.  The freighter might adjust the to-hit chance based on the fact that it's not built for combat, the turret simply ignores the event, and the pirate might adjust the to-hit chance again due to the maneuverability of the target ship.  Since none of those handlers responded that they handled the event, the combat system is now free to finish resolving the attack by making a check on the attack's to-hit value.  If it succeeds, it would then fire a WeaponHit event with the turret as the actor and the pirate as the target.  The turret sets the damage value of the hit, and the pirate sets its shield value.  The combat system is then free to either directly apply damage to the pirate (potentially firing a ShipDestroyed event), or to break the resolution of damage down further by firing one or more Damage events.

The power of this system lies in the realization that another type of target ship may have a handler for WeaponHit that checks the power of the source laser, and simply aborts the hit if the laser isn't powerful enough to damage it.  Similarly, a  special laser turret that contains an auto-targeting computer may register a handler for LaserAttack that automatically fires WeaponHit without a skill check and informs the game system that the attack event has already been resolved, thus bypassing hit avoidance of the target ship entirely.  All of this happens without actually modifying the code that handles the generic case of a laser weapon fired at another ship.

Enough for now.  I'm going to go work on the design document a bit before I have to mow the lawn. :)