armaan_s92

AC_KCC_CharacterControllerFixUpdate

Mar 1st, 2025
17
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.50 KB | None | 0 0
  1. using UnityEngine;
  2. using KinematicCharacterController;
  3.  
  4. namespace AC.Downloads.KCCIntegration
  5. {
  6. public enum OrientationMethod
  7. {
  8. TowardsCamera,
  9. TowardsMovement,
  10. TankControls,
  11. }
  12.  
  13. public struct PlayerCharacterInputs
  14. {
  15. public float MoveAxisForward;
  16. public float MoveAxisRight;
  17. public bool RunHeld;
  18. }
  19.  
  20. public struct AICharacterInputs
  21. {
  22. public Vector3 MoveVector;
  23. public Vector3 LookVector;
  24. public bool RunHeld;
  25. }
  26.  
  27. public class AC_KCC_CharacterController : MonoBehaviour, ICharacterController
  28. {
  29. [SerializeField] private KinematicCharacterMotor motor;
  30. public KinematicCharacterMotor Motor => motor;
  31.  
  32. [Header("Stable Movement")]
  33. [SerializeField] private float WalkSpeed = 4f;
  34. [SerializeField] private float RunSpeed = 8f;
  35. [SerializeField] private float tankTurnSpeed = 3f;
  36. [SerializeField] private float StableMovementSharpness = 15f;
  37. [SerializeField] private float OrientationSharpness = 10f;
  38. [SerializeField] private OrientationMethod OrientationMethod = OrientationMethod.TowardsCamera;
  39.  
  40. [Header("Air Movement")]
  41. [SerializeField] private float maxStepHeight = 2f;
  42. [SerializeField] private float MaxAirMoveSpeed = 5f;
  43. [SerializeField] private float AirAccelerationSpeed = 15f;
  44. [SerializeField] private float Drag = 0.1f;
  45.  
  46. [Header("Misc")]
  47. [SerializeField] private float BonusOrientationSharpness = 10f;
  48. [SerializeField] private Vector3 Gravity = new Vector3(0, -30f, 0);
  49.  
  50. private Vector3 _moveInputVector;
  51. private Vector3 _lookInputVector;
  52. private Vector3 _internalVelocityAdd = Vector3.zero;
  53.  
  54. // Variables for movement locking logic
  55. private Vector3 _lockedMoveDirection = Vector3.zero;
  56. private bool _isMovementHeld = false;
  57. private Vector2 _previousRawInput = Vector2.zero;
  58. private Quaternion _previousCameraRotation;
  59.  
  60. private bool isRunning;
  61. private bool isAIControlled;
  62.  
  63. private void Awake()
  64. {
  65. Motor.CharacterController = this;
  66. _previousCameraRotation = KickStarter.CameraMainTransform.rotation;
  67. }
  68.  
  69. public void SetInputs(ref PlayerCharacterInputs inputs)
  70. {
  71. // Get current raw input from the player (analog or digital values)
  72. Vector2 currentRawInput = new Vector2(inputs.MoveAxisRight, inputs.MoveAxisForward);
  73. bool isMoving = currentRawInput.sqrMagnitude > 0f;
  74.  
  75. // Get the current camera rotation and compute a planar rotation
  76. Quaternion cameraRotation = KickStarter.CameraMainTransform.rotation;
  77. Vector3 cameraPlanarDirection = Vector3.ProjectOnPlane(cameraRotation * Vector3.forward, Motor.CharacterUp).normalized;
  78. if (cameraPlanarDirection.sqrMagnitude == 0f)
  79. {
  80. cameraPlanarDirection = Vector3.ProjectOnPlane(cameraRotation * Vector3.up, Motor.CharacterUp).normalized;
  81. }
  82. Quaternion cameraPlanarRotation = Quaternion.LookRotation(cameraPlanarDirection, Motor.CharacterUp);
  83.  
  84. // Compute the new raw move direction in world space based on current camera orientation
  85. Vector3 newRawInput = cameraPlanarRotation * Vector3.ClampMagnitude(new Vector3(inputs.MoveAxisRight, 0f, inputs.MoveAxisForward), 1f);
  86.  
  87. // If the player is moving, update the locked direction if input has changed
  88. if (isMoving)
  89. {
  90. if (!_isMovementHeld)
  91. {
  92. _lockedMoveDirection = newRawInput;
  93. _isMovementHeld = true;
  94. }
  95. else
  96. {
  97. // If input changes beyond a small threshold, update the locked direction immediately
  98. if ((currentRawInput - _previousRawInput).sqrMagnitude > 0.001f)
  99. {
  100. _lockedMoveDirection = newRawInput;
  101. }
  102. }
  103. }
  104. else
  105. {
  106. _isMovementHeld = false;
  107. _lockedMoveDirection = Vector3.zero;
  108. }
  109.  
  110. // Use the locked movement direction if movement is held, otherwise use the new input
  111. _moveInputVector = _isMovementHeld ? _lockedMoveDirection : newRawInput;
  112.  
  113. // Determine look direction based on the chosen orientation method
  114. switch (OrientationMethod)
  115. {
  116. case OrientationMethod.TowardsCamera:
  117. _lookInputVector = cameraPlanarDirection;
  118. break;
  119. case OrientationMethod.TowardsMovement:
  120. _lookInputVector = _moveInputVector.normalized;
  121. break;
  122. default:
  123. break;
  124. }
  125.  
  126. isRunning = inputs.RunHeld;
  127. isAIControlled = false;
  128.  
  129. // Store current raw input and camera rotation for next frame comparisons.
  130. _previousRawInput = currentRawInput;
  131. _previousCameraRotation = cameraRotation;
  132. }
  133.  
  134. public void SetInputs(ref AICharacterInputs inputs)
  135. {
  136. _moveInputVector = inputs.MoveVector;
  137. _lookInputVector = inputs.LookVector;
  138. isRunning = inputs.RunHeld;
  139. isAIControlled = true;
  140. }
  141.  
  142. public void BeforeCharacterUpdate(float deltaTime) { }
  143.  
  144. public void UpdateRotation(ref Quaternion currentRotation, float deltaTime)
  145. {
  146. if (_lookInputVector.sqrMagnitude > 0f && OrientationSharpness > 0f)
  147. {
  148. // Compute the desired target rotation
  149. Quaternion targetRotation = Quaternion.LookRotation(_lookInputVector, Motor.CharacterUp);
  150. // Rotate towards target using the shortest path.
  151. // The multiplier (90f) can be adjusted to control turning speed.
  152. float maxDegreesDelta = OrientationSharpness * deltaTime * 90f;
  153. currentRotation = Quaternion.RotateTowards(currentRotation, targetRotation, maxDegreesDelta);
  154. }
  155.  
  156. Vector3 currentUp = currentRotation * Vector3.up;
  157. Vector3 smoothedGravityDir = Vector3.Slerp(currentUp, Vector3.up, 1 - Mathf.Exp(-BonusOrientationSharpness * deltaTime));
  158. currentRotation = Quaternion.FromToRotation(currentUp, smoothedGravityDir) * currentRotation;
  159. }
  160.  
  161. public void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime)
  162. {
  163. // Ground movement
  164. if (Motor.GroundingStatus.IsStableOnGround)
  165. {
  166. float currentVelocityMagnitude = currentVelocity.magnitude;
  167. Vector3 effectiveGroundNormal = Motor.GroundingStatus.GroundNormal;
  168.  
  169. currentVelocity = Motor.GetDirectionTangentToSurface(currentVelocity, effectiveGroundNormal) * currentVelocityMagnitude;
  170. Vector3 inputRight = Vector3.Cross(_moveInputVector, Motor.CharacterUp);
  171. Vector3 reorientedInput = Vector3.Cross(effectiveGroundNormal, inputRight).normalized * _moveInputVector.magnitude;
  172.  
  173. float speed = isRunning ? RunSpeed : WalkSpeed;
  174. Vector3 targetMovementVelocity = reorientedInput * speed;
  175.  
  176. currentVelocity = Vector3.Lerp(currentVelocity, targetMovementVelocity, 1f - Mathf.Exp(-StableMovementSharpness * deltaTime));
  177. }
  178. // Air movement
  179. else
  180. {
  181. if (_moveInputVector.sqrMagnitude > 0f)
  182. {
  183. Vector3 addedVelocity = _moveInputVector * AirAccelerationSpeed * deltaTime;
  184. Vector3 currentVelocityOnInputsPlane = Vector3.ProjectOnPlane(currentVelocity, Motor.CharacterUp);
  185.  
  186. if (currentVelocityOnInputsPlane.magnitude < MaxAirMoveSpeed)
  187. {
  188. Vector3 newTotal = Vector3.ClampMagnitude(currentVelocityOnInputsPlane + addedVelocity, MaxAirMoveSpeed);
  189. addedVelocity = newTotal - currentVelocityOnInputsPlane;
  190. }
  191. else
  192. {
  193. if (Vector3.Dot(currentVelocityOnInputsPlane, addedVelocity) > 0f)
  194. {
  195. addedVelocity = Vector3.ProjectOnPlane(addedVelocity, currentVelocityOnInputsPlane.normalized);
  196. }
  197. }
  198.  
  199. if (Motor.GroundingStatus.FoundAnyGround)
  200. {
  201. if (Vector3.Dot(currentVelocity + addedVelocity, addedVelocity) > 0f)
  202. {
  203. Vector3 perpenticularObstructionNormal = Vector3.Cross(Vector3.Cross(Motor.CharacterUp, Motor.GroundingStatus.GroundNormal), Motor.CharacterUp).normalized;
  204. addedVelocity = Vector3.ProjectOnPlane(addedVelocity, perpenticularObstructionNormal);
  205. }
  206. }
  207.  
  208. currentVelocity += addedVelocity;
  209. }
  210.  
  211. currentVelocity += Gravity * deltaTime;
  212. currentVelocity *= (1f / (1f + (Drag * deltaTime)));
  213. }
  214.  
  215. if (_internalVelocityAdd.sqrMagnitude > 0f)
  216. {
  217. currentVelocity += _internalVelocityAdd;
  218. _internalVelocityAdd = Vector3.zero;
  219. }
  220.  
  221. Vector3 nextPosition = Motor.TransientPosition + (currentVelocity * Time.deltaTime);
  222. bool nextPositionStable = Physics.Raycast(nextPosition + Vector3.up, Vector3.down, 1f + maxStepHeight);
  223. if (!nextPositionStable)
  224. {
  225. if (Physics.Raycast(nextPosition + Vector3.down * maxStepHeight, -currentVelocity, out RaycastHit hitInfo, 1f))
  226. {
  227. currentVelocity = Vector3.Reflect(currentVelocity, -hitInfo.normal);
  228. }
  229. else
  230. {
  231. currentVelocity = new Vector3(0f, currentVelocity.y, 0f);
  232. }
  233. }
  234. }
  235.  
  236. public void AfterCharacterUpdate(float deltaTime) { }
  237.  
  238. public void PostGroundingUpdate(float deltaTime)
  239. {
  240. if (Motor.GroundingStatus.IsStableOnGround && !Motor.LastGroundingStatus.IsStableOnGround)
  241. {
  242. OnLanded();
  243. }
  244. else if (!Motor.GroundingStatus.IsStableOnGround && Motor.LastGroundingStatus.IsStableOnGround)
  245. {
  246. OnLeaveStableGround();
  247. }
  248. }
  249.  
  250. public bool IsColliderValidForCollisions(Collider coll) => true;
  251. public void OnGroundHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport) { }
  252. public void OnMovementHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport) { }
  253. public void AddVelocity(Vector3 velocity) => _internalVelocityAdd += velocity;
  254. public void ProcessHitStabilityReport(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, Vector3 atCharacterPosition, Quaternion atCharacterRotation, ref HitStabilityReport hitStabilityReport) { }
  255. protected void OnLanded() { }
  256. protected void OnLeaveStableGround() { }
  257. public void OnDiscreteCollisionDetected(Collider hitCollider) { }
  258. }
  259. }
  260.  
Advertisement
Add Comment
Please, Sign In to add comment