Unity 导览相机实现:键鼠控制自由漫游(WASD 移动 + 右键旋转)

简介


在虚拟展厅、景区导览、3D 模型预览等场景中,导览相机 是核心交互组件。本文将实现一款轻量、易扩展的导览相机脚本,支持 WASD 移动、QE 升降、右键视角旋转,还可通过 Shift 键加速,适配编辑器 / 运行时环境,新手也能快速上手!

核心功能说明


操作方式 功能效果
W/S/A/D 相机前后左右移动(基于自身朝向)
Q/E 相机垂直升降(世界坐标系 Y 轴)
鼠标右键按住 + 鼠标拖动 旋转相机视角(水平 / 垂直)
Left Shift 按住 移动速度翻倍(加速漫游)

完整代码实现


cs 复制代码
using UnityEngine;

/// <summary>
/// 导览相机核心脚本
/// 功能:WASD移动 + QE升降 + 右键旋转 + Shift加速
/// 适用:虚拟导览、展厅漫游、3D模型预览等场景
/// </summary>
[DisallowMultipleComponent] // 禁止重复挂载
public class TourCamera : MonoBehaviour
{
    [Header("移动配置")]
    [Tooltip("基础移动速度(单位:米/秒)")]
    public float moveSpeed = 5.0f; // 建议默认值5,更贴合实际漫游体验
    [Tooltip("视角旋转速度(单位:度/秒)")]
    public float rotateSpeed = 90.0f;
    [Tooltip("Shift加速倍率")]
    public float shiftRate = 2.0f;

    [Header("旋转限制(可选扩展)")]
    [Tooltip("垂直旋转最小角度(防止低头过度)")]
    [Range(-89, 0)] public float minVerticalAngle = -60f;
    [Tooltip("垂直旋转最大角度(防止抬头过度)")]
    [Range(0, 89)] public float maxVerticalAngle = 60f;

    private Transform cameraTrans; // 相机Transform缓存
    private float currentVerticalAngle; // 记录垂直旋转角度(用于限制)
    private Vector3 moveDirection; // 最终移动方向向量

    /// <summary>
    /// 初始化(缓存组件,避免重复GetComponent)
    /// </summary>
    private void Start()
    {
        // 优先使用挂载对象的Transform,也可指定外部相机
        cameraTrans = gameObject.transform;
        // 初始化垂直旋转角度(基于相机初始欧拉角)
        currentVerticalAngle = cameraTrans.eulerAngles.x;
    }

    /// <summary>
    /// 每帧更新(处理输入和相机变换)
    /// </summary>
    private void Update()
    {
        // 仅在编辑器/运行时响应(可选:可移除限制,适配打包后)
        if (Application.isEditor || Application.isPlaying)
        {
            HandleInput(); // 处理键鼠输入
            UpdateCameraMovement(); // 更新相机位置
            UpdateCameraRotation(); // 更新相机旋转
        }
    }

    /// <summary>
    /// 处理所有输入事件(输入逻辑单独封装,便于维护)
    /// </summary>
    private void HandleInput()
    {
        // 1. 重置移动方向
        moveDirection = Vector3.zero;

        // 2. Shift加速逻辑(修复原脚本Bug:重复按下Shift导致速度无限倍)
        float currentSpeedMultiplier = Input.GetKey(KeyCode.LeftShift) ? shiftRate : 1f;
        float finalMoveSpeed = moveSpeed * currentSpeedMultiplier;

        // 3. WASD前后左右移动(基于相机自身朝向)
        if (Input.GetKey(KeyCode.W)) moveDirection += cameraTrans.forward;
        if (Input.GetKey(KeyCode.S)) moveDirection -= cameraTrans.forward;
        if (Input.GetKey(KeyCode.A)) moveDirection -= cameraTrans.right;
        if (Input.GetKey(KeyCode.D)) moveDirection += cameraTrans.right;

        // 4. QE垂直升降(世界坐标系Y轴,避免旋转后升降方向偏移)
        if (Input.GetKey(KeyCode.Q)) moveDirection += Vector3.down;
        if (Input.GetKey(KeyCode.E)) moveDirection += Vector3.up;

        // 5. 归一化方向向量(避免斜向移动速度翻倍)
        if (moveDirection.magnitude > 1f)
        {
            moveDirection.Normalize();
        }

        // 6. 应用速度倍率
        moveDirection *= finalMoveSpeed;
    }

    /// <summary>
    /// 更新相机位置(移动逻辑)
    /// </summary>
    private void UpdateCameraMovement()
    {
        // 基于世界坐标系移动(保证升降方向始终为世界Y轴)
        cameraTrans.Translate(moveDirection * Time.deltaTime, Space.World);
    }

    /// <summary>
    /// 更新相机旋转(右键视角控制)
    /// </summary>
    private void UpdateCameraRotation()
    {
        if (Input.GetMouseButton(1)) // 按住鼠标右键
        {
            // 1. 水平旋转(绕世界Y轴,左右拖动鼠标)
            float horizontalRotate = Input.GetAxis("Mouse X") * rotateSpeed * Time.deltaTime;
            cameraTrans.RotateAround(cameraTrans.position, Vector3.up, horizontalRotate);

            // 2. 垂直旋转(绕相机自身X轴,上下拖动鼠标,带角度限制)
            float verticalRotate = -Input.GetAxis("Mouse Y") * rotateSpeed * Time.deltaTime;
            currentVerticalAngle += verticalRotate;
            // 限制垂直旋转角度,防止相机翻转
            currentVerticalAngle = Mathf.Clamp(currentVerticalAngle, minVerticalAngle, maxVerticalAngle);

            // 3. 应用垂直旋转(重置X轴欧拉角,避免万向节死锁)
            Vector3 currentEuler = cameraTrans.eulerAngles;
            cameraTrans.eulerAngles = new Vector3(currentVerticalAngle, currentEuler.y, currentEuler.z);
        }
    }

    /// <summary>
    /// 可选:Gizmos绘制相机移动方向(调试用)
    /// </summary>
    private void OnDrawGizmos()
    {
        Gizmos.color = Color.red;
        Gizmos.DrawRay(cameraTrans.position, moveDirection.normalized * 2f);
    }
}
相关推荐
技术探讨者19 小时前
极境导表工具 —— 让配置数据成为游戏开发的效率引擎
unity·编辑器·ai编程·游戏策划
游乐码19 小时前
Unity基础(六)小案例
游戏·unity·游戏引擎
Alaso_shuang20 小时前
视觉组通识
数码相机·算法·计算机视觉
Sator11 天前
Unity2022版接入MCP
unity·ai编程
kyle~1 天前
机器视觉---熔池相机(穿透强光的视觉感知)
c++·数码相机·计算机视觉·机器人·焊接机器人
3DVisionary2 天前
精密模具电极如何测形变?蓝光三维扫描3D检测方案解析
c++·数码相机·蓝光三维扫描·质量控制 qc·形位公差分析·模具电极检测·非接触三维测量
相信神话20212 天前
第四章:创建《酒魂》项目与场景结构
游戏·游戏引擎·godot·2d游戏开发
mxwin2 天前
Unity Shader URP 使用模板测试 · 深度测试实现秘境空间效果
unity·游戏引擎·shader
YANQ6622 天前
6. Gemini相机+yoloseg+foundationpose环境搭建及应用
人工智能·数码相机
真鬼1233 天前
【Unity 6】Unity6快捷下载,快速下载
unity·游戏引擎