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
相关产品推荐
相关产品推荐

