Guest User

AC_KCC_CharacterControllerFix

a guest
Feb 28th, 2025
12
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.41 KB | None | 0 0
  1. using UnityEngine;
  2. using KinematicCharacterController;
  3.  
  4. namespace AC.Downloads.KCCIntegration
  5. {
  6.  
  7. public enum OrientationMethod
  8. {
  9. TowardsCamera,
  10. TowardsMovement,
  11. TankControls,
  12. }
  13.  
  14.  
  15. public struct PlayerCharacterInputs
  16. {
  17. public float MoveAxisForward;
  18. public float MoveAxisRight;
  19. public bool RunHeld;
  20. }
  21.  
  22.  
  23. public struct AICharacterInputs
  24. {
  25. public Vector3 MoveVector;
  26. public Vector3 LookVector;
  27. public bool RunHeld;
  28. }
  29.  
  30.  
  31. public class AC_KCC_CharacterController : MonoBehaviour, ICharacterController
  32. {
  33.  
  34. [SerializeField] private KinematicCharacterMotor motor;
  35. public KinematicCharacterMotor Motor => motor;
  36.  
  37. [Header("Stable Movement")]
  38. [SerializeField] private float WalkSpeed = 4f;
  39. [SerializeField] private float RunSpeed = 8f;
  40. [SerializeField] private float tankTurnSpeed = 3f;
  41. [SerializeField] private float StableMovementSharpness = 15f;
  42. [SerializeField] private float OrientationSharpness = 10f;
  43. [SerializeField] private OrientationMethod OrientationMethod = OrientationMethod.TowardsCamera;
  44.  
  45. [Header("Air Movement")]
  46. [SerializeField] private float maxStepHeight = 2f;
  47. [SerializeField] private float MaxAirMoveSpeed = 5f;
  48. [SerializeField] private float AirAccelerationSpeed = 15f;
  49. [SerializeField] private float Drag = 0.1f;
  50.  
  51. [Header("Misc")]
  52. [SerializeField] private float BonusOrientationSharpness = 10f;
  53. [SerializeField] private Vector3 Gravity = new (0, -30f, 0);
  54.  
  55. private Vector3 _moveInputVector;
  56. private Vector3 _lookInputVector;
  57. private Vector3 _internalVelocityAdd = Vector3.zero;
  58. private Vector3 _lockedMoveDirection = Vector3.zero;
  59. private bool _isMovementHeld = false;
  60. private Quaternion _previousCameraRotation;
  61. private bool isRunning;
  62. private bool isAIControlled;
  63.  
  64.  
  65. private void Awake ()
  66. {
  67. Motor.CharacterController = this;
  68. }
  69.  
  70.  
  71. public void SetInputs(ref PlayerCharacterInputs inputs)
  72. {
  73. bool isMoving = inputs.MoveAxisForward != 0f || inputs.MoveAxisRight != 0f;
  74. Quaternion cameraRotation = KickStarter.CameraMainTransform.rotation;
  75.  
  76. if (isMoving)
  77. {
  78. if (!_isMovementHeld || Quaternion.Angle(_previousCameraRotation, cameraRotation) > 10f)
  79. {
  80. _lockedMoveDirection = _moveInputVector;
  81. }
  82. _isMovementHeld = true;
  83. }
  84. else
  85. {
  86. _isMovementHeld = false;
  87. _lockedMoveDirection = Vector3.zero;
  88. }
  89.  
  90. Vector3 moveInputVector = Vector3.ClampMagnitude(new Vector3(inputs.MoveAxisRight, 0f, inputs.MoveAxisForward), 1f);
  91. Vector3 cameraPlanarDirection = Vector3.ProjectOnPlane(cameraRotation * Vector3.forward, Motor.CharacterUp).normalized;
  92.  
  93. if (cameraPlanarDirection.sqrMagnitude == 0f)
  94. {
  95. cameraPlanarDirection = Vector3.ProjectOnPlane(cameraRotation * Vector3.up, Motor.CharacterUp).normalized;
  96. }
  97.  
  98. Quaternion cameraPlanarRotation = Quaternion.LookRotation(cameraPlanarDirection, Motor.CharacterUp);
  99.  
  100. _moveInputVector = _isMovementHeld && _lockedMoveDirection != Vector3.zero
  101. ? _lockedMoveDirection
  102. : cameraPlanarRotation * moveInputVector;
  103.  
  104. switch (OrientationMethod)
  105. {
  106. case OrientationMethod.TowardsCamera:
  107. _lookInputVector = cameraPlanarDirection;
  108. break;
  109.  
  110. case OrientationMethod.TowardsMovement:
  111. _lookInputVector = _moveInputVector.normalized;
  112. break;
  113. }
  114.  
  115. isRunning = inputs.RunHeld;
  116. isAIControlled = false;
  117. _previousCameraRotation = cameraRotation;
  118. }
  119.  
  120.  
  121. public void SetInputs (ref AICharacterInputs inputs)
  122. {
  123. _moveInputVector = inputs.MoveVector;
  124. _lookInputVector = inputs.LookVector;
  125. isRunning = inputs.RunHeld;
  126. isAIControlled = true;
  127. }
  128.  
  129.  
  130. public void BeforeCharacterUpdate (float deltaTime) {}
  131.  
  132.  
  133. public void UpdateRotation (ref Quaternion currentRotation, float deltaTime)
  134. {
  135. if (_lookInputVector.sqrMagnitude > 0f && OrientationSharpness > 0f)
  136. {
  137. // Smoothly interpolate from current to target look direction
  138. Vector3 smoothedLookInputDirection;
  139. if (!isAIControlled && OrientationMethod == OrientationMethod.TankControls)
  140. {
  141. float _tankTurnSpeed = tankTurnSpeed * (isRunning ? (RunSpeed / WalkSpeed) : 1f);
  142. smoothedLookInputDirection = Quaternion.AngleAxis (_lookInputVector.x * _tankTurnSpeed, Vector3.up) * Motor.CharacterForward * (1 - Mathf.Exp(-OrientationSharpness * deltaTime));
  143. }
  144. else
  145. {
  146. smoothedLookInputDirection = Vector3.Slerp (Motor.CharacterForward, _lookInputVector, 1 - Mathf.Exp(-OrientationSharpness * deltaTime)).normalized;
  147. }
  148.  
  149. // Set the current rotation (which will be used by the KinematicCharacterMotor)
  150. currentRotation = Quaternion.LookRotation (smoothedLookInputDirection, Motor.CharacterUp);
  151. }
  152.  
  153. Vector3 currentUp = currentRotation * Vector3.up;
  154. Vector3 smoothedGravityDir = Vector3.Slerp (currentUp, Vector3.up, 1 - Mathf.Exp (-BonusOrientationSharpness * deltaTime));
  155. currentRotation = Quaternion.FromToRotation (currentUp, smoothedGravityDir) * currentRotation;
  156. }
  157.  
  158.  
  159. public void UpdateVelocity (ref Vector3 currentVelocity, float deltaTime)
  160. {
  161. // Ground movement
  162. if (Motor.GroundingStatus.IsStableOnGround)
  163. {
  164. float currentVelocityMagnitude = currentVelocity.magnitude;
  165.  
  166. Vector3 effectiveGroundNormal = Motor.GroundingStatus.GroundNormal;
  167.  
  168. // Reorient velocity on slope
  169. currentVelocity = Motor.GetDirectionTangentToSurface (currentVelocity, effectiveGroundNormal) * currentVelocityMagnitude;
  170.  
  171. // Calculate target velocity
  172. Vector3 inputRight = Vector3.Cross (_moveInputVector, Motor.CharacterUp);
  173. Vector3 reorientedInput = Vector3.Cross (effectiveGroundNormal, inputRight).normalized * _moveInputVector.magnitude;
  174.  
  175. float speed = isRunning ? RunSpeed : WalkSpeed;
  176. Vector3 targetMovementVelocity = reorientedInput * speed;
  177.  
  178. // Smooth movement Velocity
  179. currentVelocity = Vector3.Lerp (currentVelocity, targetMovementVelocity, 1f - Mathf.Exp (-StableMovementSharpness * deltaTime));
  180. }
  181. // Air movement
  182. else
  183. {
  184. // Add move input
  185. if (_moveInputVector.sqrMagnitude > 0f)
  186. {
  187. Vector3 addedVelocity = _moveInputVector * AirAccelerationSpeed * deltaTime;
  188.  
  189. Vector3 currentVelocityOnInputsPlane = Vector3.ProjectOnPlane (currentVelocity, Motor.CharacterUp);
  190.  
  191. // Limit air velocity from inputs
  192. if (currentVelocityOnInputsPlane.magnitude < MaxAirMoveSpeed)
  193. {
  194. // clamp addedVel to make total vel not exceed max vel on inputs plane
  195. Vector3 newTotal = Vector3.ClampMagnitude (currentVelocityOnInputsPlane + addedVelocity, MaxAirMoveSpeed);
  196. addedVelocity = newTotal - currentVelocityOnInputsPlane;
  197. }
  198. else
  199. {
  200. // Make sure added vel doesn't go in the direction of the already-exceeding velocity
  201. if (Vector3.Dot (currentVelocityOnInputsPlane, addedVelocity) > 0f)
  202. {
  203. addedVelocity = Vector3.ProjectOnPlane (addedVelocity, currentVelocityOnInputsPlane.normalized);
  204. }
  205. }
  206.  
  207. // Prevent air-climbing sloped walls
  208. if (Motor.GroundingStatus.FoundAnyGround)
  209. {
  210. if (Vector3.Dot (currentVelocity + addedVelocity, addedVelocity) > 0f)
  211. {
  212. Vector3 perpenticularObstructionNormal = Vector3.Cross (Vector3.Cross (Motor.CharacterUp, Motor.GroundingStatus.GroundNormal), Motor.CharacterUp).normalized;
  213. addedVelocity = Vector3.ProjectOnPlane (addedVelocity, perpenticularObstructionNormal);
  214. }
  215. }
  216.  
  217. // Apply added velocity
  218. currentVelocity += addedVelocity;
  219. }
  220.  
  221. // Gravity
  222. currentVelocity += Gravity * deltaTime;
  223.  
  224. // Drag
  225. currentVelocity *= (1f / (1f + (Drag * deltaTime)));
  226. }
  227.  
  228. // Take into account additive velocity
  229. if (_internalVelocityAdd.sqrMagnitude > 0f)
  230. {
  231. currentVelocity += _internalVelocityAdd;
  232. _internalVelocityAdd = Vector3.zero;
  233. }
  234.  
  235. Vector3 nextPosition = Motor.TransientPosition + (currentVelocity * Time.deltaTime);
  236. bool nextPositionStable = Physics.Raycast (nextPosition + Vector3.up, Vector3.down, 1f + maxStepHeight);
  237. if (!nextPositionStable)
  238. {
  239. if (Physics.Raycast (nextPosition + Vector3.down * maxStepHeight, -currentVelocity, out RaycastHit hitInfo, 1f))
  240. {
  241. currentVelocity = Vector3.Reflect (currentVelocity, -hitInfo.normal);
  242. }
  243. else
  244. {
  245. currentVelocity = new Vector3 (0f, currentVelocity.y, 0f);
  246. }
  247. }
  248. }
  249.  
  250.  
  251. public void AfterCharacterUpdate (float deltaTime) {}
  252.  
  253.  
  254. public void PostGroundingUpdate (float deltaTime)
  255. {
  256. // Handle landing and leaving ground
  257. if (Motor.GroundingStatus.IsStableOnGround && !Motor.LastGroundingStatus.IsStableOnGround)
  258. {
  259. OnLanded ();
  260. }
  261. else if (!Motor.GroundingStatus.IsStableOnGround && Motor.LastGroundingStatus.IsStableOnGround)
  262. {
  263. OnLeaveStableGround ();
  264. }
  265. }
  266.  
  267.  
  268. public bool IsColliderValidForCollisions (Collider coll)
  269. {
  270. return true;
  271. }
  272.  
  273.  
  274. public void OnGroundHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport) {}
  275.  
  276. public void OnMovementHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport) {}
  277.  
  278.  
  279. public void AddVelocity (Vector3 velocity)
  280. {
  281. _internalVelocityAdd += velocity;
  282. }
  283.  
  284.  
  285. public void ProcessHitStabilityReport (Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, Vector3 atCharacterPosition, Quaternion atCharacterRotation, ref HitStabilityReport hitStabilityReport) {}
  286.  
  287. protected void OnLanded () {}
  288.  
  289. protected void OnLeaveStableGround () {}
  290.  
  291. public void OnDiscreteCollisionDetected (Collider hitCollider) {}
  292.  
  293. }
  294.  
  295. }
Advertisement
Add Comment
Please, Sign In to add comment