Hey all,
I know this is a topic that I have brought up before, but I wanted some recent input on design. Consider the topic of creating a platformer project, like mario, but where mario's abilities and behaviors are dynamically altered based on various factors, such as equipment.
For those who program, (For me, c# in unity or monogame), I would typically create a character handler that would handle states and delegate which particular behavior should have control over the character (run, walk, jumping, moving in air, wall sliding, etc...). When a a new ability is added to the character, it would register its various functions on actions/callbacks that are triggered by the handler. Some people use state machines to handle the transitions, but I preffered a softer machine where multiple states run at the same time and can share control (for example, sometimes you want the "horizontal movement" ability to execute while "rocket jump" is executing.
Its nice, because then adding a "power jump that charges while ducking" allows the code for that ability to live in one place, instead of having to be distributed around a giant if/else tree in various locations. You just register into the appropriate action/callback. In this case, the handler would call any ability that has registered with the particular input/state conditions that result in duck being true, and the power jump would charge.
Ideally, these abilities all inherit from some base class that handles the boilerplate registration and callbacks. This is easier to manage with polymorphism and class imo, but I suspect there is an elegant way to handle this in c3.
Elegance = Easily scalable, maintainable, and changeable code that is the easiest to read and work with.
Building such a system out with c3 function maps doesn't seem the right way to go, as it clutters the global name space (Not ELEGANTO!) and has some performance issues. Custom actions is a better solution, but without dynamic routing, you have to wrap up abilities in objects. So even though you have a mario characterHandler object, his jump logic is actually being processed by a custom action on a "BehaviorJump" object that is in a family of CharacterAbilities. The CharacterHandler familily handles a list of UIDs to its abilities , and simply calls the type of action wanted.
This current solution has got a lot of UID picking, and is verbose. Alot of boilerplate. But it is as elegant as I can imagine atm.
You can easily build up a giant spaghetti mess of character abilities all being togled on and off by boolean trees, but that gets to be a nightmare once you start trying to add dynamic abilities that can be picked up with an item or activated in specific situations. I know some famous gamemakers have said, screw it, and then just made a mess (celeste's character controler is a grand example of this), but the fact is, a working mess is only a problem if you have to go in and change things.
AND the whole point of the project is to provide a reference for design patterns for those building projects along SOLID principles, so the matter is somewhat academic.