It might not be possible to switch to state tables without a big rework — and if your current structure works fine in your project, it’s probably not worth the effort. In your next project you could try another approach to learn the pros and cons.
Maybe you can have where actors are stored convey their type or behavior(s).
I have a structure reminiscent of an ECS. Conceptually, I define a number of archetypes. Two tables (entities) are of the same archetype if they have the same members and should be updated with the same procedure (have the same behavior), e.g. idle_player_unit or forest_tile. I store all entities of the same archetype in a single array, and by them being in this array determines how they will be processed. On update I iterate over the array and run the same code (system) on each element.
Consequently, in my gamestate table I have a few dozen archetype arrays, storing all the entities currently in the game world.
When an entity is to change behavior, I move it to another archetype array and add/remove/update any relevant members of the table. I have a module function defined for each valid transition, e.g. player_unit_from_idle_to_moving(entity, destination...)
. On update, when iterating over all the idle_player_units, I may call this function for one or more of the entities.
This way I have no need to store behaviors/functions directly on entities.
I do have a few places in my input handling where I store which module to call and with what arguments. It’s something I will try to refactor in the future. But essentially, I create an “interaction” by passing it a reference to the module that will handle the logic response, and the instance/state table to pass to it. E.g. instantiate interaction with act_on_tile.create(presenter_module, presenter_instance)
, and then it calls back with t.presenter_module.act_on_node_sequence(t.presenter_instance...)
.