在Unity中,常用的旋转方式有三种,分别是transform.Rotate(参数),欧拉角旋转,和今天我们要聊的四元数。虽然四元数理解起来不如欧拉角那么直观,但是它却能很好的避免了万向锁问题,而且在限制旋转角度方面也是一把好手,同时,四元数自带球面线性插值(Slerp)。
一,使用四元数Slerp控制开关车门
1.创建车门,大概如下图所示:
2.创建一个脚本,直接挂在车门上,代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Test : MonoBehaviour
{
/// <summary>
/// 初始的旋转状态
/// </summary>
private Quaternion InitialRotation;
/// <summary>
/// 打开后的旋转状态
/// </summary>
private Quaternion OpenRotation;
/// <summary>
/// 门的当前状态
/// </summary>
private bool DoorCurrentState;
void Start()
{
InitialRotation = transform.localRotation;
OpenRotation = Quaternion.Euler(transform.localEulerAngles.x, transform.localEulerAngles.y, transform.localEulerAngles.z - 90f);
}
void Update()
{
if (Input.GetKey(KeyCode.Alpha1))
{
float result = Quaternion.Dot(transform.localRotation, OpenRotation);
if (result != 1 && result != -1)
{
transform.localRotation = Quaternion.Slerp(transform.localRotation, OpenRotation, 0.2f);
}
else
{
Debug.Log("完成开门");
DoorCurrentState = true;
}
}
if (Input.GetKey(KeyCode.Alpha2))
{
float result = Quaternion.Dot(transform.localRotation, InitialRotation);
if (result != 1 && result != -1)
{
transform.localRotation = Quaternion.Slerp(transform.localRotation, InitialRotation, 0.2f);
}
else
{
Debug.Log("完成关门");
DoorCurrentState = false;
}
}
}
}
二,使用四元数制作简易的第一人称控制器
1.创建一个Cube并将主置为他的子物体,并将所有的旋转置零,如下图
2.创建控制移动的脚本并拖到Cube上,代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FirstPersonMove : MonoBehaviour
{
private float MoveSpeed = 8;
private void FixedUpdate()
{
float x = Input.GetAxis("Horizontal");
float y = Input.GetAxis("Vertical");
if (x != 0 || y != 0)
{
transform.Translate(Vector3.right * x * Time.deltaTime * MoveSpeed);
transform.Translate(Vector3.forward * y * Time.deltaTime * MoveSpeed);
}
}
}
3.这样我们就能通过WASD键来控制Cube移动了,剩下的就是控制相机的旋转了,代码如下:
using UnityEngine;
public class FirstPersonLook : MonoBehaviour
{
public float sensitivity = 2;
public float smoothing = 1.5f;
Vector2 velocity;
Vector2 frameVelocity;
private void FixedUpdate()
{
Vector2 mouseDelta = new Vector2(Input.GetAxisRaw("Mouse X"), Input.GetAxisRaw("Mouse Y"));
Vector2 rawFrameVelocity = Vector2.Scale(mouseDelta, Vector2.one * sensitivity);
frameVelocity = Vector2.Lerp(frameVelocity, rawFrameVelocity, 1 / smoothing);
velocity += frameVelocity;
velocity.y = Mathf.Clamp(velocity.y, -120, 90);
transform.localRotation = Quaternion.AngleAxis(-velocity.y, Vector3.right);
transform.parent.localRotation = Quaternion.AngleAxis(velocity.x, Vector3.up);
}
}
该代码分为三部分,第一部分是为了获得一个平滑的velocoty,第二部分是控制相机的视角的上下移动,第三部分则是控制Cube的左右旋转,由于主相机是Cube的子物体,所以Cube左右旋转相对而言,我们看到的就是主相机视角的左右移动。
至此,一个简易的第一人称控制器就完成了(别忘了给Cube添加个刚体和摩檫力,否则不能上下坡了)。