A game about forced loneliness, made by TACStudios
1using UnityEngine;
2using UnityEngine.InputSystem;
3#if UNITY_EDITOR
4using UnityEditor;
5#endif
6
7// Say you want to distinguish a device not only by its type (e.g. "PS4 Controller")
8// but also by the way it is used. This is a common scenario for VR controllers, for
9// example, where the same type of controller may be used once in the left hand and
10// once in the right hand. However, the need for distinguishing devices in a similar
11// manner can pop up in a variety of situations. For example, on Switch it is used
12// to distinguish the current orientation of the Joy-Con controller ("Horizontal" vs.
13// "Vertical") allowing you to take orientation into account when binding actions.
14//
15// The input system allows you to distinguish devices based on the "usages" assigned
16// to them. This is a generic mechanism that can be used to tag devices with arbitrary
17// custom usages.
18//
19// To make this more concrete, let's say we have a game where two players control
20// the game together each one using a gamepad but each receiving control over half
21// the actions in the game.
22//
23// NOTE: What we do here is only one way to achieve this kind of setup. We could
24// alternatively go and just create one control scheme for the first player
25// and one control scheme for the second one and then have two PlayerInputs
26// each using one of the two.
27//
28// So, what we'd like to do is tag one gamepad with "Player1" and one gamepad with
29// with "Player2". Then, in the actions we can set up a binding scheme specifically
30// for this style of play and bind actions such that are driven either from the
31// first player's gamepad or from the second player's gamepad (or from either).
32//
33// The first bit we need for this is to tell the input system that "Player1" and
34// "Player2" are usages that we intend to apply to gamepads. For this, we need
35// to modify the "Gamepad" layout. We do so by applying what's called a "layout
36// override". This needs to happen during initialization so here we go:
37#if UNITY_EDITOR
38[InitializeOnLoad]
39#endif
40public static class InitCustomDeviceUsages
41{
42 static InitCustomDeviceUsages()
43 {
44 Initialize();
45 }
46
47 [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
48 private static void Initialize()
49 {
50 // Here we register the layout override with the system.
51 //
52 // The layout override is just a fragment of layout information
53 // in JSON format.
54 //
55 // The key property here is "commonUsages" which tells the system
56 // that "Player1" and "Player2" are possible usages applied to devices
57 // using the given layout ("Gamepad" in our case).
58 InputSystem.RegisterLayoutOverride(@"
59 {
60 ""name"" : ""GamepadPlayerUsageTags"",
61 ""extend"" : ""Gamepad"",
62 ""commonUsages"" : [
63 ""Player1"", ""Player2""
64 ]
65 }
66 ");
67
68 // Now that we have done this, you will see that when using the
69 // control picker in the action editor, that there is now a
70 // "Gamepad (Player1)" and "Gamepad (Player2)" entry underneath
71 // "Gamepad". When you select those, you can bind specifically
72 // to a gamepad with the respective device usage.
73 //
74 // Also, you will now be able to *require* a device with the
75 // given usage in a control scheme. So, when creating a control
76 // scheme representing the shared Player1+Player2 controls,
77 // you can add one "Gamepad (Player1)" and one "Gamepad (Player2)"
78 // requirement.
79 //
80 // You can see an example setup for how this would look in an
81 // .inputactions file in the TwoPlayerControls.inputactions file
82 // that is part of this sample.
83 }
84}
85
86// However, we are still missing a piece. At runtime, no gamepad will
87// receive either the "Player1" or the "Player2" usage assignment yet.
88// So none of the bindings will work yet.
89//
90// To assign the usage tags to the devices, we need to call
91// InputSystem.AddDeviceUsage or SetDeviceUsage.
92//
93// We could set this up any which way. As a demonstration, let's create
94// a MonoBehaviour here that simply associates a specific tag with a
95// specific gamepad index.
96//
97// In practice, you would probably want to do the assignment in a place
98// where you handle your player setup/joining.
99public class CustomDeviceUsages : MonoBehaviour
100{
101 public int gamepadIndex;
102 public string usageTag;
103
104 private Gamepad m_Gamepad;
105
106 protected void OnEnable()
107 {
108 if (gamepadIndex >= 0 && gamepadIndex < Gamepad.all.Count)
109 {
110 m_Gamepad = Gamepad.all[gamepadIndex];
111 InputSystem.AddDeviceUsage(m_Gamepad, usageTag);
112 }
113 }
114
115 protected void OnDisable()
116 {
117 // If we grabbed a gamepad and it's still added to the system,
118 // remove the usage tag we added.
119 if (m_Gamepad != null && m_Gamepad.added)
120 InputSystem.RemoveDeviceUsage(m_Gamepad, usageTag);
121 m_Gamepad = null;
122 }
123}