You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

Unity 3D 6.0版本:Z轴倾斜后鼠标视角反转问题求助

问题:Z轴倾斜操作后鼠标视角反转

开发第一人称太空游戏时,给带有Rigidbody组件的空物体同时挂载了TiltMovement和Mouse Look脚本。通过TiltMovement执行Z轴左右倾斜后,Mouse Look控制的鼠标视角会出现反转现象,只有当Z轴旋转值回到0时才恢复正常。游戏需要保留滚动倾斜效果,无法移除,需排查解决该问题。

TiltMovement脚本代码

void TiltMovement()
{
    float tiltRight = Input.GetKey(GameManager.Instance.InputManager.GetKey("TiltRight")) ? 1 : Input.GetKey(GameManager.Instance.InputManager.GetKey("TiltLeft")) ? -1 : 0;

    if (tiltRight != 0)
    {
        // Calculate the rotation amount based on the tilt input
        float tiltAmount = tiltRight * tiltSpeed * Time.deltaTime;

        // Apply Z-axis rotation in local space
        transform.Rotate(Vector3.forward, -tiltAmount, Space.Self);
    }
}

Mouse Look脚本代码

void HandleMouseLook()
{
    float mouseX = Input.GetAxis("Mouse X") * lookSpeed * Time.deltaTime;
    float mouseY = Input.GetAxis("Mouse Y") * lookSpeed * Time.deltaTime;

    targetMouseDelta = new Vector2(mouseX, mouseY);
    currentMouseDelta = Vector2.Lerp(currentMouseDelta, targetMouseDelta, smoothFactor * Time.deltaTime);

    rotationY += currentMouseDelta.x;
    rotationX -= currentMouseDelta.y;
    rotationX = Mathf.Clamp(rotationX, -clampAngle, clampAngle);

    // Apply rotations in local space
    transform.Rotate(Vector3.up, rotationY, Space.Self); // Rotate around local Y axis
    transform.Rotate(Vector3.right, rotationX, Space.Self); // Rotate around local X axis
}

问题根源与修复方案

根源

两个脚本直接修改同一物体的本地旋转,且Mouse Look使用累积旋转值叠加Rotate操作。当Z轴(本地forward轴)旋转后,物体的本地up、right轴方向发生偏移,后续的Rotate操作会基于偏移后的轴计算,导致视角旋转方向混乱,出现反转。

修复方案1:使用父子物体分离旋转(推荐)

将旋转职责拆分:

  • 根空物体挂载TiltMovement脚本,负责Z轴倾斜操作
  • 创建子物体,挂载Mouse Look脚本和相机,负责XY轴视角旋转

这样两个旋转操作在不同层级的Transform上执行,互相完全独立,不会产生干扰。

修复方案2:修改脚本使用欧拉角直接设置(同物体挂载)

如果必须将两个脚本挂载在同一物体上,修改Mouse Look脚本,改用localEulerAngles直接设置旋转值,避免叠加旋转:

修改后的Mouse Look代码:

void HandleMouseLook()
{
    float mouseX = Input.GetAxis("Mouse X") * lookSpeed * Time.deltaTime;
    float mouseY = Input.GetAxis("Mouse Y") * lookSpeed * Time.deltaTime;

    targetMouseDelta = new Vector2(mouseX, mouseY);
    currentMouseDelta = Vector2.Lerp(currentMouseDelta, targetMouseDelta, smoothFactor * Time.deltaTime);

    rotationY += currentMouseDelta.x;
    rotationX -= currentMouseDelta.y;
    rotationX = Mathf.Clamp(rotationX, -clampAngle, clampAngle);

    // 直接设置本地欧拉角,保留当前Z轴旋转,仅修改X、Y轴
    Vector3 currentEuler = transform.localEulerAngles;
    transform.localEulerAngles = new Vector3(rotationX, rotationY, currentEuler.z);
}

同时可以优化TiltMovement脚本,用欧拉角设置避免累积旋转误差:

void TiltMovement()
{
    float tiltRight = Input.GetKey(GameManager.Instance.InputManager.GetKey("TiltRight")) ? 1 : Input.GetKey(GameManager.Instance.InputManager.GetKey("TiltLeft")) ? -1 : 0;

    if (tiltRight != 0)
    {
        float tiltAmount = tiltRight * tiltSpeed * Time.deltaTime;
        Vector3 currentEuler = transform.localEulerAngles;
        // 转换Z轴角度到-180~180范围,避免360度循环导致的异常
        float currentZ = Mathf.DeltaAngle(0, currentEuler.z);
        currentZ -= tiltAmount;
        // 可选:添加Z轴倾斜角度限制
        // currentZ = Mathf.Clamp(currentZ, -45f, 45f);
        transform.localEulerAngles = new Vector3(currentEuler.x, currentEuler.y, currentZ);
    }
}

通过这种方式,两个脚本分别控制不同的欧拉轴,旋转操作不会互相干扰,Z轴倾斜后XY视角旋转也能保持正常方向。

内容的提问来源于stack exchange,提问作者Patryk Patek2 Waraksa

火山引擎 最新活动