PlayerControllerScript.cs 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. using UnityEngine;
  2. using Mirror;
  3. namespace Mirror.Examples.CharacterSelection
  4. {
  5. [RequireComponent(typeof(CapsuleCollider))]
  6. [RequireComponent(typeof(CharacterController))]
  7. [RequireComponent(typeof(NetworkTransformUnreliable))]
  8. [RequireComponent(typeof(Rigidbody))]
  9. public class PlayerControllerScript : NetworkBehaviour
  10. {
  11. public enum GroundState : byte { Jumping, Falling, Grounded }
  12. [Header("Avatar Components")]
  13. public CharacterController characterController;
  14. [Header("Movement")]
  15. [Range(1, 20)]
  16. public float moveSpeedMultiplier = 8f;
  17. [Header("Turning")]
  18. [Range(1f, 200f)]
  19. public float maxTurnSpeed = 100f;
  20. [Range(.5f, 5f)]
  21. public float turnDelta = 3f;
  22. [Header("Jumping")]
  23. [Range(0.1f, 1f)]
  24. public float initialJumpSpeed = 0.2f;
  25. [Range(1f, 10f)]
  26. public float maxJumpSpeed = 5f;
  27. [Range(0.1f, 1f)]
  28. public float jumpDelta = 0.2f;
  29. [Header("Diagnostics - Do Not Modify")]
  30. public GroundState groundState = GroundState.Grounded;
  31. [Range(-1f, 1f)]
  32. public float horizontal;
  33. [Range(-1f, 1f)]
  34. public float vertical;
  35. [Range(-200f, 200f)]
  36. public float turnSpeed;
  37. [Range(-10f, 10f)]
  38. public float jumpSpeed;
  39. [Range(-1.5f, 1.5f)]
  40. public float animVelocity;
  41. [Range(-1.5f, 1.5f)]
  42. public float animRotation;
  43. public Vector3Int velocity;
  44. public Vector3 direction;
  45. private Transform cameraObj;
  46. public Transform cameraTarget;
  47. private SceneReferencer sceneReferencer;
  48. private CharacterSelection characterSelection;
  49. public void Awake()
  50. {
  51. if (characterController == null)
  52. characterController = GetComponent<CharacterController>();
  53. if (characterSelection == null)
  54. characterSelection = GetComponent<CharacterSelection>();
  55. // Override CharacterController default values
  56. characterController.enabled = false;
  57. characterController.skinWidth = 0.02f;
  58. characterController.minMoveDistance = 0f;
  59. GetComponent<Rigidbody>().isKinematic = true;
  60. this.enabled = false;
  61. }
  62. public override void OnStartAuthority()
  63. {
  64. characterController.enabled = true;
  65. this.enabled = true;
  66. #if UNITY_2021_3_OR_NEWER
  67. sceneReferencer = GameObject.FindAnyObjectByType<SceneReferencer>();
  68. #else
  69. // Deprecated in Unity 2023.1
  70. sceneReferencer = GameObject.FindObjectOfType<SceneReferencer>();
  71. #endif
  72. cameraObj = sceneReferencer.cameraObject.transform;
  73. }
  74. public override void OnStopAuthority()
  75. {
  76. this.enabled = false;
  77. characterController.enabled = false;
  78. }
  79. void Update()
  80. {
  81. if (cameraObj && characterSelection)
  82. {
  83. characterSelection.floatingInfo.forward = cameraObj.transform.forward;
  84. }
  85. if (!Application.isFocused) return;
  86. if (!characterController.enabled)
  87. return;
  88. HandleTurning();
  89. HandleJumping();
  90. HandleMove();
  91. // Reset ground state
  92. if (characterController.isGrounded)
  93. groundState = GroundState.Grounded;
  94. else if (groundState != GroundState.Jumping)
  95. groundState = GroundState.Falling;
  96. // Diagnostic velocity...FloorToInt for display purposes
  97. velocity = Vector3Int.FloorToInt(characterController.velocity);
  98. if (cameraObj != null)
  99. {
  100. cameraObj.position = cameraTarget.position;
  101. cameraObj.rotation = cameraTarget.rotation;
  102. }
  103. }
  104. // TODO: Turning works while airborne...feature?
  105. void HandleTurning()
  106. {
  107. // Q and E cancel each other out, reducing the turn to zero.
  108. if (Input.GetKey(KeyCode.Q))
  109. turnSpeed = Mathf.MoveTowards(turnSpeed, -maxTurnSpeed, turnDelta);
  110. if (Input.GetKey(KeyCode.E))
  111. turnSpeed = Mathf.MoveTowards(turnSpeed, maxTurnSpeed, turnDelta);
  112. // If both pressed, reduce turning speed toward zero.
  113. if (Input.GetKey(KeyCode.Q) && Input.GetKey(KeyCode.E))
  114. turnSpeed = Mathf.MoveTowards(turnSpeed, 0, turnDelta);
  115. // If neither pressed, reduce turning speed toward zero.
  116. if (!Input.GetKey(KeyCode.Q) && !Input.GetKey(KeyCode.E))
  117. turnSpeed = Mathf.MoveTowards(turnSpeed, 0, turnDelta);
  118. transform.Rotate(0f, turnSpeed * Time.deltaTime, 0f);
  119. }
  120. void HandleJumping()
  121. {
  122. // Handle variable force jumping.
  123. // Jump starts with initial power on takeoff, and jumps higher / longer
  124. // as player holds spacebar. Jump power is increased by a diminishing amout
  125. // every frame until it reaches maxJumpSpeed, or player releases the spacebar,
  126. // and then changes to the falling state until it gets grounded.
  127. if (groundState != GroundState.Falling && Input.GetKey(KeyCode.Space))
  128. {
  129. if (groundState != GroundState.Jumping)
  130. {
  131. // Start jump at initial power.
  132. groundState = GroundState.Jumping;
  133. jumpSpeed = initialJumpSpeed;
  134. }
  135. else
  136. // Jumping has already started...increase power toward maxJumpSpeed over time.
  137. jumpSpeed = Mathf.MoveTowards(jumpSpeed, maxJumpSpeed, jumpDelta);
  138. // If power has reached maxJumpSpeed, change to falling until grounded.
  139. // This prevents over-applying jump power while already in the air.
  140. if (jumpSpeed == maxJumpSpeed)
  141. groundState = GroundState.Falling;
  142. }
  143. else if (groundState != GroundState.Grounded)
  144. {
  145. // handles running off a cliff and/or player released Spacebar.
  146. groundState = GroundState.Falling;
  147. jumpSpeed = Mathf.Min(jumpSpeed, maxJumpSpeed);
  148. jumpSpeed += Physics.gravity.y * Time.deltaTime;
  149. }
  150. else
  151. jumpSpeed = Physics.gravity.y * Time.deltaTime;
  152. }
  153. // TODO: Directional input works while airborne...feature?
  154. void HandleMove()
  155. {
  156. // Capture inputs
  157. horizontal = Input.GetAxis("Horizontal");
  158. vertical = Input.GetAxis("Vertical");
  159. // Create initial direction vector without jumpSpeed (y-axis).
  160. direction = new Vector3(horizontal, 0f, vertical);
  161. // Clamp so diagonal strafing isn't a speed advantage.
  162. direction = Vector3.ClampMagnitude(direction, 1f);
  163. // Transforms direction from local space to world space.
  164. direction = transform.TransformDirection(direction);
  165. // Multiply for desired ground speed.
  166. direction *= moveSpeedMultiplier;
  167. // Add jumpSpeed to direction as last step.
  168. direction.y = jumpSpeed;
  169. // Finally move the character.
  170. characterController.Move(direction * Time.deltaTime);
  171. }
  172. }
  173. }