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

如何在平面法向量定义的斜面上旋转?坦克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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 04:26:01