一种错误的写法
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rotation : MonoBehaviour
{
void Update()
{
Vector3 euler_rotation = transform.rotation.eulerAngles;
euler_rotation += new Vector3(20,20,0) * Time.deltaTime;
transform.rotation = Quaternion.Euler(euler_rotation);
}
}

可以看到物体只有一开始在 X 轴上是有旋转的,后面就 “卡住了”,具体的原因可以在学习了四元数与欧拉角的转换之后再探究,现在只需要知道如果想要使用欧拉角旋转,需要将整个旋转角度存在一个变量里面,不能直接从四元数获取。具体写法参考如下:
控制欧拉角的写法
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rotation : MonoBehaviour
{
private Vector3 rotation;
private Vector3 EulerRotation
{
get { return rotation; }
set {
Vector3 temp = value;
if (temp.x > 360)
{
temp.x -= 360;
}
if (temp.y > 360)
{
temp.y -= 360;
}
if(temp.z > 360)
{
temp.z -= 360;
}
rotation = temp;
}
}
// Start is called before the first frame update
void Start()
{
EulerRotation = transform.rotation.eulerAngles;
}
// Update is called once per frame
void Update()
{
EulerRotation += new Vector3(20,20,0) * Time.deltaTime;
transform.rotation = Quaternion.Euler(EulerRotation);
}
}
可以很直观的从欧拉角知道旋转的效果。这里其实就是将目标欧拉角一直存储在一个单独的 Vertor3 里面。
在这个过程中物体在 Inspector 面板的旋转会基本跟预期的一样,也就是说如果设置的旋转是 Vector3(20,20,0) * Time.deltaTime
,那么它在 Z 轴的旋转就不会变。看图可以看到一开始 x 和 y 都是同步增长的,但后面就不一样了,过一段时间之后又会恢复到同步增长的状态。

如果使用 Rotate
函数,也就是只在 update
里面写一句 transform.Rotate(new Vector3(20, 20, 0) * Time.deltaTime,Space.World);
那么结果会跟你想象的不太一样。可以看到他的旋转不仅 Z 轴是变化的,而且 X 和 Y 也没有保持统一。

对比一下看看,旋转都是 new Vector3(20, 20, 0) * Time.deltaTime,Space.World;

先站立,再旋转
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rotation : MonoBehaviour
{
private Vector3 point1; // 正方体的一个顶点
private Vector3 point2; // 正方体的相对的那个顶点
private Quaternion targetRotation;
private Quaternion originRotation;
private float timeCount = 0.0f;
private void Start()
{
Renderer render= GetComponent<Renderer>();
point1 = render.bounds.center;
point2 = render.bounds.center;
point1 += render.bounds.extents; // 这里的 extents 是包含缩放的
point2 -= render.bounds.extents;
Vector3 origin_dir = point1 - point2;
originRotation = transform.rotation;
targetRotation = originRotation * Quaternion.FromToRotation(origin_dir, Vector3.up);
}
private void Update()
{
if(timeCount > 1) // 已经到位置了
{
// 写法一:
transform.Rotate(new Vector3(0, 20 * Time.deltaTime, 0), Space.World);
// 写法二:// 两种写法效果一样的
// Vector3 axis = transform.InverseTransformDirection(Vector3.up); // 将世界方向的 up 转换到本地方向
// transform.rotation *= Quaternion.AngleAxis(20 * Time.deltaTime, axis);
}
else // 没有旋转到对应位置
{
timeCount += Time.deltaTime;
transform.rotation = Quaternion.Slerp(originRotation, targetRotation, timeCount);
}
}
}

这个效果即使物体有缩放,也不受影响。先获得两个相对的顶点,然后算出应该旋转到的位置。Slerp
参考 lerp
也比较好理解。
网友评论