为了使某个物体A通过旋转面向另一物体B,如AI转向玩家。
旋转1
通常会先考虑判断B在A的左边还是右边,然后在控制A向左转或者向右转。当A的forward和B的夹角小于某一个值时则认为A已经面向了B,这时停止旋转。
//先将目标坐标转换到本地坐标系 Vector3 pos = transform.InverseTransformPoint(target.position); //将A和B转到同一平面 pos.y = 0; if (Vector3.Angle(Vector3.forward, pos) > 1) { //用向量乘积判断左右 Vector3 cross = Vector3.Cross(Vector3.forward, pos); if (cross.y > 0) { //右边 transform.Rotate(new Vector3(0, rotateSpeed * Time.deltaTime, 0)); } else { //左边 transform.Rotate(new Vector3(0, -1 * rotateSpeed * Time.deltaTime, 0)); } }
旋转2
平滑的旋转
用到了两个APIpublic static Quaternion LookRotation(Vector3forward,Vector3upwards = Vector3.up);
参数:
forward 要面向的方向
upwards 定义up方向的向量
描述:
用forward和upwards创建一个旋转。
返回一个经过计算的四元数。如果用来确定Transform的方向,z轴与 forward对齐,y轴与upwards对齐。
public static Quaternion Slerp(Quaterniona,Quaternionb,floatt);
描述:
通过t返回a和b之间的差值。t必须在0和1之间。
代码:
Vector3 lookForward = target.position - transform.position; lookForward.y = 0; Quaternion lookQua = Quaternion.LookRotation(lookForward); transform.rotation = Quaternion.Slerp(transform.rotation, lookQua, rotateSpeed * Time.deltaTime);这种方式会产生一个平滑的旋转,旋转速度会在快要结束时逐渐减小。
旋转3
有时候我们希望每次的旋转幅度都是常量,而不是在结尾的时候减小。
用到的API
public static float MoveTowardsAngle(float current,float target,float maxDelta);
描述:
类似于MoveTowards, 但是这个函数确保其值在超过360度时仍然是正确的。
变量current和target被假定为角度。为了最优化的原因,不支持maxDelta为负值,如果为负值肯能出现摆动。
(这个函数每次执行就是在current的基础上增加maxDelta,但是结果不会超过target。如果target大于current,就执行current+maxDelta,如果target小于current则执行 current-maxDelta)
代码:
Vector3 lookForward = target.position - transform.position; lookForward.y = 0; Quaternion lookQua = Quaternion.LookRotation(lookForward); float targetAngle = lookQua.eulerAngles.y; float currentAngle = transform.rotation.eulerAngles.y; float nextAngle = Mathf.MoveTowardsAngle(currentAngle, targetAngle, rotateSpeed * Time.deltaTime); transform.eulerAngles = new Vector3(0, nextAngle, 0);
这种方式不用考虑向左转还是向右转的问题