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);
    }
}
相关推荐
沉默金鱼17 小时前
Unity实用技能-UI进度条
ui·unity·游戏引擎
老朱佩琪!1 天前
Unity离线开发经验分享
unity·游戏引擎
Sator11 天前
unity的GPUInstance和GPU动画
unity·游戏引擎
沉默金鱼2 天前
Unity实用技能-模型
unity·游戏引擎
阿里云云原生2 天前
AgentRun:如何利用 AI Agent 构建现代化的舆情分析解决方案?
人工智能·unity·游戏引擎
在路上看风景2 天前
2.8 预渲染
unity
老朱佩琪!2 天前
Unity代理模式
unity·游戏引擎·代理模式
技术小甜甜2 天前
【Godot】【入门】GDScript 快速上手(只讲游戏里最常用的 20% 语法)
android·游戏·编辑器·游戏引擎·godot
风途知识百科2 天前
el缺陷检测仪 检测光伏板性能质量的测试设备
数码相机