You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

169 lines
4.9 KiB
C#

using UnityEngine;
public enum MoveState { Idle, Walking, Running, Jumping, Falling};
[RequireComponent(typeof(CharacterController))]
public class FPSController : MonoBehaviour {
[Header("General")]
[SerializeField] private MoveState m_moveState = MoveState.Idle;
public bool playerControl = true;
[Header("Movement")]
[SerializeField] [Range(0f, 1f)] private float m_moveBackwardFactor = .8f;
[SerializeField] [Range(0f, 1f)] private float m_moveSideFactor = .8f;
[SerializeField] private float m_antiBumpFactor = .75f;
private CharacterController m_characterController;
private bool m_grounded = true;
private float m_speed;
private Vector2 m_input = Vector2.zero;
private Vector3 m_moveDirection = Vector3.zero;
private Vector3 m_moveVelocity = Vector3.zero;
private CollisionFlags m_collisionFlags;
[Header("Walking")]
[SerializeField] private float m_walkSpeed = 5f;
[Header("Running")]
[SerializeField] private float m_runSpeed = 8f;
[Header("Jumping")]
[SerializeField] private float m_jumpVerticalSpeed = 7f;
[SerializeField] private float m_jumpHorizontalSpeed = 2f;
[SerializeField] private float m_framesGroundedBetweenJumps = 1;
private float m_jumpFrameCounter;
[Header("Falling")]
private bool m_falling = false;
[Header("Camera")]
[SerializeField] private FPSMouseLook m_mouseLook;
public Camera m_fpsCamera;
[Header("Physics")]
[SerializeField] private float m_gravity = 20f;
// ---------- Properties ----------
public float Speed
{
get { return m_speed; }
set { m_speed = Mathf.Clamp(value, 0, m_runSpeed); }
}
public MoveState CurrentMoveState
{
get { return m_moveState; }
}
private void Awake()
{
m_characterController = GetComponent<CharacterController>();
m_fpsCamera = Camera.main;
}
private void Start ()
{
m_mouseLook.Init(transform, m_fpsCamera.transform);
m_speed = m_walkSpeed;
m_jumpFrameCounter = m_framesGroundedBetweenJumps;
}
private void Update ()
{
if (!playerControl)
return;
m_mouseLook.LookRotation();
if (m_grounded)
{
if (m_falling)
{
m_falling = false;
}
if (Input.GetKey(KeyCode.LeftShift))
{
m_speed = m_runSpeed;
}
else
{
m_speed = m_walkSpeed;
}
}
else
{
if (!m_falling)
{
m_falling = true;
}
}
MovePosition();
UpdateMoveState();
}
private void MovePosition()
{
m_input = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
if (m_input.y < 0)
m_input.y *= m_moveBackwardFactor;
if (m_input.x != 0)
m_input.x *= m_moveSideFactor;
if (m_input.sqrMagnitude > 1)
m_input.Normalize();
if (m_grounded)
{
m_moveDirection = transform.forward * m_input.y + transform.right * m_input.x;
RaycastHit hitInfo;
Physics.SphereCast(transform.position + m_characterController.center, m_characterController.radius, Vector3.down, out hitInfo,
m_characterController.height / 2f, Physics.AllLayers, QueryTriggerInteraction.Ignore);
m_moveDirection = Vector3.ProjectOnPlane(m_moveDirection, hitInfo.normal).normalized;
m_moveDirection.y = -m_antiBumpFactor;
m_moveVelocity = m_moveDirection * m_speed;
if (!Input.GetButton("Jump"))
m_jumpFrameCounter++;
else if (m_jumpFrameCounter >= m_framesGroundedBetweenJumps)
{
m_moveVelocity.y = m_jumpVerticalSpeed;
m_moveVelocity += m_moveDirection * m_jumpHorizontalSpeed;
m_jumpFrameCounter = 0;
}
}
m_moveVelocity.y -= m_gravity * Time.deltaTime;
m_collisionFlags = m_characterController.Move(m_moveVelocity * Time.deltaTime);
m_grounded = (m_collisionFlags & CollisionFlags.Below) != 0;
}
// ---------- Move State ----------
private void UpdateMoveState()
{
if (!m_grounded)
{
if (m_characterController.velocity.y < 0)
m_moveState = MoveState.Falling;
else
m_moveState = MoveState.Jumping;
return;
}
Vector2 moveInput = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
if (moveInput.sqrMagnitude == 0)
{
m_moveState = MoveState.Idle;
return;
}
if (m_speed == m_runSpeed)
m_moveState = MoveState.Running;
else if (m_speed == m_walkSpeed)
m_moveState = MoveState.Walking;
}
}