[FreedomAI]第三周——A*寻路

上篇介绍了InfluenceMap,如果不使用这些信息,那么也是浪费的,这篇我们来看一个InfluenceMap的应用。A*寻路——我们经常遇到的一个问题是,如何让AI从一个点到另一个点。通常两点之前线段最短在这里并不适用,有可能我们需要避开那些讨厌的障碍,有可能我们需要希望分散开来夹击敌人,我们需要避开影响图上友方信息密集的区域..............这时候我们就需要用到了A*寻路算法。

我们可以想象一下,你在棋盘的一个格子上,你要到棋盘的另一个格子上,你会怎么做?由于你没有看到全局的能力,多半你会选择,移动到当前收益最高的相邻点,如此递归下去,最终到达目的地。

如此我们得到了第一个A*寻路需要的概念——代价。每一个节点都会有一个代价,在每次移动操作中,我们都会倾向移动到代价最小的那个点。

好的,算法大致如上叙述。让我们用比较严谨的语言来叙述一下。

一开始我们维护一个开始节点,一个目标节点,一个开始列表,一个关闭列表。

1.添加开始节点进入进入开始列表。

2.如果开始列表中有节点。出列,检查是否是关闭列表中的节点,若是,重复这一过程。

3.检查该节点是否是目标节点,若是,退出。

4.计算该节点的相邻节点的代价,并将其添加到开始列表中。

5.添加该节点到目标路径中。

6.退回第2步。

来看看代码:

public class AStarNodeItem 
	{
		
		public Vector3 pos;
	
		public int x, y;

	
		public int gCost;

		public int hCost;


		public int fCost
		{
			get 
			{
				return gCost + hCost; 
			}
		}


		public AStarNodeItem parent;

		public AStarNodeItem(Vector3 pos, int x, int y) 
		{
			this.pos = pos;
			this.x = x;
			this.y = y;
		}

		public AStarNodeItem()
		{
			
		}

	}

注意这里我们将代价定义成两部分,gcost,和相邻节点的距离,注意到九宫格中心离其他点距离有相邻和对角线的区别,另一个部分才是我们计算的主体。

再来看看,寻路部分的代码:

public Queue<Vector3> AStarFindPath(Vector3 src,Vector3 des,AStarComputer pAStarComputer)
		{
			PriorityQueue<AStarNodeItem> openList = new PriorityQueue<AStarNodeItem> (0,new AStarNodeItemCamparer());
			List<AStarNodeItem> closedList = new List<AStarNodeItem> ();
			Queue<Vector3> pathLast = new Queue<Vector3> ();
			Vector2 start = getTilefromPosition (new Vector2(src.x,src.z));
			Vector2 end = getTilefromPosition (new Vector2(des.x,des.z));

			if (!(start.x == end.x && start.y == end.y))
			{
				AStarNodeItem AStarforStart = new AStarNodeItem (src,(int)start.x,(int)start.y);
				AStarforStart.gCost = 0;
				AStarforStart.hCost = pAStarComputer (src,des);
				openList.Push (AStarforStart);
			}

			while(openList.Count!=0)
			{
				AStarNodeItem tAStarNodeItem = openList.Pop ();
				while (closedList.Contains(tAStarNodeItem)&&!isWall(new Vector2(tAStarNodeItem.x,tAStarNodeItem.y)))
					tAStarNodeItem = openList.Pop ();
				
				if (tAStarNodeItem.x == end.x && tAStarNodeItem.y == end.y) 
				{
					pathLast.Enqueue (tAStarNodeItem.pos);
					return pathLast;
				}

				pathLast.Enqueue (tAStarNodeItem.pos);
				closedList.Add (tAStarNodeItem);
				openList.Clear ();
				for (int i = 0; i < NineGrid.Length; i++) 
				{
					Vector2 tv = new Vector2 (tAStarNodeItem.x+NineGrid[i].x,tAStarNodeItem.y+NineGrid[i].y);
					Vector3 tp = GetPositionByTile (tv);
					AStarNodeItem ttAStarNodeItem = new AStarNodeItem (tp,(int)tv.x,(int)tv.y);
					ttAStarNodeItem.gCost = (int)(NineGrid [i].magnitude*10);
					ttAStarNodeItem.hCost = pAStarComputer (tp,des);
					openList.Push (ttAStarNodeItem);
				}

			}

			return null;

		}

此外,我们还提供了另一种参数形式:

public Queue<Vector3> AStarFindPath(Vector3 src,Vector3 des,AStarComputerformula pAStarComputerformula)
		{
			return AStarFindPath (src, des, pAStarComputerformula.EquationComputer);
		}

这是在干什么呢?事实上,在计算hcost的时候,我们需要考虑的因素往往不止一种,所以这种参数形式就可以任何,你指定好一个表达式 des= srcA*A+srcB*B............................的形式,将若干种因素的计算按重要性混融出来,得到结果。

来看看AStarComputerformula的定义:

public class AStarComputerformula
	{
		List<AStarComputerformulaNode> mAStarComputerList = new List<AStarComputerformulaNode>() ;

		float blendfuncSum = 0.0f;

		public AStarComputer EquationComputer
		{
			get
			{
				return (Vector3 target, Vector3 des) => 
				{
					float rf = 0.0f;
					foreach(var v in mAStarComputerList)
					{
						float tf = v.mAStarComputer(target,des);
						rf+=tf*v.mBlendFunc/blendfuncSum;
					}
					return rf;
				};
			}
		}

		public void Add(AStarComputer pAStarComputer,float pBlendFunc)
		{
			AStarComputerformulaNode tAStarComputerformulaNode = new AStarComputerformulaNode ();
			tAStarComputerformulaNode.mAStarComputer = pAStarComputer;
			tAStarComputerformulaNode.mBlendFunc = pBlendFunc;
			blendfuncSum += pBlendFunc;
		}

	};
这里我们使用了拉姆达表达式的用法,很简洁的算出了等价的计算函数。

                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值