Two finite state machines might determine how a function is handled. Ways to handle this?

Hey guys, this question involves way more code than can easily be shown here, so I’ve tried to describe this as concisely as I can with a graphic below.

The situation is like this:

When GameState changes, the PlayerState is watching and will also change. But PlayerState can also be changed from input. What changes input can make happen depend on the Game State though. For instance:

If GameState is “InGame” and PlayerState is “Movement”, then input of ESC would change PlayerState to UI and make the pause menu appear. This is all handled in the PlayerState.

Suppose the same situation, except the GameState is “Menu”. In that case, we are in the Main Menu, so ESC would behave differently.

So it is a situation where we get some new states that are the product of GameState + PlayerState. Effectively, there are new states that are getting created, except they are not defined clearly. I have PlayerStates each wrapped in an object, but I cannot wrap the unique cases where GameState:A + PlayerState:A is different from GameState:B + PlayerState:A. That would get out of hand pretty fast.

The simple obvious solution is just to have the GameState enumerator filter certain input cases. But that has zero modularity and would not scale well.

It makes me feel like, there is probably some common programmer techniques to handle a situation like this, but I don’t know how to properly describe the situation to find some examples. Or perhaps I am mishandling these state machines in a weird way to begin with.

Any advice is appreciated.

I think the community rubber ducky has helped me out here again.

After typing this out I realize that I have just missed the most obvious solution, and didn’t see what the actual problem is:

I am overlapping responsibilities of the state machines.

GameState is not responsible for player input. So, it should not be considered in that at all.

PlayerState can, in some situations, be overridden by the GameState. But that is easy - I just make a couple extra Player States for those situations, e.g. “MainMenuState”.

This way PlayerState retains responsibility on input and there doesn’t need to be any conditional checks, switch statements, etc. I suppose the end result is not very different from using some enumerator switches - in a way the PlayerState is linked to the Gamestate in that changes in the GameStates will necessitate updating the player states as well, however I find those sorts of changes easier to make if I am dealing with objects rather than having to pilfer through long node chains.