2025-10-14 17:10:15 +08:00
|
|
|
|
using Core;
|
|
|
|
|
using UnityEngine;
|
2025-10-17 15:10:19 +08:00
|
|
|
|
using Script.Gameplay.Input;
|
2025-10-14 17:10:15 +08:00
|
|
|
|
|
2025-10-20 10:12:07 +08:00
|
|
|
|
namespace Script.Gameplay.Player
|
2025-10-14 17:10:15 +08:00
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 玩家第一人称相机控制器
|
|
|
|
|
/// 挂到相机或相机父物体,playerBody 指向角色的根 Transform(用于左右旋转)
|
|
|
|
|
/// </summary>
|
|
|
|
|
public class PlayerCameraController : MonoBehaviour
|
|
|
|
|
{
|
2025-10-17 15:10:19 +08:00
|
|
|
|
[Header("References")] [Tooltip("角色根 Transform,用于水平旋转(yaw)")]
|
2025-10-14 17:10:15 +08:00
|
|
|
|
public Transform playerBody;
|
2025-10-17 15:10:19 +08:00
|
|
|
|
|
2025-10-14 17:10:15 +08:00
|
|
|
|
[Tooltip("如果相机不是挂载在同一物体上,可以指定相机 Transform(可选)")]
|
|
|
|
|
public Transform cameraTransform;
|
|
|
|
|
|
2025-10-17 15:10:19 +08:00
|
|
|
|
[Header("Sensitivity & Invert")] [Tooltip("鼠标灵敏度")] [Range(0.01f, 1f)]
|
2025-10-14 17:10:15 +08:00
|
|
|
|
public float mouseSensitivity = 0.2f;
|
|
|
|
|
|
2025-10-17 15:10:19 +08:00
|
|
|
|
[Tooltip("反转垂直轴")] public bool invertY = false;
|
2025-10-14 17:10:15 +08:00
|
|
|
|
|
2025-10-17 15:10:19 +08:00
|
|
|
|
[Header("Vertical Limits")] [Tooltip("向上最大仰角(度)")]
|
2025-10-14 17:10:15 +08:00
|
|
|
|
public float maxUpAngle = 60f;
|
|
|
|
|
|
2025-10-17 15:10:19 +08:00
|
|
|
|
[Tooltip("向下最大俯角(度)")] public float maxDownAngle = 60f;
|
|
|
|
|
|
|
|
|
|
[Header("Smoothing")] public bool enableSmoothing = false;
|
|
|
|
|
[Tooltip("旋转平滑时间(秒)")] public float smoothTime = 0.05f;
|
2025-10-14 17:10:15 +08:00
|
|
|
|
|
|
|
|
|
// internal state
|
|
|
|
|
private float xRotation = 0f; // 垂直角(pitch)
|
2025-10-17 15:10:19 +08:00
|
|
|
|
private float yaw = 0f; // 水平角(yaw)
|
2025-10-14 17:10:15 +08:00
|
|
|
|
private float smoothVelocityPitch = 0f;
|
|
|
|
|
private float smoothVelocityYaw = 0f;
|
|
|
|
|
|
|
|
|
|
void Start()
|
|
|
|
|
{
|
|
|
|
|
if (cameraTransform == null)
|
|
|
|
|
cameraTransform = transform;
|
|
|
|
|
|
|
|
|
|
// 初始化当前角度以避免跳变
|
|
|
|
|
Vector3 euler = cameraTransform.localEulerAngles;
|
|
|
|
|
xRotation = NormalizeAngle(euler.x);
|
|
|
|
|
yaw = NormalizeAngle(playerBody ? playerBody.eulerAngles.y : transform.eulerAngles.y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Update()
|
|
|
|
|
{
|
|
|
|
|
Vector2 mouse = InputManager.Instance.Look;
|
|
|
|
|
|
|
|
|
|
// ✅ 不要乘 Time.deltaTime,因为 Look 已经是每帧的增量
|
|
|
|
|
float mouseX = mouse.x * mouseSensitivity;
|
|
|
|
|
float mouseY = mouse.y * mouseSensitivity;
|
|
|
|
|
|
|
|
|
|
float invert = invertY ? 1f : -1f;
|
|
|
|
|
|
|
|
|
|
yaw += mouseX;
|
|
|
|
|
xRotation += mouseY * invert;
|
|
|
|
|
|
|
|
|
|
// 限制垂直角度
|
|
|
|
|
xRotation = Mathf.Clamp(xRotation, -maxDownAngle, maxUpAngle);
|
|
|
|
|
|
|
|
|
|
if (enableSmoothing)
|
|
|
|
|
{
|
2025-10-17 15:10:19 +08:00
|
|
|
|
float smoothPitch = Mathf.SmoothDampAngle(cameraTransform.localEulerAngles.x, xRotation,
|
|
|
|
|
ref smoothVelocityPitch, smoothTime);
|
|
|
|
|
float smoothYaw = Mathf.SmoothDampAngle(playerBody ? playerBody.eulerAngles.y : transform.eulerAngles.y,
|
|
|
|
|
yaw, ref smoothVelocityYaw, smoothTime);
|
2025-10-14 17:10:15 +08:00
|
|
|
|
|
|
|
|
|
cameraTransform.localRotation = Quaternion.Euler(smoothPitch, 0f, 0f);
|
|
|
|
|
if (playerBody)
|
|
|
|
|
playerBody.rotation = Quaternion.Euler(0f, smoothYaw, 0f);
|
|
|
|
|
else
|
|
|
|
|
transform.rotation = Quaternion.Euler(0f, smoothYaw, 0f);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cameraTransform.localRotation = Quaternion.Euler(xRotation, 0f, 0f);
|
|
|
|
|
if (playerBody)
|
|
|
|
|
playerBody.rotation = Quaternion.Euler(0f, yaw, 0f);
|
|
|
|
|
else
|
|
|
|
|
transform.rotation = Quaternion.Euler(0f, yaw, 0f);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 将角度规范到 [-180,180] 范围,避免插值跳变
|
|
|
|
|
private float NormalizeAngle(float angle)
|
|
|
|
|
{
|
|
|
|
|
angle = (angle + 180f) % 360f - 180f;
|
|
|
|
|
return angle;
|
|
|
|
|
}
|
2025-10-17 15:10:19 +08:00
|
|
|
|
|
|
|
|
|
|
2025-10-14 17:10:15 +08:00
|
|
|
|
}
|
2025-10-17 15:10:19 +08:00
|
|
|
|
}
|