相机旋转且输入反转

问题描述 投票:0回答:1

我目前正在使用 Unity 游戏引擎创建 3D 平台游戏,并且正在遵循本教程系列来获得一些基本的玩家动作:https://www.youtube.com/watch?v=h2d9Wc3Hhi0&list=PLiyfvmtjWC_V_H-VMGGAZi7n5E0gyhc37。当我完成教程的运动部分后,我遇到了一个问题。每当我将鼠标移动到旋转阈值时,相机都会避开阈值并绕 y 轴旋转。旋转后,鼠标输入会反转。这是我的相机控制器代码:

using UnityEngine;

namespace Player
{
    public class CameraController : MonoBehaviour
    {
        public Transform target;
        public Transform orientation;
        public Vector3 offset;
        public bool useOffsetValues;
        public float sensitivity;
        public float maxViewAngle = 85;
        public float minViewAngle = -75;
        public bool invertY;

        private void Start()
        {
            if (!useOffsetValues)
            {
                offset = target.position - transform.position;
            }

            orientation.position = target.position;
            orientation.parent = null;

            Cursor.lockState = CursorLockMode.Locked;
        }

        private void LateUpdate()
        {
            orientation.position = target.position;

            float yaw = Input.GetAxis("Mouse X") * sensitivity * Time.fixedDeltaTime;
            orientation.Rotate(0, yaw, 0);

            float pitch = Input.GetAxis("Mouse Y") * sensitivity * Time.fixedDeltaTime;
            if (invertY) orientation.Rotate(pitch, 0, 0);
            else orientation.Rotate(-pitch, 0, 0);

            if (orientation.rotation.eulerAngles.x > maxViewAngle && orientation.rotation.eulerAngles.x < 180)
            {
                orientation.rotation = Quaternion.Euler(maxViewAngle, orientation.eulerAngles.y, 0);
            }
            if (orientation.rotation.eulerAngles.x < 360 + minViewAngle && orientation.rotation.eulerAngles.x > 180)
            {
                orientation.rotation = Quaternion.Euler(360 + minViewAngle, orientation.eulerAngles.y, 0);
            }

            float yAngle = orientation.eulerAngles.y;
            float xAngle = orientation.eulerAngles.x;
            Quaternion rot = Quaternion.Euler(xAngle, yAngle, 0);
            transform.position = target.position - (rot * offset);

            if (transform.position.y < target.position.y - 0.5f)
            {
                transform.position = new Vector3(transform.position.x, target.position.y - 0.5f, transform.position.z);
            }

            transform.LookAt(target);
        }
    }
}

如有任何帮助,我们将不胜感激!

c# unity-game-engine
1个回答
0
投票

首先,不要将

GetAxis(mouse_axis_name)
乘以增量时间。
GetAxis(mouse_axis_name)
返回一个距离,当乘以增量时间时,该距离没有多大意义。只需使用
float yaw = Input.GetAxis("Mouse X") * sensitivity;
float pitch = Input.GetAxis("Mouse Y") * sensitivity;
即可避免更改帧速率导致的问题

其次,与比较欧拉角分量相比,更容易简单地将

pitch
限制在不会导致旋转超出范围的范围内,使用
Vector3.Angle
计算角度并使用
Mathf.Clamp
进行夹紧。 这解释了从欧拉角转换到
Transform
的内部
Quaternion
表示之间的信息丢失。为此,请设置最小向上和向下角度。这些越大,相机在某些角度上的限制就越多。

第三,偏移量应该只是一段距离,以避免与相机的旋转角度发生冲突。

第四,您可以使用

Quaternion localRotation
来表示相机的状态,而不是整个
Transform
,它会执行一些您甚至不使用的额外操作。使用
Quaternion.Euler(0f, yaw, 0f) * desiredRotation * Quaternion.Euler(pitch, 0f, 0f)
将四元数围绕全局向上旋转
yaw
和局部向右旋转
pitch
,然后使用
desiredRotation * Vector3.forward
找到旋转想要产生的前向。 使用
Quaternion.LookRotation
将其初始化为使相机看着目标的旋转。

总共:

[SerializeField] Transform target;
[SerializeField] float offset;
[SerializeField] bool useOffsetValues;
[SerializeField] float sensitivity;
[SerializeField] float minUpAngle = 5f;
[SerializeField] float minDownAngle = 5f;
[SerializeField] bool invertY;

Quaternion desiredRotation;

void Start()
{
    Vector3 positionDelta = target.position - transform.position;
    if (!useOffsetValues)
    {
        offset = positionDelta;
    }

    desiredRotation = Quaternion.LookRotation(positionDelta);
    Cursor.lockState = CursorLockMode.Locked;
}

void LateUpdate()
{
    float yaw = Input.GetAxis("Mouse X") * sensitivity;
    float pitch = Input.GetAxis("Mouse Y") * sensitivity;
    if (!invertY) pitch = -pitch;

    float angleForwardUp = Vector3.Angle(desiredRotation * Vector3.forward, Vector3.up);
    float angleForwardDown = 180f - angleForwardUp;

    float pitchMin = minUpAngle - angleForwardUp;
    float pitchMax = angleForwardDown - minDownAngle;

    pitch = Mathf.Clamp(pitch, pitchMin, pitchMax);

    desiredRotation = Quaternion.Euler(0f, yaw, 0f) * desiredRotation 
            * Quaternion.Euler(pitch, 0f, 0f);

    transform.position = target.position - (desiredRotation
            * Vector3.forward * offset);

    if (transform.position.y < target.position.y - 0.5f)
    {
        transform.position = new Vector3(transform.position.x,
                target.position.y - 0.5f,
                transform.position.z);
    }

    transform.LookAt(target);
}

© www.soinside.com 2019 - 2024. All rights reserved.