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