我目前正在使用 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);
}
}
}
如有任何帮助,我们将不胜感激!
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);
}