青先生

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

1NavMesh

2NavMesh Agent

3NavMesh Obstacle

4NavMesh Surface

5NavMesh Modifier

6NavMesh Modifier Volume

7NavMesh Link

8Off Mesh Link

9抛物线跳跃脚本

10巡逻脚本

11在使用AI时可能会遇到的问题

【1】NavMesh

Agent Radius:半径数值越小,生成网格面积越大。一般与Agent的数值一致。

Agent Height:烘焙的高度,通常是角色所要通过的高度。一般与Agent的数值一致。

Max Slope:最大斜坡角度。角度越大,代理越能爬坡 ,超过这个坡度寻路者则无法通过。

Step Height:台阶步高。步高越大,导航代理迈过台阶的能力越强(可达到或代替跳跃效果)。

Drop Height:跳落高度。(只能往下跳,往返需要添加Link组件)。

Jump Distance:代理跳跃距离。 表示Agent的跳跃距离的极限。

Manual Voxel Size 导航烘焙的像素效果(提高地图的质量同时降低性能)。

Min Regon Area:网格面枳小于该值的地方,将不生成导肮网格。

Height Mesh:勾选后,将会保存高度信息。占用更多的内存和烘焙时间。(DropHeight数值越高,Agent从上往下所能跳跃的地方的标记越多,需要在视图中勾选显示Height Mesh。)

 注意事项:

烘焙的Radius和NavMeshAgent的Radius的区别:

第一阶段只考虑烘培NavMesh并寻找一条可行的路径,而第二阶段Agent就已经在前往目的地的路上了,它会考虑其他agent和obstacle,并尽量避开他们。

烘培时候的Radius就对应第一阶段的生成NavMesh,而Agent上的Radius只在第二阶段使用。就比如说,有一条小径,你有一只大怪是通过不了该路径的,但烘培时候的Radius设置的比较小,虽然Agent的Radius可能设置的很大,但这只大怪还是会使用该小径通过。

Navgation Areas and Costs:这个暂时搞不明白,深入时再了解

【2】NavMesh Agent

Base Offset 碰撞模型和实体模型之间的垂直偏移量。

Speed 物体的速度。

Acceleration 物体的加速度。

Angular Speed 物体的角速度。

Stopping Distance 离目标距离还有多远时停止(一般都会设置一些,因为设置0距离物体可能永远无法到达目的地)。

Auto Braking:自动刹车。

Auto Repath 在行进某些原因中断后是否重新开始寻路。

Radius 物体的半径。

Height 物体的高度。

Quality:物体的质量。

Priority:物体的优先级。

Auto Traverse Off Mesh Link 是否采用默认方式度过链接路径。

Auto Repath:自动复制路径。

Auto Mask:agent会在哪些烘培的区域中寻找路径,能通过的Mask层,这个可以配合Navigation组件中Areas(设置层的)使用。

 

【3】NavMesh Obstacle

carve:雕刻(Agent就能够识别该物体为障碍物自动更换路线)。

Move Threshold:该参数代表该障碍物的移动的极限距离超过这个参数时,才会重新雕刻这个障碍物(增大此值,障碍物移动没有超过这个距离,就不会重新雕刻导航网格)。

Time To Startionary:障碍物静止不动多少时间后会重新雕刻导航网格。(当障碍物移动的时间不会进行雕刻)。

Carve Only Startionary: 勾选此参数时,只有在障碍物静止时才会对它导航网格进行雕刻。

 

【4】NavMesh Surface

进阶的NavMesh组件,优势:自定义烘焙单个物体减少性能消耗,无需对整个场景烘焙,可以在动态场景中进行即时烘焙BuildNavMesh();可以在运行时动态的修改NavMesh;支持垂直面烘焙。

Agent Type 导航代理类型(不同宽高、移动旋转速度、爬坡角度),在Navigation窗口设置。

Collect Objects从哪些物体上烘培导航场景。All:场景中有所物体都会拿来烘培 Children:只有自己及其子层级的物体才会加入烘培 Volume指定区域内才会烘培

Include Layers包含哪些的层级。

Use Geometry使用哪种网格来烘培场景。Render Meshs:有MeshRenderer组件的。Physics Colliders:有物理Collider组件的。

Default Area: 默认生成区域类型。

Override Voxel Size: 覆盖默认的Voxel Size,体素尺寸,用来调整精度,场景比较精密的可以把该值调小,值越小精度越高,精度越高,bake越慢,该值与Tile Size共同影响bake的效果。

Override Tile Size: 覆盖默认的Tile Size,块大小,默认是256voxel作为一块,为了让bake有较多平行与增加内存效率才有了此设置,在障碍物多的时候,可以将块减小以提升运行效率。或者打算实时bake的时候,可以用更小的Tile Size来降低内存消耗。

注意事项:复制带有Surface的物体,需要重新烘焙。

 

【5】NavMesh Modifier

用来被NavMeshSurface组件bake的物体进行微调,组件的作用可用于实时bake,且不需要static,效果包括其下的所有子物体。

Ignore From Build : 烘培时是否无视它。 

Override Area : 重写该区域(是否可以走,是否要跳过)。 

Affected Agents :排除此物体对某一类agent的影响。

 

【6】NavMesh Modifier Volume

功能同NavMesh Modifier,只能作用于特定粉色方框内。

 

【7】NavMesh Link

Agent Type: 哪种Agent才可以使用这个NavMesh Link

Swap:起点和终点位置倒置

Align Transform: 将此物体的Transform中心放在起点和终点的中心

Width :宽度如果为0则通过两个点连接,如果大于0通过两条线连接。

Cost Modifier 非负值时,通过这个链接的代价是Cost Modifier乘以终点的距离。

Bidirectional: 勾上时线的方向为双向,没勾时只能start-to-end单向。

Area Type: 区域类型

【8】Off Mesh Link

可以在两个独立的加载NavMesh Surface的地形中导航。

使用方法:将起点和重点加载到Start和End上,Agent就可以导航。

【9】抛物线跳跃脚本

 private IEnumerator Start()
    {
        NavMeshAgent agent = GetComponent<NavMeshAgent>();
        agent.autoTraverseOffMeshLink = false;
        while (true)
        {
            if (agent.isOnOffMeshLink)
            {
                yield return StartCoroutine(Parabola(agent, 2f, 0.5f));
                agent.CompleteOffMeshLink();
            }
            yield return null;
        }
    }
    IEnumerator Parabola(NavMeshAgent agent,float height,float duration)
    {
        OffMeshLinkData data = agent.currentOffMeshLinkData;
        Vector3 startPos = agent.transform.position;
        Vector3 endPos = data.endPos;
        float time = 0f;
        while (time <1f)
        {
            float yoffset = height * (time - time * time);
            agent.transform.position = Vector3.Lerp(startPos, endPos, time) + yoffset * Vector3.up;
            time += Time.deltaTime / duration;
            yield return null;
        }
    }

【10】巡逻脚本

//协程的参考博客分析https://www.cnblogs.com/fly-100/p/3910515.html
    private NavMeshAgent agent;
    private Animator anim;
    public Transform target;
    Vector3 lastKnowPosition;
    public Transform eye;
    bool patrolling;
    public Transform[] patrolTarget;
    private int destPoint;
    private bool arrived;
    // Use this for initialization
    void Start ()
    {
        agent = GetComponent<NavMeshAgent>();
        anim = GetComponent<Animator>();
        lastKnowPosition = transform.position;
    }
    bool CanSeeTarget()
    {
        //
        bool canSee = false;
        Ray ray  = new Ray(eye.position, target.transform.position - eye.position);//获取一个射线,从眼睛的位置射出,射向目标位置
        RaycastHit hit;
        if (Physics.Raycast(ray,out hit))
        {
            Debug.Log(hit.transform+"----"+target);
            Debug.Log(hit.transform.position + "----" + target.position);
            if (hit.transform != target)
            {
                canSee = false;
            } else
            {
                canSee = true;
                lastKnowPosition = target.transform.position;
            }
            Debug.Log(2);
        }
        return canSee;
    }
    // Update is called once per frame
    void Update () {
        if (agent.pathPending)//调用setDestination 后,会有一个计算路径的时间,计算过程中pathPending为true. 在这个过程中remainingDistance一直为0.
        {
            return;
        }
        if (patrolling)
        {
            if (agent.remainingDistance < agent.stoppingDistance)//剩余距离<停止距离,一定要和pathpengding连用,因为计算remainDistance需要时间,否则数值不会变化。
            {
                if (!arrived)
                {
                    arrived = true;
                    StartCoroutine("GoToNextPoint");
                }
            }
            else
            {
                arrived = false;
            }
        }
        if (CanSeeTarget())
            {
                agent.SetDestination(target.transform.position);
                patrolling = false;
                if (agent.remainingDistance<agent.stoppingDistance)
                {anim.SetBool("Attack",true);
                }
                else
                {
                    anim.SetBool("Attack", false);
                }
            }   
        else
        {
            anim.SetBool("Attack", false);
            if (!patrolling)
            {
                agent.SetDestination(lastKnowPosition);//如果没有开始巡逻,就会自动寻路到上次保存的位置点
                if (agent.remainingDistance < agent.stoppingDistance)//判定到达上一个目标点停止后,自动开始固定巡逻的协程
                {
                    patrolling = true;
                    StartCoroutine("GoToNextPoint");
                }
            }        
        }
        anim.SetFloat("Forward",agent.velocity.sqrMagnitude);
    }
    IEnumerator GoToNextPoint()
    {
        if (patrolTarget.Length==0)
        {
            yield break;
        }
        patrolling = true;
        yield return  new WaitForSeconds(2f);//yield return的值代表何时恢复协程
        arrived = false;
        agent.destination = patrolTarget[destPoint].position;
        destPoint = (destPoint + 1) % patrolTarget.Length;
    }

 

 

【11】在使用AI时可能会遇到的问题

1.NavMesh Agent的绿色线框是否与物体重合,此项有可能会影响寻路的准确性(在Pivot/local中,子物体和母物体的位置是相对距离,子物体Tranform归零,即可到母物体中心)。

2.Raycast这个方法投射的时候对方必须有碰撞器,否则识别不了。

 

posted on 2019-02-26 18:29  青先生  阅读(1944)  评论(0编辑  收藏  举报