如何在平面法向量定义的斜面上旋转?坦克Y轴旋转锁定求助
问题描述
我在做学校作业,开发一款坦克瞄准射击游戏。需要用射线检测(Raycasting)让坦克和平面法向量对齐,但设置后坦克Y轴旋转被锁定,没法继续旋转。需求是坦克能贴合斜面,transform.up由平面法向量定义,同时能在斜面上移动和旋转。
原代码
public class PlayerController : MonoBehaviour { public GameObject player; public float movementSpeed; public float rotationSpeed; RaycastHit hitinfo; public float hoverHeight = 0.7f; float offsetdistance; //public Vector2 moveVal; public Vector2 moveVal; public Vector3 Dir; public float moveSpeed; //get OnMove input and put it in a vector to be used later on void OnMove(InputValue value) { moveVal = value.Get<Vector2>(); } void Update() { //moves player PlayerHover(); player.transform.Translate(new Vector3(0, 0, moveVal.y) * moveSpeed * Time.deltaTime); player.transform.Rotate(0, moveVal.x * rotationSpeed * Time.deltaTime, 0, Space.Self); } void PlayerHover() { if (Physics.Raycast(transform.position, -Vector3.up, out hitinfo, 20f)) { offsetdistance = hoverHeight - hitinfo.distance; transform.up = hitinfo.normal; transform.position = new Vector3(transform.position.x, transform.position.y + offsetdistance, transform.position.z); } } }
解决方案
问题根源
直接赋值transform.up = hitinfo.normal会强制覆盖物体的整个旋转,包括Y轴的转向,导致旋转操作失效。正确做法是保留Y轴旋转,只调整X、Z轴让up向量贴合斜面。
修改后的代码
public class PlayerController : MonoBehaviour { public GameObject player; public float movementSpeed; public float rotationSpeed; RaycastHit hitinfo; public float hoverHeight = 0.7f; float offsetdistance; public Vector2 moveVal; public float moveSpeed; void OnMove(InputValue value) { moveVal = value.Get<Vector2>(); } void Update() { PlayerHover(); // 沿着坦克自身前方向移动,适配斜面环境 player.transform.Translate(player.transform.forward * moveVal.y * moveSpeed * Time.deltaTime, Space.World); // 保留Y轴旋转操作 player.transform.Rotate(0, moveVal.x * rotationSpeed * Time.deltaTime, 0, Space.Self); } void PlayerHover() { if (Physics.Raycast(transform.position, -Vector3.up, out hitinfo, 20f)) { offsetdistance = hoverHeight - hitinfo.distance; transform.position = new Vector3(transform.position.x, transform.position.y + offsetdistance, transform.position.z); // 保留当前Y轴的转向,将前方向投影到斜面平面上 Vector3 projectedForward = Vector3.ProjectOnPlane(transform.forward, hitinfo.normal).normalized; // 构建目标旋转:up对齐斜面法向量,forward对齐投影后的前方向 Quaternion targetRotation = Quaternion.LookRotation(projectedForward, hitinfo.normal); // 平滑过渡到目标旋转,避免生硬跳转 transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, Time.deltaTime * 10f); } } }
关键改动说明
- 旋转逻辑重构:用
Quaternion.LookRotation构建旋转,既保证transform.up贴合斜面法向量,又通过投影前方向保留了Y轴的转向控制。 - 移动方向修正:把世界空间Z轴移动改成坦克自身前方向移动,确保在斜面上移动时方向符合操作预期。
- 平滑过渡:使用
Quaternion.Lerp让坦克贴合斜面的过程更自然,减少突兀感。
内容的提问来源于stack exchange,提问作者logi
相关产品推荐
相关产品推荐

