Unity3d 脚本应用旋转两次?

Unity3d script applying rotation twice?

我一直在研究一个简单的 space 车辆控制器,它允许移动、偏航、滚动和俯仰。它在每个轴上都很好用,但是当我偏航和滚动、俯仰和移动等时,旋转是不正确的。我相信事情发生了两次,因为当车辆处于 90 度俯仰角时,它应该垂直移动时水平移动(90 度旋转时偏离 90 度)。 45 岁时,它处于中间位置。在 0 时它按预期工作。

我的完整代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player_Input : MonoBehaviour
{

    private Rigidbody rb;
    public float moveAcceleration = 50f;
    public float maxMoveSpeed = 500f;
    public float turnAcceleration = 30f;
    public float maxTurnSpeed = 100f;
    public float rotAcceleration = 30f;
    public float maxRotSpeed = 100f;

    private float moveSpeed = 0;
    private float pitchSpeed = 0;
    private float yawSpeed = 0;
    private float rollSpeed = 0;
    private Vector3 angle = new Vector3 (0, 0, 0);

    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        if(Input.GetKey("w")) {
            moveSpeed += moveAcceleration * Time.deltaTime;
        } else if(Input.GetKey("s")) {
            moveSpeed -= moveAcceleration * Time.deltaTime;
        }

        if(moveSpeed > 10f) {
            moveSpeed -= 5f * Time.deltaTime;
        }else if(moveSpeed < -10f) {
            moveSpeed += 5f * Time.deltaTime;
        } else if(!Input.GetKey("w") && !Input.GetKey("s")) {
            moveSpeed = 0f;
        }

        moveSpeed = Mathf.Clamp(moveSpeed, -maxMoveSpeed, maxMoveSpeed);


        if(Input.GetKey("a")) {
            yawSpeed += turnAcceleration * Time.deltaTime;
        } else if(Input.GetKey("d")) {
            yawSpeed -= turnAcceleration * Time.deltaTime;
        }       

        if(yawSpeed > 10f) {
            yawSpeed -= 5f * Time.deltaTime;
        }else if(yawSpeed < -10f) {
            yawSpeed += 5f * Time.deltaTime;
        } else if(!Input.GetKey("a") && !Input.GetKey("d")) {
            yawSpeed = 0f;
        }

        yawSpeed = Mathf.Clamp(yawSpeed, -maxTurnSpeed, maxTurnSpeed);

        if(Input.GetKey("left")) {
            rollSpeed += rotAcceleration * Time.deltaTime;
        } else if(Input.GetKey("right")) {
            rollSpeed -= rotAcceleration * Time.deltaTime;
        }        

        if(rollSpeed > 10f) {
            rollSpeed -= 5f * Time.deltaTime;
        }else if(rollSpeed < -10f) {
            rollSpeed += 5f * Time.deltaTime;
        } else if(!Input.GetKey("left") && !Input.GetKey("right")) {
            rollSpeed = 0f;
        }

        rollSpeed = Mathf.Clamp(rollSpeed, -maxRotSpeed, maxRotSpeed);

        if(Input.GetKey("up")) {
            pitchSpeed += turnAcceleration * Time.deltaTime;
        } else if(Input.GetKey("down")) {
            pitchSpeed -= turnAcceleration * Time.deltaTime;
        }        

        if(pitchSpeed > 10f) {
            pitchSpeed -= 5f * Time.deltaTime;
        }else if(pitchSpeed < -10f) {
            pitchSpeed += 5f * Time.deltaTime;
        } else if(!Input.GetKey("up") && !Input.GetKey("down")) {
            pitchSpeed = 0f;
        }

        pitchSpeed = Mathf.Clamp(pitchSpeed, -maxTurnSpeed, maxTurnSpeed);


        this.transform.Translate(moveSpeed * transform.forward * Time.deltaTime);
        angle += Time.deltaTime * ((pitchSpeed * transform.right) + (rollSpeed * transform.forward) + (yawSpeed * transform.up));
        //Debug.Log(transform.forward);
        this.transform.eulerAngles = angle;

    }
}

相关的位在最后(加速度和预期的工作),就在设置角度的地方。变换是正确的(我已经检查过),但应用的动作不正确。你看到问题了吗?

谢谢,我很感激!

编辑:GameObject 上也只有 1 个脚本实例,只是为了进一步缩小范围。

编辑 2:我发现 this 论坛 post 似乎有同样的问题,但我不认为我做过与此人相同的事情。也许是一个好的起点?

编辑 3:我觉得“angle += ...”行是罪魁祸首,但我说不出原因。也许看那里。

使用 Quaterion class 来避免万向节锁定并将当前旋转与新的附加旋转相乘。我修改了你脚本的最后几行:

> angle = new Vector3(pitchSpeed, yawSpeed, rollSpeed);
> transform.rotation *= Quaternion.Euler(angle);
> transform.Translate(moveSpeed * transform.forward * Time.deltaTime, Space.World);

你会想大大减少这些,我把它们除以 10,看起来很平滑:

public float turnAcceleration = 30f;
public float maxTurnSpeed = 100f;
public float rotAcceleration = 30f;
public float maxRotSpeed = 100f;

不确定您是希望偏航方向是按下的方向还是反转的方向,目前如果您按下左键,它就会向右偏航,如果需要,您可以反转这些方向:

if(Input.GetKey("a")) {
   yawSpeed += turnAcceleration * Time.deltaTime;
} else if(Input.GetKey("d")) {
   yawSpeed -= turnAcceleration * Time.deltaTime;
}  

如果您正在制作 space 游戏,您可能需要考虑使用 https://docs.unity3d.com/ScriptReference/Mathf.SmoothDamp.html or https://docs.unity3d.com/ScriptReference/Vector3.SmoothDamp.html 平滑 moveSpeed , pitchSpeed, yawSpeed, rollSpeed 以使动作更逼真。