SimpleCameraController.cs 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. #if ENABLE_INPUT_SYSTEM
  2. using UnityEngine.InputSystem;
  3. #endif
  4. using UnityEngine;
  5. namespace UnityTemplateProjects
  6. {
  7. public class SimpleCameraController : MonoBehaviour
  8. {
  9. class CameraState
  10. {
  11. public float yaw;
  12. public float pitch;
  13. public float roll;
  14. public float x;
  15. public float y;
  16. public float z;
  17. public void SetFromTransform(Transform t)
  18. {
  19. pitch = t.eulerAngles.x;
  20. yaw = t.eulerAngles.y;
  21. roll = t.eulerAngles.z;
  22. x = t.position.x;
  23. y = t.position.y;
  24. z = t.position.z;
  25. }
  26. public void Translate(Vector3 translation)
  27. {
  28. Vector3 rotatedTranslation = Quaternion.Euler(pitch, yaw, roll) * translation;
  29. x += rotatedTranslation.x;
  30. y += rotatedTranslation.y;
  31. z += rotatedTranslation.z;
  32. }
  33. public void LerpTowards(CameraState target, float positionLerpPct, float rotationLerpPct)
  34. {
  35. yaw = Mathf.Lerp(yaw, target.yaw, rotationLerpPct);
  36. pitch = Mathf.Lerp(pitch, target.pitch, rotationLerpPct);
  37. roll = Mathf.Lerp(roll, target.roll, rotationLerpPct);
  38. x = Mathf.Lerp(x, target.x, positionLerpPct);
  39. y = Mathf.Lerp(y, target.y, positionLerpPct);
  40. z = Mathf.Lerp(z, target.z, positionLerpPct);
  41. }
  42. public void UpdateTransform(Transform t)
  43. {
  44. t.eulerAngles = new Vector3(pitch, yaw, roll);
  45. t.position = new Vector3(x, y, z);
  46. }
  47. }
  48. CameraState m_TargetCameraState = new CameraState();
  49. CameraState m_InterpolatingCameraState = new CameraState();
  50. [Header("Movement Settings")]
  51. [Tooltip("Exponential boost factor on translation, controllable by mouse wheel.")]
  52. public float boost = 3.5f;
  53. [Tooltip("Time it takes to interpolate camera position 99% of the way to the target."), Range(0.001f, 1f)]
  54. public float positionLerpTime = 0.2f;
  55. [Header("Rotation Settings")]
  56. [Tooltip("X = Change in mouse position.\nY = Multiplicative factor for camera rotation.")]
  57. public AnimationCurve mouseSensitivityCurve = new AnimationCurve(new Keyframe(0f, 0.5f, 0f, 5f), new Keyframe(1f, 2.5f, 0f, 0f));
  58. [Tooltip("Time it takes to interpolate camera rotation 99% of the way to the target."), Range(0.001f, 1f)]
  59. public float rotationLerpTime = 0.01f;
  60. [Tooltip("Whether or not to invert our Y axis for mouse input to rotation.")]
  61. public bool invertY = false;
  62. #if ENABLE_INPUT_SYSTEM
  63. InputAction movementAction;
  64. InputAction verticalMovementAction;
  65. InputAction lookAction;
  66. InputAction boostFactorAction;
  67. bool mouseRightButtonPressed;
  68. void Start()
  69. {
  70. var map = new InputActionMap("Simple Camera Controller");
  71. lookAction = map.AddAction("look", binding: "<Mouse>/delta");
  72. movementAction = map.AddAction("move", binding: "<Gamepad>/leftStick");
  73. verticalMovementAction = map.AddAction("Vertical Movement");
  74. boostFactorAction = map.AddAction("Boost Factor", binding: "<Mouse>/scroll");
  75. lookAction.AddBinding("<Gamepad>/rightStick").WithProcessor("scaleVector2(x=15, y=15)");
  76. movementAction.AddCompositeBinding("Dpad")
  77. .With("Up", "<Keyboard>/w")
  78. .With("Up", "<Keyboard>/upArrow")
  79. .With("Down", "<Keyboard>/s")
  80. .With("Down", "<Keyboard>/downArrow")
  81. .With("Left", "<Keyboard>/a")
  82. .With("Left", "<Keyboard>/leftArrow")
  83. .With("Right", "<Keyboard>/d")
  84. .With("Right", "<Keyboard>/rightArrow");
  85. verticalMovementAction.AddCompositeBinding("Dpad")
  86. .With("Up", "<Keyboard>/pageUp")
  87. .With("Down", "<Keyboard>/pageDown")
  88. .With("Up", "<Keyboard>/e")
  89. .With("Down", "<Keyboard>/q")
  90. .With("Up", "<Gamepad>/rightshoulder")
  91. .With("Down", "<Gamepad>/leftshoulder");
  92. boostFactorAction.AddBinding("<Gamepad>/Dpad").WithProcessor("scaleVector2(x=1, y=4)");
  93. movementAction.Enable();
  94. lookAction.Enable();
  95. verticalMovementAction.Enable();
  96. boostFactorAction.Enable();
  97. }
  98. #endif
  99. void OnEnable()
  100. {
  101. m_TargetCameraState.SetFromTransform(transform);
  102. m_InterpolatingCameraState.SetFromTransform(transform);
  103. }
  104. Vector3 GetInputTranslationDirection()
  105. {
  106. Vector3 direction = Vector3.zero;
  107. #if ENABLE_INPUT_SYSTEM
  108. var moveDelta = movementAction.ReadValue<Vector2>();
  109. direction.x = moveDelta.x;
  110. direction.z = moveDelta.y;
  111. direction.y = verticalMovementAction.ReadValue<Vector2>().y;
  112. #else
  113. if (Input.GetKey(KeyCode.W))
  114. {
  115. direction += Vector3.forward;
  116. }
  117. if (Input.GetKey(KeyCode.S))
  118. {
  119. direction += Vector3.back;
  120. }
  121. if (Input.GetKey(KeyCode.A))
  122. {
  123. direction += Vector3.left;
  124. }
  125. if (Input.GetKey(KeyCode.D))
  126. {
  127. direction += Vector3.right;
  128. }
  129. if (Input.GetKey(KeyCode.Q))
  130. {
  131. direction += Vector3.down;
  132. }
  133. if (Input.GetKey(KeyCode.E))
  134. {
  135. direction += Vector3.up;
  136. }
  137. #endif
  138. return direction;
  139. }
  140. void Update()
  141. {
  142. // Exit Sample
  143. if (IsEscapePressed())
  144. {
  145. Application.Quit();
  146. #if UNITY_EDITOR
  147. UnityEditor.EditorApplication.isPlaying = false;
  148. #endif
  149. }
  150. // Hide and lock cursor when right mouse button pressed
  151. if (IsRightMouseButtonDown())
  152. {
  153. Cursor.lockState = CursorLockMode.Locked;
  154. }
  155. // Unlock and show cursor when right mouse button released
  156. if (IsRightMouseButtonUp())
  157. {
  158. Cursor.visible = true;
  159. Cursor.lockState = CursorLockMode.None;
  160. }
  161. // Rotation
  162. if (IsCameraRotationAllowed())
  163. {
  164. var mouseMovement = GetInputLookRotation() * Time.deltaTime * 5;
  165. if (invertY)
  166. mouseMovement.y = -mouseMovement.y;
  167. var mouseSensitivityFactor = mouseSensitivityCurve.Evaluate(mouseMovement.magnitude);
  168. m_TargetCameraState.yaw += mouseMovement.x * mouseSensitivityFactor;
  169. m_TargetCameraState.pitch += mouseMovement.y * mouseSensitivityFactor;
  170. }
  171. // Translation
  172. var translation = GetInputTranslationDirection() * Time.deltaTime;
  173. // Speed up movement when shift key held
  174. if (IsBoostPressed())
  175. {
  176. translation *= 10.0f;
  177. }
  178. // Modify movement by a boost factor (defined in Inspector and modified in play mode through the mouse scroll wheel)
  179. boost += GetBoostFactor();
  180. translation *= Mathf.Pow(2.0f, boost);
  181. m_TargetCameraState.Translate(translation);
  182. // Framerate-independent interpolation
  183. // Calculate the lerp amount, such that we get 99% of the way to our target in the specified time
  184. var positionLerpPct = 1f - Mathf.Exp((Mathf.Log(1f - 0.99f) / positionLerpTime) * Time.deltaTime);
  185. var rotationLerpPct = 1f - Mathf.Exp((Mathf.Log(1f - 0.99f) / rotationLerpTime) * Time.deltaTime);
  186. m_InterpolatingCameraState.LerpTowards(m_TargetCameraState, positionLerpPct, rotationLerpPct);
  187. m_InterpolatingCameraState.UpdateTransform(transform);
  188. }
  189. float GetBoostFactor()
  190. {
  191. #if ENABLE_INPUT_SYSTEM
  192. return boostFactorAction.ReadValue<Vector2>().y * 0.01f;
  193. #else
  194. return Input.mouseScrollDelta.y * 0.2f;
  195. #endif
  196. }
  197. Vector2 GetInputLookRotation()
  198. {
  199. #if ENABLE_INPUT_SYSTEM
  200. return lookAction.ReadValue<Vector2>();
  201. #else
  202. return new Vector2(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y")) * 10;
  203. #endif
  204. }
  205. bool IsBoostPressed()
  206. {
  207. #if ENABLE_INPUT_SYSTEM
  208. bool boost = Keyboard.current != null ? Keyboard.current.leftShiftKey.isPressed : false;
  209. boost |= Gamepad.current != null ? Gamepad.current.xButton.isPressed : false;
  210. return boost;
  211. #else
  212. return Input.GetKey(KeyCode.LeftShift);
  213. #endif
  214. }
  215. bool IsEscapePressed()
  216. {
  217. #if ENABLE_INPUT_SYSTEM
  218. return Keyboard.current != null ? Keyboard.current.escapeKey.isPressed : false;
  219. #else
  220. return Input.GetKey(KeyCode.Escape);
  221. #endif
  222. }
  223. bool IsCameraRotationAllowed()
  224. {
  225. #if ENABLE_INPUT_SYSTEM
  226. bool canRotate = Mouse.current != null ? Mouse.current.rightButton.isPressed : false;
  227. canRotate |= Gamepad.current != null ? Gamepad.current.rightStick.ReadValue().magnitude > 0 : false;
  228. return canRotate;
  229. #else
  230. return Input.GetMouseButton(1);
  231. #endif
  232. }
  233. bool IsRightMouseButtonDown()
  234. {
  235. #if ENABLE_INPUT_SYSTEM
  236. return Mouse.current != null ? Mouse.current.rightButton.isPressed : false;
  237. #else
  238. return Input.GetMouseButtonDown(1);
  239. #endif
  240. }
  241. bool IsRightMouseButtonUp()
  242. {
  243. #if ENABLE_INPUT_SYSTEM
  244. return Mouse.current != null ? !Mouse.current.rightButton.isPressed : false;
  245. #else
  246. return Input.GetMouseButtonUp(1);
  247. #endif
  248. }
  249. }
  250. }