如何旋转至面向某个物体

时间:2022-06-28 10:22:56

为了使某个物体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

平滑的旋转

用到了两个API
public 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);

这种方式不用考虑向左转还是向右转的问题