CustomDeviceUsages.cs 4.9 KB

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