You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity C#实现玩家随鼠标旋转:仿Valorant第一人称朝向控制

实现Valorant风格鼠标指向移动(Unity C#)

核心逻辑

玩家移动方向由鼠标在地面平面的投影指向决定,而非自身初始朝向。通过将鼠标屏幕坐标转换为世界空间的地面交点,以此为参考计算移动方向,同时保持玩家自身不随鼠标旋转,仅相机完成环视操作。

实现步骤

1. 前置组件配置

确保玩家对象拥有:

  • CharacterController(负责移动物理)
  • 主相机(设为玩家子物体,用于第一人称环视)

2. 完整代码实现

using UnityEngine;

[RequireComponent(typeof(CharacterController))]
public class PlayerMouseDirectionMovement : MonoBehaviour
{
    [Header("移动参数")]
    public float moveSpeed = 6f;
    public float mouseSensitivity = 2.5f;

    [Header("地面设置")]
    public float groundYLevel = 0f; // 场景地面的Y轴高度,按需调整
    public LayerMask groundLayer; // 可选:用碰撞层替代平面检测,适配复杂地形

    private CharacterController _controller;
    private Camera _mainCamera;

    void Start()
    {
        _controller = GetComponent<CharacterController>();
        _mainCamera = Camera.main;

        // 锁定鼠标至屏幕中心,隐藏光标
        Cursor.lockState = CursorLockMode.Locked;
        Cursor.visible = false;
    }

    void Update()
    {
        HandleCameraLook();
        HandleDirectionalMovement();
    }

    void HandleCameraLook()
    {
        // 获取鼠标输入增量
        float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity;
        float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity;

        // 相机上下旋转(限制俯仰角度,避免翻转)
        float currentPitch = _mainCamera.transform.localEulerAngles.x - mouseY;
        currentPitch = currentPitch > 180f ? currentPitch - 360f : currentPitch;
        currentPitch = Mathf.Clamp(currentPitch, -85f, 85f);
        
        // 相机左右旋转(玩家自身不旋转)
        _mainCamera.transform.localEulerAngles = new Vector3(
            currentPitch,
            _mainCamera.transform.localEulerAngles.y + mouseX,
            0f
        );
    }

    void HandleDirectionalMovement()
    {
        // 获取WASD输入
        float horizontal = Input.GetAxis("Horizontal");
        float vertical = Input.GetAxis("Vertical");

        // 无输入时直接返回
        if (Mathf.Abs(horizontal) < 0.01f && Mathf.Abs(vertical) < 0.01f) return;

        // 生成鼠标射线,检测地面交点
        Ray mouseRay = _mainCamera.ScreenPointToRay(Input.mousePosition);
        Vector3 moveDirection = Vector3.zero;

        // 方式1:平面检测(适用于平坦地面)
        Plane groundPlane = new Plane(Vector3.up, new Vector3(0, groundYLevel, 0));
        if (groundPlane.Raycast(mouseRay, out float planeDistance))
        {
            Vector3 targetPoint = mouseRay.GetPoint(planeDistance);
            moveDirection = Vector3.ProjectOnPlane(targetPoint - transform.position, Vector3.up).normalized;
        }

        // 方式2:碰撞层检测(适用于复杂地形,注释掉上方平面检测启用此段)
        //if (Physics.Raycast(mouseRay, out RaycastHit hit, 100f, groundLayer))
        //{
        //    moveDirection = Vector3.ProjectOnPlane(hit.point - transform.position, Vector3.up).normalized;
        //}

        // 构建基于鼠标指向的移动坐标系
        Vector3 rightDir = Vector3.Cross(Vector3.up, moveDirection).normalized;
        Vector3 forwardDir = moveDirection;
        Vector3 finalMove = (forwardDir * vertical) + (rightDir * horizontal);

        // 应用移动
        _controller.Move(finalMove * moveSpeed * Time.deltaTime);
    }
}

3. 关键细节说明

  • 相机环视:仅旋转相机(玩家子物体),玩家自身transform.rotation始终保持初始状态,不随鼠标操作改变。
  • 移动方向计算:通过射线检测将鼠标位置映射到世界地面,提取水平方向作为移动参考轴,WASD输入会基于此轴转换为实际移动方向(W朝向鼠标点,S反向,A向鼠标左侧,D向右侧)。
  • 地形适配:平坦场景用平面检测即可,复杂地形可启用碰撞层检测,指定地面层级后射线会自动识别地形表面。

4. 手感调整建议

  • 修改moveSpeed和mouseSensitivity参数适配游戏节奏。
  • 若移动时出现打滑感,可在HandleDirectionalMovement中对finalMove做归一化处理。

内容的提问来源于stack exchange,提问作者Guts

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 09:55:28