I'm quite early in development for a concept I've been working on, and I've decided to use Pushdown Automata (PDA) to handle input and states for both the player character and for more complex NPCs with AI.
My question does require some set up, so sorry for the wall of text:
I don't, at this moment, have a pushdown automata implementation for my platform of choice, which is JavaScript. What I do have is the wonderful machina.js[1] . I'm currently trying to decide how best to extend Machina to serve my needs, and I'm a little stuck on the solution.
The simplest implementation I could think of would be to simply extend the base machina.FSM to include a stack, which for JS can simply be an array, and include pushing and popping functions that operate at the FSM level.
This shoves a lot of the implementation details over to the state transition definitions and functions, since the internals of machina.js don't recognize the stack and don't use it to determine state transitions. I'm okay with this because that means I won't be breaking the middleware trying to get it to work, but I still want to "wrap" my implementation up nicely so all the PDA-related stuff isn't handled in places it shouldn't be.
Thing is, I don't need the stack to operate independently of state. I'd like for my stack to simply be the list of states that we came from (I assume this is common for games).
My intended "model" for this is to have states either explicitly transition into a new one through a push, or to have a state "expire" or otherwise become invalid, at which point the PDA starts popping states off the stack until it finds something that the old state is allowed to transition into.
Eg. My player character is idle. I then start shooting, which will cause "idle" to get pushed onto the stack and the current state to be "shooting". While I am shooting, however, I get hit by an attack that causes "stunned". "Shooting" gets pushed onto the stack, and "stunned" is the current state. "Stunned" is on a timer, of course, and once it is over, the automaton looks at the top symbol of the stack. There is no transition from "stunned" to "shooting", so "shooting" gets discarded and the next pop gives us "idle", which is a valid state to transition into from "stunned", so the game takes me from "stunned" directly to "idle" and we can continue on.
I'm concerned about the integrity of my solution. Instead of transitions causing stack manipulation as a matter of bookkeeping, I want to use stack manipulation as the determining factor for transitions. This way, I don't need the transitions to become aware of what's going on with the stack. It becomes the responsibility of the logic around the stack to find the right transitions, and the transitions don't need to know about it at all. I still need to define all the valid transitions and whatnot, but my feeling is that this "winding/unwinding" model will let me be more expressive and spend less time defining new states or state transitions when they come up.
Everything about pushdown automata that I've seen does it the other way, with transitions being stack-aware and explicitly pushing and popping... but a lot of that content is strongly academic, and what matters isn't that it's theoretically correct, but that it works.
I realize that this restriction may make my implementation strictly less powerful than a real PDA. Is there a very good reason why I shouldn't do it this way? I'd hate to do a bunch of work and then find out that I screwed up and there is no way to describe an operation I want to do in terms of the psuedo-Pushdown Automaton that I've created.
Alternatively, if you know of a robust PDA implementation in JS that is FOSS or at least useable for a project that may or may not be commercial, or a different forum I should post to, please let me know!