CCCPaste Login

FirstPersonCharacter

    public class FirstPersonCharacter : MonoBehaviour
    {
        public static FirstPersonCharacter Instance { get; private set; }
        public PlayerInputManager InputManager { get; private set; }

        [SerializeField]
        private PlayerInventory _inventory;
        public PlayerInventory Inventory => _inventory;

        [Header("Movement Settings")]
        [SerializeField] private float _walkSpeed = 4f;
        [SerializeField] private float _backwardWalkSpeed = 2f;
        [SerializeField] private float _runSpeed = 7f;
        [SerializeField] private float _backwardRunSpeed = 4f;
        [SerializeField] private float _jumpForce = 5f;
        [SerializeField] private float _airControlMultiplier = 0.4f;

        [Header("Ground Check Settings")]
        [SerializeField] private Transform _groundCheck;
        [SerializeField] private float _groundDistance = 0.3f;
        [SerializeField] private LayerMask _groundMask;

        [Header("Camera")]
        [SerializeField] private Camera _playerCam;
        [SerializeField] private Transform _camPositionTr;
        public Transform CamPositionTr => _camPositionTr;

        private Vector2 _rawMoveInput;
        private Vector3 _moveDirection;
        private bool _jumpRequested;
        private bool _isGrounded;

        [SerializeField] private Rigidbody _rb;
        public Rigidbody Rb => _rb;

        private void Awake()
        {
            Instance = this;

            InputManager = GetComponent();

            if (_rb == null)
                _rb = GetComponent();

            _rb.freezeRotation = true;
        }

        private void Update()
        {
            _rawMoveInput = InputManager.MoveInput;

            Vector3 moveInput = new Vector3(_rawMoveInput.x, 0, _rawMoveInput.y).normalized;
            _moveDirection = transform.TransformDirection(moveInput);

            // Ground Check
            _isGrounded = Physics.CheckSphere(_groundCheck.position, _groundDistance, _groundMask);

            if (InputManager.Jumped && _isGrounded && _rb.velocity.y <= 0)
            {
                _jumpRequested = true;
            }
        }

        private void FixedUpdate()
        {
            // make camera follow the player
            _playerCam.transform.position = _camPositionTr.position;

            HandleMovement();
            HandleJump();
        }

        private void HandleMovement()
        {
            float speed = InputManager.Running && _isGrounded ? _runSpeed : _walkSpeed;
            if (InputManager.MoveBackward)
            {
                speed = InputManager.Running && _isGrounded ? _backwardRunSpeed : _backwardWalkSpeed;
            }

            if (_isGrounded)
            {
                Vector3 targetVelocity = _moveDirection * speed;
                Vector3 velocityChange = targetVelocity - new Vector3(_rb.velocity.x, 0, _rb.velocity.z);
                _rb.AddForce(velocityChange, ForceMode.VelocityChange);
            }
            else
            {
                Vector3 airVelocity = _airControlMultiplier * speed * _moveDirection;
                _rb.AddForce(airVelocity, ForceMode.Acceleration);
            }
        }

        private void HandleJump()
        {
            if (_jumpRequested)
            {
                _rb.velocity = new Vector3(_rb.velocity.x, 0f, _rb.velocity.z); // Reset vertical velocity
                _rb.AddForce(Vector3.up * _jumpForce, ForceMode.Impulse);
                _jumpRequested = false;
            }
        }

        private void OnDrawGizmosSelected()
        {
            if (_groundCheck == null) return;
            Gizmos.color = Color.green;
            Gizmos.DrawWireSphere(_groundCheck.position, _groundDistance);
        }
    }