using UnityEngine; using KinematicCharacterController; namespace Code.Gameplay.Character.Controller { public class GroundMovementSystem { private readonly float _maxStableMoveSpeed; private readonly float _sprintMoveSpeed; private readonly float _stableMovementSharpness; private readonly float _jumpSpeed; public bool JumpRequested { get; private set; } public GroundMovementSystem(float maxStableMoveSpeed, float sprintMoveSpeed, float stableMovementSharpness, float jumpSpeed) { _maxStableMoveSpeed = maxStableMoveSpeed; _sprintMoveSpeed = sprintMoveSpeed; _stableMovementSharpness = stableMovementSharpness; _jumpSpeed = jumpSpeed; } public void RequestJump(bool jumpPressed) { if (jumpPressed) JumpRequested = true; } public void CancelJumpRequest() { JumpRequested = false; } public void UpdateVelocity( ref Vector3 currentVelocity, CharacterInputHandler inputHandler, KinematicCharacterMotor motor, float deltaTime) { var currentVelocityMagnitude = currentVelocity.magnitude; var effectiveGroundNormal = motor.GroundingStatus.GroundNormal; currentVelocity = motor.GetDirectionTangentToSurface(currentVelocity, effectiveGroundNormal) * currentVelocityMagnitude; var inputRight = Vector3.Cross(inputHandler.MoveInputVector, motor.CharacterUp); var reorientedInput = Vector3.Cross(effectiveGroundNormal, inputRight).normalized * inputHandler.MoveInputVector.magnitude; var targetSpeed = inputHandler.IsSprinting ? _sprintMoveSpeed : _maxStableMoveSpeed; var targetMovementVelocity = reorientedInput * targetSpeed; currentVelocity = Vector3.Lerp( currentVelocity, targetMovementVelocity, 1f - Mathf.Exp(-_stableMovementSharpness * deltaTime) ); if (JumpRequested) { currentVelocity += motor.CharacterUp * _jumpSpeed - Vector3.Project(currentVelocity, motor.CharacterUp); JumpRequested = false; motor.ForceUnground(); if (motor.CharacterController is CustomCharacterController controller) { controller.TriggerJump(); } } } } }