SimpleLocomotion.cs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. using UnityEngine;
  2. using System.Collections;
  3. namespace RootMotion.Demos {
  4. // The simplest multi-purpose locomotion controller for demo purposes. Can use root motion, simple procedural motion or the CharacterController
  5. public class SimpleLocomotion : MonoBehaviour {
  6. // The character rotation mode
  7. [System.Serializable]
  8. public enum RotationMode {
  9. Smooth,
  10. Linear
  11. }
  12. [Tooltip("The component that updates the camera.")]
  13. public CameraController cameraController;
  14. [Tooltip("Acceleration of movement.")]
  15. public float accelerationTime = 0.2f;
  16. [Tooltip("Turning speed.")]
  17. public float turnTime = 0.2f;
  18. [Tooltip("If true, will run on left shift, if not will walk on left shift.")]
  19. public bool walkByDefault = true;
  20. [Tooltip("Smooth or linear rotation.")]
  21. public RotationMode rotationMode;
  22. [Tooltip("Procedural motion speed (if not using root motion).")]
  23. public float moveSpeed = 3f;
  24. // Is the character grounded (using very simple y < something here for simplicity's sake)?
  25. public bool isGrounded { get; private set; }
  26. private Animator animator;
  27. private float speed;
  28. private float angleVel;
  29. private float speedVel;
  30. private Vector3 linearTargetDirection;
  31. private CharacterController characterController;
  32. void Start() {
  33. animator = GetComponent<Animator>();
  34. characterController = GetComponent<CharacterController>();
  35. cameraController.enabled = false;
  36. }
  37. void Update() {
  38. // Very basic planar method, should use collision events
  39. isGrounded = transform.position.y < 0.1f;
  40. Rotate();
  41. Move();
  42. }
  43. void LateUpdate() {
  44. // Update the camera last
  45. cameraController.UpdateInput();
  46. cameraController.UpdateTransform();
  47. }
  48. private void Rotate() {
  49. if (!isGrounded) return;
  50. // Updating the rotation of the character
  51. Vector3 inputVector = GetInputVector();
  52. if (inputVector == Vector3.zero) return;
  53. Vector3 forward = transform.forward;
  54. switch(rotationMode) {
  55. case RotationMode.Smooth:
  56. Vector3 targetDirection = cameraController.transform.rotation * inputVector;
  57. float angleForward = Mathf.Atan2(forward.x, forward.z) * Mathf.Rad2Deg;
  58. float angleTarget = Mathf.Atan2(targetDirection.x, targetDirection.z) * Mathf.Rad2Deg;
  59. // Smoothly rotating the character
  60. float angle = Mathf.SmoothDampAngle(angleForward, angleTarget, ref angleVel, turnTime);
  61. transform.rotation = Quaternion.AngleAxis(angle, Vector3.up);
  62. break;
  63. case RotationMode.Linear:
  64. Vector3 inputVectorRaw = GetInputVectorRaw();
  65. if (inputVectorRaw != Vector3.zero) linearTargetDirection = cameraController.transform.rotation * inputVectorRaw;
  66. forward = Vector3.RotateTowards(forward, linearTargetDirection, Time.deltaTime * (1f /turnTime), 1f);
  67. forward.y = 0f;
  68. transform.rotation = Quaternion.LookRotation(forward);
  69. break;
  70. }
  71. }
  72. private void Move() {
  73. // Speed interpolation
  74. float speedTarget = walkByDefault? (Input.GetKey(KeyCode.LeftShift)? 1f: 0.5f): (Input.GetKey(KeyCode.LeftShift)? 0.5f: 1f);
  75. speed = Mathf.SmoothDamp(speed, speedTarget, ref speedVel, accelerationTime);
  76. // Moving the character by root motion
  77. float s = GetInputVector().magnitude * speed;
  78. animator.SetFloat("Speed", s);
  79. // Procedural motion if we don't have root motion
  80. bool proceduralMotion = !animator.hasRootMotion && isGrounded;
  81. if (proceduralMotion) {
  82. Vector3 move = transform.forward * s * moveSpeed;
  83. if (characterController != null) {
  84. characterController.SimpleMove(move);
  85. } else {
  86. transform.position += move * Time.deltaTime;
  87. }
  88. }
  89. }
  90. // Reads the Input to get the movement direction.
  91. private Vector3 GetInputVector() {
  92. Vector3 d = new Vector3(
  93. Input.GetAxis("Horizontal"),
  94. 0f,
  95. Input.GetAxis("Vertical")
  96. );
  97. d.z += Mathf.Abs(d.x) * 0.05f;
  98. d.x -= Mathf.Abs(d.z) * 0.05f;
  99. return d;
  100. }
  101. private Vector3 GetInputVectorRaw() {
  102. return new Vector3(
  103. Input.GetAxisRaw("Horizontal"),
  104. 0f,
  105. Input.GetAxisRaw("Vertical")
  106. );
  107. }
  108. }
  109. }