Spell of Mastery Rewrite Progress Previously I have split the UI and game objects across multiple tables.
Now I'm refactoring the game logic into systems.
That immediately resulted in about 1/2 of the code being thrown away.
In addition, all these
is_null_pointer(object) ? default_value : field[object]
are now handled by the table code.
And most common null pointer errors are now impossible, since the systems just won't get called on absent fields.
It was really surprising that something as simple playing a 2d animation could be so hard to do right on the first try, when considered in a general context. And it easy to mess up, like making planner depending on the currently playing animation. For example, I had actuator waiting for the animation to reach specific stages. So now I also had to redo all my animation scripts to not including any game logic. And all the online guides on animation systems recommend the hierarchical state machines cargo cult, which is a really bad idea architecturally wise, since it breeds non-uniformity further, requiring maintaining a HSM for each class of entities.
The game logic, which was previously a convoluted spaghetti mess, is now split into a conveyor tree, where each stage depends only on the previous stage:
- Player AI gives orders to entities.
- Planner pursues the order, and issues appropriate actions;
- Actuator, like attack and move from cell to cell.
Optionally it can awaken the planner on action completion;
Everything after actuator is optional and can be turned off for the server side code.
- Animator analyses the actuator's state and determines which animation to play.
Optionally it can awaken the actuator;
- Performer plays specific animation, by providing the frames to renderer.
Optionally it can awaken the animator when the animation finishes;
- Renderer, plays the frame, picked by performer.
For me the additional challenge is the discrete nature of the game, where all entities act inside the quantified time units. And ECS helped to clean up that logic. I.e. while the entity has already consumed the allocated quants, some of the animations, like idle or move, are still expected to play. basically entities walk in place (Final Fantasy Tactics style) to express that they perform movement order. Same way, poisoned units should have poison animation playing.
TODO1: integrating the physics with the actuator actions. I.e. a can a falling unit act? Like activating a parachute?
TODO2: introduce the phased methods, instead of the clunky update_systems.
Basically the below code could be organized as a set of methods like, `entity.motilize phase.each_cycle = ...`
update_systems Me =
update_custom_systems Me
//satellites
for U each(add_cover){unit_}: add_cover U
for U each(add_shadow){unit_}: add_shadow U
for U each(remove_sat){unit_}: remove_sat U
for U each(place_sat){unit_}: place_sat U
//properties
for U each(motilize){unit_}: motilize U
for U each(needs_globals){unit_}: U.add_global_acts
//activation
for U each(active){unit_}: U.do_activation
for U each(goal){unit_}: U.break_idle
for U each(ordered){unit_}: U.break_idle
//physics
for U each(falling){unit_}: update_falling U
//actions
for U each(members_){unit_}: update_squad U
for U each(planning){unit_}: update_planning U
for U each(ordered){unit_}: take_order U
for U each(acting){unit_}: update_acting U
for U each(actpost){unit_}: update_actpost U
for U each(pursued){unit_}: update_pursued U
for U each(enchng){unit_}: update_enchng U
for U each(sqid){unit_}: update_sqid U
for U each(host){unit_}: update_hosted U
//graphics
for U each(animator){unit_}: U.upd_animator
for U each(animated){unit_}: U.upd_animated
for U each(anm_float){unit_}: U.reset_visl
for U each(made_step){unit_}: made_step U //set by upd_animated
//for U each(randidle){unit_}: U.rand_anim_step
for U each(fade_inc){unit_}: U.update_fade
for U each(suffers){unit_}: upd_suffers U
Current Mood: contemplativeCurrent Music: Kuldahar Theme