Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using UnityEngine;
- using KinematicCharacterController;
- namespace AC.Downloads.KCCIntegration
- {
- public enum OrientationMethod
- {
- TowardsCamera,
- TowardsMovement,
- TankControls,
- }
- public struct PlayerCharacterInputs
- {
- public float MoveAxisForward;
- public float MoveAxisRight;
- public bool RunHeld;
- }
- public struct AICharacterInputs
- {
- public Vector3 MoveVector;
- public Vector3 LookVector;
- public bool RunHeld;
- }
- public class AC_KCC_CharacterController : MonoBehaviour, ICharacterController
- {
- [SerializeField] private KinematicCharacterMotor motor;
- public KinematicCharacterMotor Motor => motor;
- [Header("Stable Movement")]
- [SerializeField] private float WalkSpeed = 4f;
- [SerializeField] private float RunSpeed = 8f;
- [SerializeField] private float tankTurnSpeed = 3f;
- [SerializeField] private float StableMovementSharpness = 15f;
- [SerializeField] private float OrientationSharpness = 10f;
- [SerializeField] private OrientationMethod OrientationMethod = OrientationMethod.TowardsCamera;
- [Header("Air Movement")]
- [SerializeField] private float maxStepHeight = 2f;
- [SerializeField] private float MaxAirMoveSpeed = 5f;
- [SerializeField] private float AirAccelerationSpeed = 15f;
- [SerializeField] private float Drag = 0.1f;
- [Header("Misc")]
- [SerializeField] private float BonusOrientationSharpness = 10f;
- [SerializeField] private Vector3 Gravity = new (0, -30f, 0);
- private Vector3 _moveInputVector;
- private Vector3 _lookInputVector;
- private Vector3 _internalVelocityAdd = Vector3.zero;
- private Vector3 _lockedMoveDirection = Vector3.zero;
- private bool _isMovementHeld = false;
- private Quaternion _previousCameraRotation;
- private bool isRunning;
- private bool isAIControlled;
- private void Awake ()
- {
- Motor.CharacterController = this;
- }
- public void SetInputs(ref PlayerCharacterInputs inputs)
- {
- bool isMoving = inputs.MoveAxisForward != 0f || inputs.MoveAxisRight != 0f;
- Quaternion cameraRotation = KickStarter.CameraMainTransform.rotation;
- if (isMoving)
- {
- if (!_isMovementHeld || Quaternion.Angle(_previousCameraRotation, cameraRotation) > 10f)
- {
- _lockedMoveDirection = _moveInputVector;
- }
- _isMovementHeld = true;
- }
- else
- {
- _isMovementHeld = false;
- _lockedMoveDirection = Vector3.zero;
- }
- Vector3 moveInputVector = Vector3.ClampMagnitude(new Vector3(inputs.MoveAxisRight, 0f, inputs.MoveAxisForward), 1f);
- Vector3 cameraPlanarDirection = Vector3.ProjectOnPlane(cameraRotation * Vector3.forward, Motor.CharacterUp).normalized;
- if (cameraPlanarDirection.sqrMagnitude == 0f)
- {
- cameraPlanarDirection = Vector3.ProjectOnPlane(cameraRotation * Vector3.up, Motor.CharacterUp).normalized;
- }
- Quaternion cameraPlanarRotation = Quaternion.LookRotation(cameraPlanarDirection, Motor.CharacterUp);
- _moveInputVector = _isMovementHeld && _lockedMoveDirection != Vector3.zero
- ? _lockedMoveDirection
- : cameraPlanarRotation * moveInputVector;
- switch (OrientationMethod)
- {
- case OrientationMethod.TowardsCamera:
- _lookInputVector = cameraPlanarDirection;
- break;
- case OrientationMethod.TowardsMovement:
- _lookInputVector = _moveInputVector.normalized;
- break;
- }
- isRunning = inputs.RunHeld;
- isAIControlled = false;
- _previousCameraRotation = cameraRotation;
- }
- public void SetInputs (ref AICharacterInputs inputs)
- {
- _moveInputVector = inputs.MoveVector;
- _lookInputVector = inputs.LookVector;
- isRunning = inputs.RunHeld;
- isAIControlled = true;
- }
- public void BeforeCharacterUpdate (float deltaTime) {}
- public void UpdateRotation (ref Quaternion currentRotation, float deltaTime)
- {
- if (_lookInputVector.sqrMagnitude > 0f && OrientationSharpness > 0f)
- {
- // Smoothly interpolate from current to target look direction
- Vector3 smoothedLookInputDirection;
- if (!isAIControlled && OrientationMethod == OrientationMethod.TankControls)
- {
- float _tankTurnSpeed = tankTurnSpeed * (isRunning ? (RunSpeed / WalkSpeed) : 1f);
- smoothedLookInputDirection = Quaternion.AngleAxis (_lookInputVector.x * _tankTurnSpeed, Vector3.up) * Motor.CharacterForward * (1 - Mathf.Exp(-OrientationSharpness * deltaTime));
- }
- else
- {
- smoothedLookInputDirection = Vector3.Slerp (Motor.CharacterForward, _lookInputVector, 1 - Mathf.Exp(-OrientationSharpness * deltaTime)).normalized;
- }
- // Set the current rotation (which will be used by the KinematicCharacterMotor)
- currentRotation = Quaternion.LookRotation (smoothedLookInputDirection, Motor.CharacterUp);
- }
- Vector3 currentUp = currentRotation * Vector3.up;
- Vector3 smoothedGravityDir = Vector3.Slerp (currentUp, Vector3.up, 1 - Mathf.Exp (-BonusOrientationSharpness * deltaTime));
- currentRotation = Quaternion.FromToRotation (currentUp, smoothedGravityDir) * currentRotation;
- }
- public void UpdateVelocity (ref Vector3 currentVelocity, float deltaTime)
- {
- // Ground movement
- if (Motor.GroundingStatus.IsStableOnGround)
- {
- float currentVelocityMagnitude = currentVelocity.magnitude;
- Vector3 effectiveGroundNormal = Motor.GroundingStatus.GroundNormal;
- // Reorient velocity on slope
- currentVelocity = Motor.GetDirectionTangentToSurface (currentVelocity, effectiveGroundNormal) * currentVelocityMagnitude;
- // Calculate target velocity
- Vector3 inputRight = Vector3.Cross (_moveInputVector, Motor.CharacterUp);
- Vector3 reorientedInput = Vector3.Cross (effectiveGroundNormal, inputRight).normalized * _moveInputVector.magnitude;
- float speed = isRunning ? RunSpeed : WalkSpeed;
- Vector3 targetMovementVelocity = reorientedInput * speed;
- // Smooth movement Velocity
- currentVelocity = Vector3.Lerp (currentVelocity, targetMovementVelocity, 1f - Mathf.Exp (-StableMovementSharpness * deltaTime));
- }
- // Air movement
- else
- {
- // Add move input
- if (_moveInputVector.sqrMagnitude > 0f)
- {
- Vector3 addedVelocity = _moveInputVector * AirAccelerationSpeed * deltaTime;
- Vector3 currentVelocityOnInputsPlane = Vector3.ProjectOnPlane (currentVelocity, Motor.CharacterUp);
- // Limit air velocity from inputs
- if (currentVelocityOnInputsPlane.magnitude < MaxAirMoveSpeed)
- {
- // clamp addedVel to make total vel not exceed max vel on inputs plane
- Vector3 newTotal = Vector3.ClampMagnitude (currentVelocityOnInputsPlane + addedVelocity, MaxAirMoveSpeed);
- addedVelocity = newTotal - currentVelocityOnInputsPlane;
- }
- else
- {
- // Make sure added vel doesn't go in the direction of the already-exceeding velocity
- if (Vector3.Dot (currentVelocityOnInputsPlane, addedVelocity) > 0f)
- {
- addedVelocity = Vector3.ProjectOnPlane (addedVelocity, currentVelocityOnInputsPlane.normalized);
- }
- }
- // Prevent air-climbing sloped walls
- if (Motor.GroundingStatus.FoundAnyGround)
- {
- if (Vector3.Dot (currentVelocity + addedVelocity, addedVelocity) > 0f)
- {
- Vector3 perpenticularObstructionNormal = Vector3.Cross (Vector3.Cross (Motor.CharacterUp, Motor.GroundingStatus.GroundNormal), Motor.CharacterUp).normalized;
- addedVelocity = Vector3.ProjectOnPlane (addedVelocity, perpenticularObstructionNormal);
- }
- }
- // Apply added velocity
- currentVelocity += addedVelocity;
- }
- // Gravity
- currentVelocity += Gravity * deltaTime;
- // Drag
- currentVelocity *= (1f / (1f + (Drag * deltaTime)));
- }
- // Take into account additive velocity
- if (_internalVelocityAdd.sqrMagnitude > 0f)
- {
- currentVelocity += _internalVelocityAdd;
- _internalVelocityAdd = Vector3.zero;
- }
- Vector3 nextPosition = Motor.TransientPosition + (currentVelocity * Time.deltaTime);
- bool nextPositionStable = Physics.Raycast (nextPosition + Vector3.up, Vector3.down, 1f + maxStepHeight);
- if (!nextPositionStable)
- {
- if (Physics.Raycast (nextPosition + Vector3.down * maxStepHeight, -currentVelocity, out RaycastHit hitInfo, 1f))
- {
- currentVelocity = Vector3.Reflect (currentVelocity, -hitInfo.normal);
- }
- else
- {
- currentVelocity = new Vector3 (0f, currentVelocity.y, 0f);
- }
- }
- }
- public void AfterCharacterUpdate (float deltaTime) {}
- public void PostGroundingUpdate (float deltaTime)
- {
- // Handle landing and leaving ground
- if (Motor.GroundingStatus.IsStableOnGround && !Motor.LastGroundingStatus.IsStableOnGround)
- {
- OnLanded ();
- }
- else if (!Motor.GroundingStatus.IsStableOnGround && Motor.LastGroundingStatus.IsStableOnGround)
- {
- OnLeaveStableGround ();
- }
- }
- public bool IsColliderValidForCollisions (Collider coll)
- {
- return true;
- }
- public void OnGroundHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport) {}
- public void OnMovementHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport) {}
- public void AddVelocity (Vector3 velocity)
- {
- _internalVelocityAdd += velocity;
- }
- public void ProcessHitStabilityReport (Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, Vector3 atCharacterPosition, Quaternion atCharacterRotation, ref HitStabilityReport hitStabilityReport) {}
- protected void OnLanded () {}
- protected void OnLeaveStableGround () {}
- public void OnDiscreteCollisionDetected (Collider hitCollider) {}
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment