Files
WaveDefender/Assets/Scripts/PlayerController.cs

168 lines
5.5 KiB
C#

using UnityEngine;
[RequireComponent(typeof(CharacterController))]
public class PlayerController : MonoBehaviour
{
[Header("Movement")]
public float walkSpeed = 6f;
public float sprintSpeed = 10f;
public float crouchSpeed = 3f;
public float jumpHeight = 1.2f;
public float gravity = -20f;
[Header("Mouse Look")]
public float mouseSensitivity = 2f;
public float maxLookAngle = 85f;
public Transform cameraHolder;
[Header("Crouch")]
public float standingHeight = 2f;
public float crouchingHeight = 1f;
public float crouchTransitionSpeed = 10f;
[Header("Head Bob")]
public float bobFrequency = 10f;
public float bobAmplitude = 0.04f;
public float sprintBobMultiplier = 1.6f;
// --- Private State ---
private CharacterController _cc;
private Vector3 _velocity;
private float _xRotation;
private bool _isCrouching;
private bool _isSprinting;
private float _bobTimer;
private Vector3 _cameraLocalOrigin;
void Awake()
{
_cc = GetComponent<CharacterController>();
if (cameraHolder == null && Camera.main != null)
cameraHolder = Camera.main.transform;
if (cameraHolder != null)
_cameraLocalOrigin = cameraHolder.localPosition;
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
void Update()
{
HandleMouseLook();
HandleCrouch();
HandleMovement();
HandleHeadBob();
}
// -----------------------------------------------------------------------
// Mouse Look
// -----------------------------------------------------------------------
void HandleMouseLook()
{
float mouseX = Input.GetAxisRaw("Mouse X") * mouseSensitivity;
float mouseY = Input.GetAxisRaw("Mouse Y") * mouseSensitivity;
_xRotation -= mouseY;
_xRotation = Mathf.Clamp(_xRotation, -maxLookAngle, maxLookAngle);
if (cameraHolder != null)
cameraHolder.localRotation = Quaternion.Euler(_xRotation, 0f, 0f);
transform.Rotate(Vector3.up * mouseX);
}
// -----------------------------------------------------------------------
// Movement & Jumping
// -----------------------------------------------------------------------
void HandleMovement()
{
bool grounded = _cc.isGrounded;
if (grounded && _velocity.y < 0f)
_velocity.y = -2f; // keep grounded
float h = Input.GetAxisRaw("Horizontal");
float v = Input.GetAxisRaw("Vertical");
_isSprinting = grounded && Input.GetKey(KeyCode.LeftShift) && !_isCrouching && v > 0f;
float speed = _isCrouching ? crouchSpeed : (_isSprinting ? sprintSpeed : walkSpeed);
// Instant direction change — no momentum (arcade feel)
Vector3 move = (transform.right * h + transform.forward * v).normalized * speed;
_cc.Move(move * Time.deltaTime);
// Jump
if (Input.GetButtonDown("Jump") && grounded && !_isCrouching)
_velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
// Gravity
_velocity.y += gravity * Time.deltaTime;
_cc.Move(new Vector3(0f, _velocity.y, 0f) * Time.deltaTime);
}
// -----------------------------------------------------------------------
// Crouch
// -----------------------------------------------------------------------
void HandleCrouch()
{
bool wantCrouch = Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.C);
// Prevent standing up if something is above the player
if (_isCrouching && !wantCrouch && !CanStandUp())
wantCrouch = true;
_isCrouching = wantCrouch;
float targetHeight = _isCrouching ? crouchingHeight : standingHeight;
_cc.height = Mathf.Lerp(_cc.height, targetHeight, crouchTransitionSpeed * Time.deltaTime);
_cc.center = new Vector3(0f, _cc.height / 2f, 0f);
// Move camera with the capsule top
if (cameraHolder != null)
{
float targetCamY = _cameraLocalOrigin.y - (standingHeight - _cc.height) * 0.5f;
Vector3 pos = cameraHolder.localPosition;
pos.y = Mathf.Lerp(pos.y, targetCamY, crouchTransitionSpeed * Time.deltaTime);
cameraHolder.localPosition = new Vector3(_cameraLocalOrigin.x, pos.y, _cameraLocalOrigin.z);
}
}
bool CanStandUp()
{
float checkDistance = standingHeight - _cc.height;
Vector3 top = transform.position + Vector3.up * (_cc.height - _cc.radius);
return !Physics.SphereCast(top, _cc.radius * 0.9f, Vector3.up, out _, checkDistance);
}
// -----------------------------------------------------------------------
// Head Bob
// -----------------------------------------------------------------------
void HandleHeadBob()
{
if (cameraHolder == null) return;
bool isMoving = _cc.isGrounded && _cc.velocity.magnitude > 0.1f;
if (isMoving)
{
float multiplier = _isSprinting ? sprintBobMultiplier : 1f;
_bobTimer += Time.deltaTime * bobFrequency * multiplier;
float bobY = Mathf.Sin(_bobTimer) * bobAmplitude;
float bobX = Mathf.Sin(_bobTimer * 0.5f) * bobAmplitude * 0.5f;
Vector3 pos = cameraHolder.localPosition;
pos.y += bobY;
pos.x = _cameraLocalOrigin.x + bobX;
cameraHolder.localPosition = pos;
}
else
{
_bobTimer = 0f;
}
}
}