Using Unity's new Input System


Welcome to the first dev blog of 2020 (and Happy Lunar New Year)! We're talking about something 'new' today for the new year, Unity's new Input System!

If you're a Unity developer, you probably know that Unity is rolling out a new Input System to replace its current one, which is rather clunky to use. I'm talking about this one.

This blog is longer than usual, so I'll split it into 2 sections in case you want to skip ahead. First section is about how I came to use the system. Second section is about how I set the system up for local multiplayer.

Me and the system

I originally worked with the old system where I had to create an entry for every input axis, for every controller.

oldinput.png

It's not too great because it meant any control scheme changes needed to be applied manually to each related axis for all controllers. For example, if I'd like to map Right Trigger to Attack instead of West Button, I'd have to modify 8 entries, those two buttons for four controllers. It's also quite easy to make mistakes when editing axes due to it just being text boxes with no validation.

However, only a couple weeks into development of OverGem, I heard about Unity's new Input System, which sounded like it will get rid of all of the problems with the old system.

I jumped on it immediately.

It was around May 2019, I think, the new Input System preview package was only at version 0.1.1 or some low number. Although initially looking really good, it was actually rather buggy.

newsystem.png

I encountered issues like bindings not working, controllers not assigned correctly etc. I eventually decided to continue development with the old system until the new system became more stable.

Around November, I picked up the new system again after hearing about how usable it became. To my delight, they were right, there was even documented API.

Setup for local multiplayer

I wanted to share how I set up the new Input System for local multiplayer, which I hope you'll find useful if you're a developer.

As above, you can see my Action Map for Players. Unity's new Input system allows me use this same mapping for every connected device , where as the old one required me to create entries for every device. It even allows for platform agnostic mapping (meaning I don't have to remap for different consoles).

For each Player, Unity's new Input System requires the representing GameObject, which I will call the Player_GameObject, to have the Player Input component . The recommended setup is that when a device is connected, we would spawn a Player_GameObject Prefab. There is a problem with this approach. In local multiplayers made with Unity, you probably want the "Player Joining" phase to be in a different Scene to the actual Game Scene. So my options were:

  1. Spawn the Player_GameObject Prefab, which has the PlayerInput component, in the Menu/Player-joining Scene and make it DontDestroyOnLoad()
  2. Merge the Menu/Player-joining Scene and Game Scene into a single Scene.

The problem with both these approaches is that I'd have to maintain the state for either the Player_GameObjects (1) or the Scene (2). If something goes into a bad state, its much more effort to untangle that. I prefer a more stateless approach.

What I did instead was spawn a GameObject that acted as a "Player Input Relay" every time a device connected in the Menu/Player-joining Scene, and made it persistent (DontDestroyOnLoad()). This GameObject would have the PlayerInput component.

relay.png

This allows me to abstract the controls away from the Player_GameObject. The PlayerInputRelay has no state, it doesn't need to know anything besides which player its controlling in the Game Scene. I can now just spawn the Player_GameObject Prefabs in the Game Scene without making it persistent.

I just need to map the PlayerInputRelays to a Player_GameObject for every game round.

I already have a static class that I use to store global information about OverGem. I added code to this class to also store information about the players.

Then, in the Game Scene, I'd have a script doing this

The Player_GameObject having this script

After every round, the Player_GameObject will be destroyed, but thats totally fine! We don't have to do anything extra between rounds like moving them out of the viewport, cleaning animation state or resetting any stats.

Hope you find that useful! See you in the next post.

Leave a comment

Log in with itch.io to leave a comment.