Files
agame_for_unity/Assets/_Game/Scripts/MouseLook.cs
T
2026-09-20 15:54:34 +08:00

91 lines
3.4 KiB
C#

using UnityEngine;
using UnityEngine.InputSystem;
namespace Agame
{
/// <summary>
/// 第一人称视角控制:鼠标横移带动 body 偏航,纵移带动相机俯仰。
///
/// 网络侧前提(重要):本组件挂在 PlayerCamera 上,而 PlayerCamera 只会被
/// <see cref="PlayerController"/> 为「本地拥有者」启用(见其 ApplyOwnership)。
/// 非拥有者客户端的相机是 disabled 的,因此这里不会执行,天然不需要再判所有权。
///
/// 反过来说:如果日后把 PlayerCamera 改成常驻启用,必须补上所有权判断,
/// 否则每个客户端都会用自己的鼠标去转动别人玩家的视角。
/// </summary>
public class MouseLook : MonoBehaviour
{
[Header("Sensitivity")]
[Tooltip("Degrees of rotation per pixel of mouse movement.")]
[SerializeField] private float mouseSensitivity = 0.12f;
[Header("Vertical Clamp")]
[SerializeField] private float minLookAngle = -80f;
[SerializeField] private float maxLookAngle = 80f;
[Header("References")]
[Tooltip("被偏航(Horizontal)的躯体 Transform,通常是玩家根节点。")]
[SerializeField] private Transform characterBody;
private float _xRotation;
private bool _warnedMissingBody;
private void OnEnable()
{
// 跟随本对象的启用状态锁定光标:只有本地拥有者的相机会被启用,
// 所以光标锁定/释放自然就只在拥有者这一侧发生。
LockCursor(true);
}
private void OnDisable()
{
// 对象被禁用(非拥有者,或玩家已下线)时务必释放光标,否则会锁死在别人的机器上。
LockCursor(false);
}
private void Update()
{
Mouse mouse = Mouse.current;
if (mouse == null)
return;
// Esc 释放光标,左键重新抓取(方便编辑器里切出去)。
Keyboard kb = Keyboard.current;
if (kb != null && kb.escapeKey.wasPressedThisFrame)
LockCursor(false);
if (mouse.leftButton.wasPressedThisFrame && Cursor.lockState != CursorLockMode.Locked)
LockCursor(true);
if (Cursor.lockState != CursorLockMode.Locked)
return;
// 新输入系统下 delta 的单位是像素,不是轴值。
Vector2 delta = mouse.delta.ReadValue();
// 横移:转动躯体
if (characterBody != null)
{
characterBody.Rotate(Vector3.up * (delta.x * mouseSensitivity));
}
else if (!_warnedMissingBody)
{
_warnedMissingBody = true;
Debug.LogWarning(
$"[{nameof(MouseLook)}] 未指定 Character Body,水平视角不会生效。请指向玩家根节点的 Transform。",
this);
}
// 纵移:俯仰相机,并夹在上下限之间防止翻转
_xRotation = Mathf.Clamp(_xRotation - (delta.y * mouseSensitivity), minLookAngle, maxLookAngle);
transform.localRotation = Quaternion.Euler(_xRotation, 0f, 0f);
}
private void LockCursor(bool locked)
{
Cursor.lockState = locked ? CursorLockMode.Locked : CursorLockMode.None;
Cursor.visible = !locked;
}
}
}