Friday, November 15, 2019

xna - A pattern for a contextual InputState in a Game State Management architecture


Context of the question :



When developing a game using Game State Management I came across a problematic when it came to handling user input : I want my game to retrieve user input a single way, but to handle it in a completely different way, depending on the context.


For example, the [Up] key will always mean "Menu Up" when you're in a menu, but if you're in the game, it might do different things, depending on the key bindings. Another difference would be, for example, that in a menu, a .5sec KeyDown on a key should be interpreted as a single command, but when you're in game, a .5sec KeyDown should often be seen as a .5sec movement / burst / charge shot / etc...


Then way I though about to achieve this result is the following :



  • Have an InputState class that keeps the current and previous Keyboard/Gamepad input states, just like the usual InputState class. Have this InputState class implement all the methods I would need in all the different contexts.

  • Create an Interface per context. For example, IMenuInputState, IGameInputState, ICutsceneInputState, etc. These interfaces would only contain the method definitions related to the context.

  • Have the InputState implement all the I[...]InputState interfaces. If two or more context need the same method, the same implementation would be used.

  • In the ScreenManager's Update method, the InputState would be Updated, but depending on which screen must handle the InputState, a different I[...]InputState would be sent. Even though the screen could access the other methods by casting the interface, only the contextual methods would directly be usable.


My question is the following : Is my idea a proper / common way of handling this issue?



If it is, could you tell me the name of that "pattern" or direct me to some online resources so I can read on that and avoid the known pitfalls. If it's not, how would you suggest I handle the problem?


Note: I know this question is borderline since the answer is partially subjective but I'd appreciate some help on this issue since I think it's a critical decision in my project.



Answer



If I am understanding, then you are saying that you will have a class called InputState that implements many interfaces. Then, other classes should never use InputState, but rather, pick an interface that applies to them.


With this model, you will be losing the advantages of inheritance. All of the code will be in one class, InputState, and the way of accessing that class becomes less clear. These kinds of statements should be a red flag in object-oriented languages:



Have this InputState class implement all the methods I would need in all the different contexts.



How about something like this:




  • InputState receives all inputs and reports on them

  • ContextualInput is a class which defines all of the shared contextual methods

  • MenuInput, GameInput, CutsceneInput all extend ContextualInput and have context-specific methods


InputState will only have general methods such as InputState.isKeyHeld(), InputState.getMousePosition(), or InputState.getAccelerometer().


ContextualInput holds a reference to the InputState object, which can be easily swapped out when you want to do testing and supply fake user input. It can also have methods that are shared among all contextual inputs, such as ContextualInput.getLastAction().


Each of the classes that extend ContextualInput implement their own methods that are completely abstracted from the way they are triggered. You could use a publish/subscribe pattern for other classes to be notified of these events:



  • MenuInput.onMenuOpen()

  • CutsceneInput.onAdvanceSlide()


  • GameInput.onCharacterJump()


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...