nfagerlund / bevy-tablestakes

takin a new thing for a spin
0 stars 0 forks source link

Player state machine design #4

Closed nfagerlund closed 1 year ago

nfagerlund commented 1 year ago

(and/or similar kinds of entity state machines)

nfagerlund commented 1 year ago

Something occurred to me earlier -- I could just do the same idea as with inputs for handling the state transitions robustly. The current state can modify the state component to indicate it's due for a transition, and then I can have one system in PostUpdate that processes that so the next tick will use the new state.

(the comment about inputs is: I moved input processing to a PreUpdate system and everything else just reads the resource instead of polling inputs.)

nfagerlund commented 1 year ago

Currently where I've got it is that there's a "transition out" system per state, because I couldn't come up with an ergonomic way to make a unified one given the type requirements. (Tried doing some shit where I pre-construct a Command, box it, and put it in a vec, but that was a non-starter for some reason once it came down to getting it out and doing anything with it.

I reworked the movement to be like,

That's working ok for now, I think. State machine design stuff will just continue to percolate. The next thing I ran into was the question of how to deal with drawing shadows and fake-height Y offsets for objects in the air! (For the bonk state.)

nfagerlund commented 1 year ago

Ok, ready to do the bonk state, and on letting it percolate, I'm not at all happy with my state transitions logic here.

I'm starting to think I should be using events instead! Will investigate.

nfagerlund commented 1 year ago

Ok, so

Each event can be consumed by multiple systems, in parallel, with consumption tracked by the EventReader on a per-system basis.

As for how to integrate that into a flow of state transitions, hmmm.

nfagerlund commented 1 year ago

Right now the transitions I have going on are:

(and then more in the original project)

Hmm, makes me wonder if collision should be an event too, rather than a prop on Movement.

nfagerlund commented 1 year ago

Uh, this situation has mutated outlandishly since last I wrote here. Events ended up being somewhat unstable for state transitions.

nfagerlund commented 1 year ago

And I ended up using timers instead, for the most part. 🤔

nfagerlund commented 1 year ago

OK, so I was previously using one sparse component per state, because it allowed me to check the current player state in the system query. (The type system can't manipulate enum values, only types.)

But the resulting system code was actually much more complicated and brittle than it would have been otherwise (careful gardening of command sync points, need to manually ensure mutually exclusive states exclude each other, etc.), and it was much easier to get a handle on what was happening after I switched the state to be a single enum (with an optional queued-up "next" instance) inside a PlayerStateMachine component.

I think I've now hit the point where I've learned plenty of stuff and I won't learn more by designing without a use case. So let's close this ticket and figure out how to make something playable next.