CinemachineInputProvider.cs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. #if CINEMACHINE_UNITY_INPUTSYSTEM
  2. using System.Linq;
  3. using UnityEngine;
  4. using UnityEngine.InputSystem;
  5. using UnityEngine.InputSystem.Users;
  6. namespace Cinemachine
  7. {
  8. /// <summary>
  9. /// This is an add-on to override the legacy input system and read input using the
  10. /// UnityEngine.Input package API. Add this behaviour to any CinemachineVirtualCamera
  11. /// or FreeLook that requires user input, and drag in the the desired actions.
  12. /// If the Input System Package is not installed, then this behaviour does nothing.
  13. /// </summary>
  14. [HelpURL(Documentation.BaseURL + "manual/CinemachineAlternativeInput.html")]
  15. public class CinemachineInputProvider : MonoBehaviour, AxisState.IInputAxisProvider
  16. {
  17. /// <summary>
  18. /// Leave this at -1 for single-player games.
  19. /// For multi-player games, set this to be the player index, and the actions will
  20. /// be read from that player's controls
  21. /// </summary>
  22. [Tooltip("Leave this at -1 for single-player games. "
  23. + "For multi-player games, set this to be the player index, and the actions will "
  24. + "be read from that player's controls")]
  25. public int PlayerIndex = -1;
  26. /// <summary>If set, Input Actions will be auto-enabled at start</summary>
  27. [Tooltip("If set, Input Actions will be auto-enabled at start")]
  28. public bool AutoEnableInputs = true;
  29. /// <summary>Vector2 action for XY movement</summary>
  30. [Tooltip("Vector2 action for XY movement")]
  31. public InputActionReference XYAxis;
  32. /// <summary>Float action for Z movement</summary>
  33. [Tooltip("Float action for Z movement")]
  34. public InputActionReference ZAxis;
  35. /// <summary>
  36. /// Implementation of AxisState.IInputAxisProvider.GetAxisValue().
  37. /// Axis index ranges from 0...2 for X, Y, and Z.
  38. /// Reads the action associated with the axis.
  39. /// </summary>
  40. /// <param name="axis"></param>
  41. /// <returns>The current axis value</returns>
  42. public virtual float GetAxisValue(int axis)
  43. {
  44. if (enabled)
  45. {
  46. var action = ResolveForPlayer(axis, axis == 2 ? ZAxis : XYAxis);
  47. if (action != null)
  48. {
  49. switch (axis)
  50. {
  51. case 0: return action.ReadValue<Vector2>().x;
  52. case 1: return action.ReadValue<Vector2>().y;
  53. case 2: return action.ReadValue<float>();
  54. }
  55. }
  56. }
  57. return 0;
  58. }
  59. const int NUM_AXES = 3;
  60. InputAction[] m_cachedActions;
  61. /// <summary>
  62. /// In a multi-player context, actions are associated with specific players
  63. /// This resolves the appropriate action reference for the specified player.
  64. ///
  65. /// Because the resolution involves a search, we also cache the returned
  66. /// action to make future resolutions faster.
  67. /// </summary>
  68. /// <param name="axis">Which input axis (0, 1, or 2)</param>
  69. /// <param name="actionRef">Which action reference to resolve</param>
  70. /// <returns>The cached action for the player specified in PlayerIndex</returns>
  71. protected InputAction ResolveForPlayer(int axis, InputActionReference actionRef)
  72. {
  73. if (axis < 0 || axis >= NUM_AXES)
  74. return null;
  75. if (actionRef == null || actionRef.action == null)
  76. return null;
  77. if (m_cachedActions == null || m_cachedActions.Length != NUM_AXES)
  78. m_cachedActions = new InputAction[NUM_AXES];
  79. if (m_cachedActions[axis] != null && actionRef.action.id != m_cachedActions[axis].id)
  80. m_cachedActions[axis] = null;
  81. if (m_cachedActions[axis] == null)
  82. {
  83. m_cachedActions[axis] = actionRef.action;
  84. if (PlayerIndex != -1)
  85. m_cachedActions[axis] = GetFirstMatch(InputUser.all[PlayerIndex], actionRef);
  86. if (AutoEnableInputs && actionRef != null && actionRef.action != null)
  87. actionRef.action.Enable();
  88. }
  89. // Update enabled status
  90. if (m_cachedActions[axis] != null && m_cachedActions[axis].enabled != actionRef.action.enabled)
  91. {
  92. if (actionRef.action.enabled)
  93. m_cachedActions[axis].Enable();
  94. else
  95. m_cachedActions[axis].Disable();
  96. }
  97. return m_cachedActions[axis];
  98. // local function to wrap the lambda which otherwise causes a tiny gc
  99. InputAction GetFirstMatch(in InputUser user, InputActionReference aRef) =>
  100. user.actions.First(x => x.id == aRef.action.id);
  101. }
  102. // Clean up
  103. protected virtual void OnDisable()
  104. {
  105. m_cachedActions = null;
  106. }
  107. }
  108. }
  109. #else
  110. using UnityEngine;
  111. namespace Cinemachine
  112. {
  113. /// <summary>
  114. /// This is an add-on to override the legacy input system and read input using the
  115. /// UnityEngine.Input package API. Add this behaviour to any CinemachineVirtualCamera
  116. /// or FreeLook that requires user input, and drag in the the desired actions.
  117. /// If the Input System Package is not installed, then this behaviour does nothing.
  118. /// </summary>
  119. [AddComponentMenu("")] // Hide in menu
  120. public class CinemachineInputProvider : MonoBehaviour {}
  121. }
  122. #endif