I’m fairly sure that the title could cause some confusion, so I’ll try to explain to the best of my ability.
I’m working on a game that will require a variety input contexts, and will also include multiplayer. I’m using the New Input System because I wanted to get away from the polling paradigm of the old one, but I’m running into some code structure roadblocks. Since the game is still in the prototype phase and a lot of things might change/be extended, I’m striving to keep the logic as modular and abstract as possible, within reason.
One reason for choosing the new system was that Action Maps can serve as contexts. Right now, I have three entities that are affected by input. I’m going to provide some detail to help you understand exactly what my problem is:
- Player: an FPSController script is responsible for moving the player around and camera looking, while a PlayerInventory component acts as a ‘repository’ for the player’s items and only handles adding/removing, updating quantites etc.
- Weapon: weapons are made from modular C# components that represent different functions (shooting, reloading etc.) and a WeaponController that is only responsible for setup and orchestration – the other components can be swapped for ones that execute different logic (i.e. RifleReload vs ShotgunReload or Hitscan vs. Projectile) using interfaces
- UI: specific UI elements like the inventory UI are kept under a GameObject responsible for their orchestration, enabling/disabling etc. The inventory UI is only responsible for drawing the inventory and listening to events sent by the PlayerInventory script for updating the display.
Before I started the current refactoring process, and for prototyping purposes, I handled input in the simplest way possible: components that needed input to function simply created an instance of the script generated by the input asset (I’m not using the PlayerInput component), enabled the appropriate action maps and subscribed to the appropriate events. Of course, this creates a tangled mess of input code scattered everywhere and now every script with input can enable/disable action maps! I’m fine with input-dependent components listening for events within their own script, but I want the action map/context changes to be handled in a centralized manner.
I also tried the heavy-handed approach: the Player GameObject has a PlayerInputController component that creates a single instance of the generated C# input script. I create a list of private class fields for every input action, get references to the entities (UI, weapon etc.), subscribe their methods inside the PlayerInputController and call the from this location whenever an input event is fired. This creates another problem: I now need a reference to every component that needs input, so I get tight coupling.
I’ve been hitting my head on the wall with this for a while, and I can barely find anything of use online. Most tutorials/articles focus on extremely simple use cases that just cram everything in a Player script and call it a day. If you have a good approach that handles input and separates concerns as cleanly as humanly possible, I’d like to hear it. Thank you for reading.