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); } }