Unity3D物体自动躲避障碍物

 Unity版本

        2017.4.4f1

基本思路

        物体向前发射一个射线,检测到碰撞后,根据碰撞信息选择新的方向。最终结果如下。

Unity3D物体自动躲避障碍物_第1张图片

 具体实现步骤代码

1.物体添加胶囊体碰撞组件CapsuleCollider

通过发射虚拟胶囊体来检测碰撞api

bool Physics.CapsuleCast (Vector3 point1, Vector3 point2, float radius, Vector3 direction, out RaycastHit hit, float maxDistance)

 points参数如图所示,radius是Capsule的radius,direction为当前面向,hit为碰撞信息,maxDistance为检测距离:

Unity3D物体自动躲避障碍物_第2张图片

根据参数申请一下变量并初始化:

    //检测距离
    float distance = 1;
    //物体速度
    public float speed = 1;
    //物体下一帧面向
    Vector3 nexForward;
    //capsule端点
    Vector3 point1, point2;
    //capsule组件
    public CapsuleCollider capsule;

    // Use this for initialization
    void Start()
    {
        capsule = GetComponent();
        nexForward = transform.forward;
        point1 = capsule.center - new Vector3(0, 0.5f * capsule.height, 0);
        point2 = capsule.center + new Vector3(0, 0.5f * capsule.height, 0);
    }

2.申请CheckCollision函数来检测碰撞并计算下一帧的面向。

检测到碰撞点后,由碰撞点的Normal方向和物体当前面向来计算新面向。主要方法为

nexForward = Vector3.Cross(hit.normal, Vector3.Cross(transform.forward, hit.normal));

这个公式的大概意思为,计算出当前面向向量transform.forward在碰撞面上的投影向量。可以理解为:hit.normal是阳光方向,transform.forward是一个带方向的射线,得到的是射线在面上的投影射线。投影向量作为碰撞后的新方向。

(1)需要排除掉transform.forward//hit.normal的特殊情况;

(2)检测到碰撞点后,需要从碰撞点出发,用新的面向进行二次检测,防止物体卡入角落。

具体代码如下

void CheckCollision()
    {
        //动态检测距离,速度越大越需要提前检测
        distance = speed * Time.deltaTime;
        RaycastHit hit;
        //用于二次检测
        Vector3 hitPoint;
        //capsulecast
        if (Physics.CapsuleCast(transform.position + point1, transform.position + point2, capsule.radius, transform.forward, out hit, distance))
        {
            hitPoint = hit.point + capsule.radius * hit.normal;
            //如果朝向垂直于碰撞平面
            if (Vector3.Cross(transform.forward, hit.normal) == Vector3.zero)
            {
                nexForward = Vector3.Cross(hit.normal, Vector3.up);
            }
            else
            {
                nexForward = Vector3.Cross(hit.normal, Vector3.Cross(transform.forward, hit.normal));
            }
            bool left = false;
            bool right = false;
            //从碰撞点起,向两边检测两边碰撞
            if (Physics.CapsuleCast(hitPoint + capsule.center - new Vector3(0, 0.5f * capsule.height, 0), hitPoint + capsule.center + new Vector3(0, 0.5f * capsule.height, 0), capsule.radius, nexForward, out hit, distance))
            {
                left = true;
            }
            if (Physics.CapsuleCast(hitPoint + capsule.center - new Vector3(0, 0.5f * capsule.height, 0), hitPoint + capsule.center + new Vector3(0, 0.5f * capsule.height, 0), capsule.radius, -nexForward, out hit, distance))
            {
                right = true;
            }
            if (left)
            {
                if (!right)
                {
                    nexForward = -nexForward;
                }
            }
            //归一化
            nexForward.Normalize();
        }
    }

3.在update函数中更新物体面向,并向前移动

     // Update is called once per frame
    void Update()
    {
        CheckCollision();
        if (nexForward != Vector3.zero)
            transform.forward = nexForward;
        transform.Translate(new Vector3(0, 0, speed * Time.deltaTime));
    }

你可能感兴趣的:(Unity引擎技术,unity,c#,游戏引擎,游戏程序)