Unity3D 2D游戏中寻径算法的一些解决思路
需求
unity3d的3d开发环境中,原生自带了Navigation的组件,可以很便捷快速的实现寻路功能。但是在原生的2d中并没有相同的功能。
现在国内很多手机游戏都有自动寻路的功能,或者游戏中存在一些例如机器人、npc等,都需要自动寻路的功能。
我需要实现的功能类似于当年FC游戏中淘金者的运动方式。游戏中有淘金者、敌人,可移动,不可移动区域,只能沿着直线的向前向后或者向上向下。
思路
unity3d中也有一些2d寻路的插件。例如A Pathfinding Project Pro和NavMesh 2D。
两个插件都是收费插件,可以满足不同需求,但是我用过之后发现并不是我想要的效果,而且修改别人的代码的还是挺难受的。所以决定自己写一遍A*算法。
A*算法已经有很多大牛的博客中,都有非常不错的介绍。我看的是这篇,给大家推荐下:传送
这篇文章的代码在于拐点的处理上是有一定问题的,我在下面的代码中有进行修改。
解决方案
先上结果,实现后的路径是这样的。请忽略那只乱入恐龙,他其实只是来打酱油的~~
核心代码如下:
1 public Point FindPath (Point start, Point end, bool IsIgnoreCorner) 2 { 3 OpenList.Add (start); 4 while (OpenList.Count != 0) { 5 //找出F值最小的点 6 var tempStart = OpenList.MinPoint (); 7 OpenList.RemoveAt (0); 8 CloseList.Add (tempStart); 9 //找出它相邻的点 10 var surroundPoints = SurrroundPoints (tempStart, IsIgnoreCorner); 11 foreach (Point point in surroundPoints) { 12 if (OpenList.Exists (point)) 13 //计算G值, 如果比原来的大, 就什么都不做, 否则设置它的父节点为当前点,并更新G和F 14 FoundPoint (tempStart, point); 15 else 16 //如果它们不在开始列表里, 就加入, 并设置父节点,并计算GHF 17 NotFoundPoint (tempStart, end, point); 18 } 19 if (OpenList.Get (end) != null) 20 return OpenList.Get (end); 21 } 22 return OpenList.Get (end); 23 }
原文中有些小问题的CanReach方向,我修改的如下:
1 public bool CanReach (Point start, int x, int y, bool IsIgnoreCorner) 2 { 3 if (!CanReach (x, y) || CloseList.Exists (x, y)) 4 return false; 5 else { 6 if (Math.Abs (x - start.X) + Math.Abs (y - start.Y) == 1) 7 return true; 8 //如果是斜方向移动, 判断是否 "拌脚" 9 else { 10 if (IsIgnoreCorner) { 11 if (CanReach (Math.Abs (x - 1), y) && CanReach (x, Math.Abs (y - 1))) 12 return true; 13 else 14 return false; 15 } else 16 return false; 17 } 18 } 19 }
总结
算法还是要多自己写一些,总是拿来主义不利于自己的成长,在大学里学过了,基本都还给老师了,项目里的东西,要用也要明明白白的用,防止为以后的开发留下隐患,到时候从头再找就需要话费给多的时间了。
项目源代码中包含了spine的例子,所以有点大,有兴趣的朋友可以下载去玩一玩。