[云图] A*寻路 基础到入门-2战术寻路
本帖最后由 z7232124 于 2016-3-15 10:15 编辑

大家好,我是云图。 今天我们进一步升级,了解下A*的战术寻路表现,在很多游戏中,比如我们在两方对战的时候,敌方的AI需要移动到某个位置,而我们正在交战,如果AI从正面或者我们轻易就能干掉的位置跑过去,这样AI会显得比较蠢(这样的AI一定不是什么正经AI),我们的想法是敌方AI应该会绕开我们的火力,或者危险区域,从而聪明的走到目标点,即使路程更远,但是显得更加聪明。好,废话不多说,开始。   首先和昨天一样,新建场景,添加Obstacles,Ground层。创建平面,Layer设置成Ground。,在设置一些Cube墙体Layer设置成Obstacles。
   考虑到如果我们采用网格导航,寻找路径时,需要逐个遍历网格,搜索的点比较多,严重的是战术寻路需要对每个网格进行视线测试(LOS),
而视线测试的消耗很大,因此多的搜索点和高的视线测试消耗,会大大降低寻路算法的效率,即使找到一条路径也需要很长时间。
   另外一种选择是采用导航网格,采用自动生成的导航网格,会生成很大的多边形,寻路只需要寻找很少数量的多边形,就可以找到一条路径,
但是对于战术寻路来说,由于多边形的面积可能很大,很可能出现多边形中的一些部分在火力范围内,其他都在火力范围外,因此很难达到好的效果,
实现中,如果使用导航网格,最好自己划分多边形,以便达到更好的效果。
   PointGraph是较容易控制的,而且对于不是很复杂的游戏也够用了,可以很容易支持战术寻路,所以我们采用视点导航图。
      添加空物体,命名为A*,然后添加寻路组件。为A*创建一个空物体,名称叫PathPoints,给PathPoints加上一个UnityReferenceHelper脚本,
然后创建一些预设的Cube物体,拖到PathPoints中,作为它的子物体,这些Cube就是我们的预设路点。
   单击Component-Pathfinding-Pathfinder,给A*加上寻路组件,选择PointGraph,将PathPoints拖到Root中,需要注意下MaxDistance表示相邻航点之间的最大距离,如果这两个点的距离大于这个值,那么这两个点就不会有连线,将Mask设置为Obstacles,选中ShowGraphs,单击Scan就可以了。
  
然后我们把我们的AI拖到场景,加上Seeker组件(Component-Pathfinding-Seeker),然后添加AstarAI.cs脚本,如图
   然后我们把开枪的玩家拖到场景,放到中间,表示有火力攻击,Tag为Player,给玩家添加FireRange.cs 脚本。
  [mw_shl_code=csharp,true]using UnityEngine;
using System.Collections;

public class FireRange : MonoBehaviour
{
        public float fireRange;
        public int penalty;
        public float fieldOfAttack = 45;

        void OnDrawGizmos()
        {
                Vector3 frontRayPoint = transform.position + (transform.forward * fireRange);
                float fieldOfAttackinRadians = fieldOfAttack*3.14f/180.0f;

                for (int i = 0; i<11; i++)
                {
                        RaycastHit hit;
                        float angle = -fieldOfAttackinRadians + fieldOfAttackinRadians * 0.2f * (float)i;
                        Vector3 rayPoint = transform.TransformPoint(new Vector3(fireRange * Mathf.Sin(angle),0,fireRange * Mathf.Cos(angle)));
                        Vector3 rayDirection = rayPoint - transform.position;
                        if (Physics.Raycast(transform.position, rayDirection, out hit,fireRange))
                        {
                                if (hit.transform.gameObject.layer == 8)
                                {
                                        Debug.DrawLine(transform.position+new Vector3(0,1,0), hit.point, Color.red);
                                        continue;
                                }
                        }

                        Debug.DrawLine(transform.position+new Vector3(0,1,0), rayPoint+new Vector3(0,1,0), Color.red);
                }
        }
}
[/mw_shl_code]



好了,现在完成了一个基于视点导航图的最简单寻路,可是我们运行的话,目前会发现AI直接从火力范围内走了过去,可能还没到终点就被打死了
所以我们现在修改一下代码,让玩家从背后的障碍物绕过去。


   为了实现战术寻路,要给每个路点添加代价信息,这个代价取决于此刻是否在玩家的实现或者攻击范围内,为了简化,只考虑玩家的攻击范围,这种战术寻路的方法是,当某个路点在玩家的攻击范围内,这个点就加上一个很大的代价值,比如3000,这样,AI角色在寻路的时候,
就会尽量避开这些路点,从而选择一个更安全的路径。
进一步加上对玩家的视线的考虑也是很容易的,只需要加入一个测试,比如,如果路点在玩家视线内,代价加500就可以了。
   我们需要修改AstarPathfindingProject/Core路径下的Path.cs 文件,找到GetTraversalCost函数,如果你的A*没有这个函数,直接下载我的工程就行
我当初也找了4 5个版本发现3.7的A*才行,其他的代码多多少少不一样。 首先是声明几个函数
[mw_shl_code=csharp,true]   //玩家对象
        protected GameObject player;
        //玩家火力范围
        protected float fireRange;
        //玩家火力范围平均值
        protected float sqrFireRange;
        //危险路点的代价值
        protected int penaltyAmount;[/mw_shl_code]

然后修改GetTraversalCost函数
[mw_shl_code=csharp,true]public uint GetTraversalCost (GraphNode node) {
            //unchecked { return GetTagPenalty((int)node.Tag) + node.Penalty; }
            //节点的惩罚值,我们要开始修改的地方
            node.Penalty = 0;
            //当前正在处理的节点位置
            Vector3 nodePos = (Vector3)node.position;
            //Debug.Log(nodePos);
            Vector3 rayStart = nodePos;
            rayStart.y = 1.0f;
            //玩家所在位置
            Vector3 playerPos = player.transform.position;
            Vector3 distance = playerPos - nodePos;
            distance.y = 0;
            //Debug.Log("进入方法:" + distance.sqrMagnitude + "  小于的值:" + sqrFireRange);
            //假设玩家的射击范围平方是61000,如果玩家与当前节点的距离平方小于这个值
            if (distance.sqrMagnitude < sqrFireRange)
            {
                //判断玩家和节点之间是否有遮挡
                RaycastHit hit;
                if (Physics.Raycast(nodePos, distance, out hit))
                {
                    Debug.DrawLine(playerPos + new Vector3(0, 1, 0), hit.point, Color.green);
                    Debug.Log("add2+hit.collider.tag:" + hit.collider.name);
                    //hit.collider.gameObject.GetComponent<MeshRenderer>().materials[0].color=Color.red;
                    //如果没有遮拦,那么节点惩罚值加上penaltyamout
                    //这里的惩罚值越大,找到的路径越倾于避开火力区
                    Debug.Log(hit.collider.name);
                    //Debug.Log("代价值:" + node.Penalty);
                    if (hit.collider.tag == "Player")
                    {
                        node.Penalty += (uint)penaltyAmount;
                        Debug.Log("代价值2:" + node.Penalty);
                    }
                }
            }
            unchecked
            {
                return GetTagPenalty((int)node.Tag) + node.Penalty;
            }[/mw_shl_code]

整个代码就不贴, 后面会直接放上工程。然后是ABPath.cs 在Pathfinders文件夹内,找到UpdateStartEnd函数,修改成如下 [mw_shl_code=csharp,true]        protected void UpdateStartEnd (Vector3 start, Vector3 end) {
                        originalStartPoint = start;
                        originalEndPoint = end;

                        startPoint = start;
                        endPoint = end;

                        startIntPoint = (Int3)start;
                        hTarget = (Int3)end;
            //寻路开始前先获取player对象,并且算出玩家火力范围的平方
            player = GameObject.FindWithTag("Player");
            fireRange = player.GetComponent<FireRange>().fireRange;
            sqrFireRange = fireRange * fireRange;
            penaltyAmount = player.GetComponent<FireRange>().penalty;
                }[/mw_shl_code]



  修改完成后在运行,这次我们的AI就会避开我们红色的火力范围,绕道障碍物后面去了,最后说一下,

如果你自己做的全部步骤都对,但是就是运行不成功,很可能是你的红色射线没有打到路点,路点没增加代价值导致的,所以细节要处理好,
我也是花了几个小时才搞定的。今天的A*就到这里,下次继续分享更高级的示例,谢谢大家。

游客,如果您要查看本帖隐藏内容请回复








   



astarpathfinding教程;
  • 沙发 王成
  • 2016-3-15 14:20:46
看看作者隐藏了啥东西                                            
赞、赞、赞!!!
  • 地板 winmain
  • 2016-3-15 15:16:57
很棒的分享,谢谢楼主
很棒的分享,谢谢楼主
赞、赞、赞!继续啊
路过看看

看看作者隐藏了啥东西        
部步骤都对,但是就是运行不成功
看一看A*算法
隐藏了神马东西呢。。。。
RE: A*寻路 基础到入门-2战术寻路 [修改]
RE: A*寻路 基础到入门-2战术寻路 [修改]
xiexiefenxiang
  • 15# lvbu
  • 2016-3-16 10:18:50
看看作者隐藏了啥东西         
1234.. 9下一页