using Unity.VisualScripting; using UnityEngine; using UnityEngine.UIElements; namespace Player.Movement { public partial class PlayerMovementController : MonoBehaviour { public bool IsGrounded { get; private set; } public bool IsCrouching { get; private set; } public bool IsMoving { get; private set; } public Vector3 Velocity { get => _rigidbody.velocity; set => _rigidbody.velocity = value; } public float FrictionCoefficient { get => frictionCoefficient; set => frictionCoefficient = value; } public Vector3 Position => _rigidbody.position; // refs private Rigidbody _rigidbody; private CapsuleCollider _capsuleCollider; // private fields private readonly GroundChecker _groundChecker = new(); private RaycastHit[] _hit; private RaycastHit _hitMovement; private float _timeSinceLanding; private bool _wasGroundedLastFrame; private void Awake() { _rigidbody = GetComponent(); _capsuleCollider = GetComponent(); _document = GetComponent(); } private void OnEnable() { jumpAction.action.performed += Jump; slideAction.action.started += SlideStart; slideAction.action.canceled += SlideEnd; crouchAction.action.started += CrouchStart; crouchAction.action.canceled += CrouchEnd; sprintAction.action.started += SprintStart; sprintAction.action.canceled += SprintEnd; } private void OnDisable() { jumpAction.action.performed -= Jump; slideAction.action.started -= SlideStart; slideAction.action.canceled -= SlideEnd; crouchAction.action.started -= CrouchStart; crouchAction.action.canceled -= CrouchEnd; sprintAction.action.started -= SprintStart; sprintAction.action.canceled -= SprintEnd; } private void Update() { //////// _bank.OpenBankUI(); IsGrounded = _groundChecker.IsGrounded(transform, _capsuleCollider.bounds, extraHeight, out _hit, groundLayerMask); // my brain's fried, idek why this works if (IsGrounded) { if (_wasGroundedLastFrame) { _timeSinceLanding += Time.deltaTime; } else { _timeSinceLanding = 0; } } else { _timeSinceLanding = 0; } _wasGroundedLastFrame = IsGrounded; IsMovingCheck(); UpdateWhichSurfaceNormalToUse(); SlopeSlidingHandling(); UpdatePlayerRotation(); StaminaSystem(); } private void UpdatePlayerRotation() { transform.rotation = Quaternion.Euler(0, playerCameraController.CameraRotationVector.y, 0); } private void IsMovingCheck() { var playerInput = moveAction.action.ReadValue(); IsMoving = playerInput.magnitude > 0; } private void UpdateWhichSurfaceNormalToUse() { float steepestAngle = 0; var steepestRaycast = _hit[0]; foreach (var raycastHit in _hit) { var angle = Vector3.Angle(raycastHit.normal, Vector3.up); if (angle > steepestAngle) { steepestAngle = angle; steepestRaycast = raycastHit; } } _hitMovement = steepestRaycast; } private void SlopeSlidingHandling() { _rigidbody.useGravity = !IsGrounded; } private void FixedUpdate() { SlideSpeedCheck(); if (IsGrounded && !NoFrictionLandTimeframeMet() && !IsMoving) { ApplyFriction(); } if (!IsSliding) { Move(); } } private bool NoFrictionLandTimeframeMet() { return _timeSinceLanding < 0.1f; } private void ApplyFriction() { var velMag = _rigidbody.velocity.magnitude; if (velMag <= 0f) return; var normal = _hitMovement.normal; var frictionForceMag = frictionCoefficient * velMag; var counterForce = -_rigidbody.velocity * frictionForceMag / velMag; counterForce.y = 0; counterForce = Vector3.ProjectOnPlane(counterForce, normal); _rigidbody.AddForce(counterForce, ForceMode.VelocityChange); } private void Move() { var playerInput = moveAction.action.ReadValue(); var movementDirection = new Vector3(playerInput.x, 0, playerInput.y); var normal = _hitMovement.normal; var cameraRotationVector = playerCameraController.CameraRotationVector; cameraRotationVector = new Vector2(0, cameraRotationVector.y); var cameraRotation = Quaternion.Euler(cameraRotationVector); var desiredMovementDirection = cameraRotation * movementDirection; var velocityInDirection = Vector3.Dot(_rigidbody.velocity, desiredMovementDirection); var missingSpeed = maxMovementSpeed - velocityInDirection; missingSpeed = Mathf.Clamp(missingSpeed, 0, acceleration); var force = desiredMovementDirection * missingSpeed; force = Vector3.ProjectOnPlane(force, normal); // Debug.Log($"missing speed: {missingSpeed} rb velocity: {_rigidbody.velocity.magnitude} force: {force.magnitude}"); _rigidbody.AddForce(force, ForceMode.VelocityChange); if (_rigidbody.velocity.magnitude > maxMovementSpeed && !NoFrictionLandTimeframeMet()) { _rigidbody.velocity = _rigidbody.velocity.normalized * maxMovementSpeed; } } private void OnDrawGizmosSelected() { if (!Application.isPlaying) return; Gizmos.color = IsGrounded ? Color.green : Color.red; var bounds = _capsuleCollider.bounds; var toCenter = Vector3.down * (bounds.extents.y / 2); Gizmos.DrawWireCube(bounds.center + toCenter + Vector3.down * extraHeight / 2, new Vector3(bounds.size.x, bounds.extents.y + extraHeight, bounds.size.z)); Gizmos.color = Color.blue; Gizmos.DrawLine(_hitMovement.point, _hitMovement.point + _hitMovement.normal * 5); } public void Move(Vector3 direction) { throw new System.NotImplementedException(); } public void Teleport(Vector3 position, Quaternion rotation) { _rigidbody.position = position; _rigidbody.rotation = rotation; } } }