转动时倾斜第一人称相机的 z 轴

Tilt first person camera's z axis while turning

我正在研究具有 boost/dash 功能的双足坦克的控制。 当通过按住按钮激活 boost/dash 模式时,坦克从传统的 WASD 扫射运动变为类似于喷气式战斗机但在地面上的运动。 现在,当玩家试图在加速时转弯时,相机需要随着转弯方向倾斜,以使其感觉更顺畅。

Here is a video clip showing my problem

这是添加到主摄像头的脚本

public class PlayerCameraTilt : MonoBehaviour
{
    private Camera viewCam;
    private CharacterController characterController;

    public float tiltAmount = 10f;

    private void Start()
    {
        viewCam = GetComponent<Camera>();
        characterController = GetComponentInParent<CharacterController>();
    }

    private void Update()
    {
        if (characterController.GetComponent<PlayerController>().movementState == MovementModes.boost)
        {
            float inputValue = Input.GetAxis("MoveHorizontal") * tiltAmount;
            Vector3 euler = transform.localEulerAngles;
            euler.z = Mathf.Lerp(euler.z, -inputValue, 5f * Time.deltaTime);
            transform.localEulerAngles = euler;

        }
        else
        {
            Vector3 euler = transform.localEulerAngles;
            euler.z = Mathf.Lerp(euler.z, 0f, 5f * Time.deltaTime);
            transform.localEulerAngles = euler;
        }

    }
}

有点效果,但只能在一个旋转方向上,即正方向。如果我转向另一个方向,角度变为负值并进行整个 360 度旋转,直到它以 0 度结束。

我尝试使用内置的四元数方法,例如 Quaternion.Rotate() 或 Quaternion.AngleAxis() 但它们不起作用,因为 Quaternion.Rotate() 不会倾斜相机,而是完全旋转它。 Quaternion.AngleAxis() 适用于整个倾斜角度限制,但也会对我不想修改的另一个轴做一些事情。

有什么方法可以防止当轴输入为负值,只是稍微倾斜一个角度时,相机就不会做完整的 360° 旋转吗?

撇开环绕问题不谈,z 组件是 "applied" 欧拉组件中的第一个,因此我不会像在本应用程序中那样直接修改它。

相反,我会将输入转换为倾斜角度,在应用 localRotation (Quaternion.Inverse(transform.localRotation) * transform.up) 之前将局部向上旋转该角度,然后使用 Quaternion.LookRotation 找到一个旋转当前向前和向上,然后使用 Quaternion.Slerp 向该旋转旋转:

private void Update()
{
    if (characterController.GetComponent<PlayerController>().movementState == MovementModes.boost)
    {
        float inputValue = Input.GetAxis("MoveHorizontal") * tiltAmount;

        Vector3 upOfParent = Quaternion.Inverse(transform.localRotation) * transform.up;

        Vector3 upDir = Quaternion.AngleAxis(-inputValue, transform.forward) * upOfParent;

        Quaternion goalRot = Quaternion.LookRotation(transform.forward, upDir);

        transform.rotation = Quaternion.Slerp(transform.rotation, goalRot, 5f * Time.deltaTime);
    }
    else
    {
        float inputValue = Input.GetAxis("MoveHorizontal") * tiltAmount;

        Vector3 upOfParent = Quaternion.Inverse(transform.localRotation) * transform.up;

        Quaternion goalRot = Quaternion.LookRotation(transform.forward, upOfParent);

        transform.rotation = Quaternion.Slerp(transform.rotation, goalRot, 5f * Time.deltaTime);
    }

}

请记住,对 lerp/slerp 操作使用 t = 5f * Time.deltaTime 并不总是保证输出永远等于 to 参数。