如何让Unity角色旋转与相机rotation一致,按下W沿相机朝向移动
问题根因
- 你当前的移动逻辑用的是世界坐标系的固定方向(
Vector3.forward/Vector3.left等),和相机/角色的朝向完全无关,所以不管怎么旋转相机,移动方向都是固定的 - 两个脚本同时修改
target.rotation会出现执行顺序冲突,原相机脚本也没有处理Y轴旋转限制,容易出现视角翻转问题 - 刚体速度修改逻辑写在
Update里会受帧率波动影响,不符合Unity物理系统的规范 - 没有对移动方向的Y轴做过滤,相机抬头低头时会导致角色往天空/地面方向偏移
修复步骤
- 删掉相机脚本里的
target.rotation = Cam.rotation逻辑,只保留角色移动脚本里的朝向同步,避免执行顺序冲突 - 移动方向改用相机的朝向向量,过滤Y轴分量保证角色只在水平面上移动
- 把刚体相关的操作移到
FixedUpdate中执行 - 初始化移动速度基础值,新增方向归一化逻辑避免斜向移动速度过快
修正后角色移动脚本
public Rigidbody rb; public float moveSpeed = 5f; // 初始化基础移动速度 public Transform Cam; public Transform target; private Vector3 moveDir; // 物理操作统一放在FixedUpdate执行 private void FixedUpdate() { // 仅同步水平方向朝向,避免相机抬头低头导致角色歪倒 target.rotation = Quaternion.Euler(0, Cam.rotation.eulerAngles.y, 0); // 把本地坐标系方向转为世界坐标系方向后应用速度 rb.velocity = target.TransformDirection(moveDir) * moveSpeed; } void Update() { moveDir = Vector3.zero; // Update仅做输入检测,不直接操作刚体 if (Input.GetKey(KeyCode.W)) { moveDir += Vector3.forward; } if (Input.GetKey(KeyCode.S)) { moveDir += Vector3.back; } if (Input.GetKeyDown(KeyCode.Space)) { rb.velocity = new Vector3(rb.velocity.x, moveSpeed, rb.velocity.z); } if (Input.GetKey(KeyCode.A)) { moveDir += Vector3.left; } if (Input.GetKey(KeyCode.D)) { moveDir += Vector3.right; } // 速度切换逻辑 if(Input.GetKey(KeyCode.LeftShift)) { moveSpeed = 8f; } else if(Input.GetKey(KeyCode.LeftControl)) { moveSpeed = 3f; } else { moveSpeed = 5f; // 松开按键后恢复默认速度 } // 方向向量归一化,避免斜向移动速度过快 if (moveDir.magnitude > 1) { moveDir.Normalize(); } }
修正后相机跟随脚本
public float rotateSpeed; private float moveX; public Transform target; public Vector3 offset; private float moveY; // 限制上下视角范围,避免视角翻转 public float minViewAngle = -60f; public float maxViewAngle = 60f; void Update() { transform.position = target.position + offset; moveX = Input.GetAxis("Mouse X"); moveY = Input.GetAxis("Mouse Y"); // 水平旋转绕世界Y轴,垂直旋转绕自身X轴 transform.Rotate(Vector3.up, moveX * rotateSpeed * Time.deltaTime, Space.World); transform.Rotate(Vector3.right, -moveY * rotateSpeed * Time.deltaTime, Space.Self); // 对垂直旋转角度做钳制 Vector3 currentEuler = transform.localEulerAngles; currentEuler.x = ClampAngle(currentEuler.x, minViewAngle, maxViewAngle); currentEuler.z = 0; transform.localEulerAngles = currentEuler; } // 角度钳制辅助方法,处理0-360度的跳转问题 private float ClampAngle(float angle, float min, float max) { if (angle < 0f) angle += 360f; if (angle > 180f) angle -= 360f; return Mathf.Clamp(angle, min, max); }
内容的提问来源于stack exchange,提问作者Dark Lighter16
相关产品推荐
相关产品推荐

