游戏之寻路算法
玩游戏的人,都知道游戏中有自动寻路功能,鼠标点击想要到达的终点,主角则会自动走最短的一条路当然同时躲避障碍物,好了,不用多说,直接看效果吧(直观)。
绿色表示起点,红色表示终点,蓝色表示障碍物,而会动的表示从起点运动到终点的轨迹。
上面用的是寻路算法之曼哈顿算法,具体的表述可以参看http://hi.baidu.com/myfcag/blog/item/48bd91fd012a0bf6fd037fc5.html。别人翻译的很好,完全可以根据他的表述实现自己的寻路算法。下面再贴一张游戏的截面(特别申明:图中的素材全部来源于网络 )
截图的效果不太好,不过可以看到主角在后面的移动中可以穿过草丛,因为这里还没加上障碍物的定位和寻路代码,这一部分主要是看看效果,在以后的时间里会贴出完整的代码。(是不是发现游戏的人物是仙剑二中的主角,仙剑经典啊!)
贴上完整的寻路代码(下面的代码加入了一些在实际应用中的限制程序,理解主要的思想就OK了):
代码
/// <summary>
/// 寻路
/// </summary>
public List<Point> PathFinding(Point startPos, Point endPos)
{
List<Point> ps = new List<Point>();
int width = Matrix.GetLength(0);
int height = Matrix.GetLength(1);
//起点
startEB = new Entity(startPos);
startEB.Par = null;
//终点
endEB = new Entity(endPos);
//起点加入到开始列表中
startList.Add(startEB.Pos, startEB);
Entity s = startList[startEB.Pos]; //起点
if (s.Pos == endEB.Pos) return ps;
//起点的八方向(为代码方便阅读,将8个方向单独处理)
Entity temp = new Entity();
Point point = new Point();
bool upBarrier = false;
bool downBarrier = false;
bool leftBarrier = false;
bool rightBarrier = false;
while (s != null)
{
#region 初始化
upBarrier = false;
downBarrier = false;
leftBarrier = false;
rightBarrier = false;
#endregion
//****右
point = new Point(s.Pos.X + 1, s.Pos.Y);
if (!barrier.ContainsKey(point) && !closeList.ContainsKey(point) && (point.X < width && point.Y < height)) //排除障碍物
{
if (!startList.ContainsKey(point))
{
temp = new Entity(point); //(*待判断是否越界)
temp.Par = s;
temp.G = 1;
temp.H = Math.Abs(point.X - endEB.Pos.X) + Math.Abs(point.Y - endEB.Pos.Y);
temp.F = temp.G + temp.H;
startList.Add(point, temp);
}
else //格子已经包括在开始列表中
{
Entity exist = startList[point];
if (s.G + 1 < exist.G)
{
exist.Par = s;
exist.G = 1;
exist.H = Math.Abs(point.X - endEB.Pos.X) + Math.Abs(point.Y - endEB.Pos.Y);
exist.F = exist.G + exist.H;
}
}
}
else
{
if (barrier.ContainsKey(point)) //右边有障碍物
{
rightBarrier = true;
}
}
//****上
point = new Point(s.Pos.X, s.Pos.Y - 1);
if (!barrier.ContainsKey(point) && !closeList.ContainsKey(point) && (point.X < width && point.Y < height)) //排除障碍物
{
if (!startList.ContainsKey(point))
{
temp = new Entity(point);
temp.Par = s;
temp.G = 1;
temp.H = Math.Abs(point.X - endEB.Pos.X) + Math.Abs(point.Y - endEB.Pos.Y);
temp.F = temp.G + temp.H;
startList.Add(point, temp);
}
else
{
Entity exist = startList[point];
if (s.G + 1 < exist.G)
{
exist.Par = s;
exist.G = 1;
exist.H = Math.Abs(point.X - endEB.Pos.X) + Math.Abs(point.Y - endEB.Pos.Y);
exist.F = exist.G + exist.H;
}
}
}
else
{
if (barrier.ContainsKey(point)) //上边有障碍物
{
upBarrier = true;
}
}
//****左
point = new Point(s.Pos.X - 1, s.Pos.Y);
if (!barrier.ContainsKey(point) && !closeList.ContainsKey(point) && (point.X < width && point.Y < height)) //排除障碍物
{
if (!startList.ContainsKey(point))
{
temp = new Entity(point);
temp.Par = s;
temp.G = 1;
temp.H = Math.Abs(point.X - endEB.Pos.X) + Math.Abs(point.Y - endEB.Pos.Y);
temp.F = temp.G + temp.H;
startList.Add(point, temp);
}
else
{
Entity exist = startList[point];
if (s.G + 1 < exist.G)
{
exist.Par = s;
exist.G = 1;
exist.H = Math.Abs(point.X - endEB.Pos.X) + Math.Abs(point.Y - endEB.Pos.Y);
exist.F = exist.G + exist.H;
}
}
}
else
{
if (barrier.ContainsKey(point)) //左边有障碍物
{
leftBarrier = true;
}
}
//****下
point = new Point(s.Pos.X, s.Pos.Y + 1);
if (!barrier.ContainsKey(point) && !closeList.ContainsKey(point) && (point.X < width && point.Y < height)) //排除障碍物
{
if (!startList.ContainsKey(point))
{
temp = new Entity(point);
temp.Par = s;
temp.G = 1;
temp.H = Math.Abs(point.X - endEB.Pos.X) + Math.Abs(point.Y - endEB.Pos.Y);
temp.F = temp.G + temp.H;
startList.Add(point, temp);
}
else
{
Entity exist = startList[point];
if (s.G + 1 < exist.G)
{
exist.Par = s;
exist.G = 1;
exist.H = Math.Abs(point.X - endEB.Pos.X) + Math.Abs(point.Y - endEB.Pos.Y);
exist.F = exist.G + exist.H;
}
}
}
else
{
if (barrier.ContainsKey(point))
{
downBarrier = true;
}
}
//****右上
point = new Point(s.Pos.X + 1, s.Pos.Y - 1);
if (!barrier.ContainsKey(point) && !closeList.ContainsKey(point) && (point.X < width && point.Y < height)) //排除障碍物
{
if (!rightBarrier && !upBarrier)
{
if (!startList.ContainsKey(point))
{
temp = new Entity(new Point(s.Pos.X + 1, s.Pos.Y - 1));
temp.Par = s;
temp.G = 1.4;
temp.H = Math.Abs(point.X - endEB.Pos.X) + Math.Abs(point.Y - endEB.Pos.Y);
temp.F = temp.G + temp.H;
startList.Add(point, temp);
}
else
{
Entity exist = startList[point];
if (s.G + 1.4 < exist.G)
{
exist.Par = s;
exist.G = 1.4;
exist.H = Math.Abs(point.X - endEB.Pos.X) + Math.Abs(point.Y - endEB.Pos.Y);
exist.F = exist.G + exist.H;
}
}
}
}
//****右下
point = new Point(s.Pos.X + 1, s.Pos.Y + 1);
if (!barrier.ContainsKey(point) && !closeList.ContainsKey(point) && (point.X < width && point.Y < height)) //排除障碍物
{
if (!rightBarrier && !downBarrier)
{
if (!startList.ContainsKey(point))
{
temp = new Entity(point);
temp.Par = s;
temp.G = 1.4;
temp.H = Math.Abs(point.X - endEB.Pos.X) + Math.Abs(point.Y - endEB.Pos.Y);
temp.F = temp.G + temp.H;
startList.Add(point, temp);
}
else
{
Entity exist = startList[point];
if (s.G + 1.4 < exist.G)
{
exist.Par = s;
exist.G = 1.4;
exist.H = Math.Abs(point.X - endEB.Pos.X) + Math.Abs(point.Y - endEB.Pos.Y);
exist.F = exist.G + exist.H;
}
}
}
}
//****左上
point = new Point(s.Pos.X - 1, s.Pos.Y - 1);
if (!barrier.ContainsKey(point) && !closeList.ContainsKey(point) && (point.X < width && point.Y < height)) //排除障碍物
{
if (!leftBarrier && !upBarrier)
{
if (!startList.ContainsKey(point))
{
temp = new Entity(point);
temp.Par = s;
temp.G = 1.4;
temp.H = Math.Abs(point.X - endEB.Pos.X) + Math.Abs(point.Y - endEB.Pos.Y);
temp.F = temp.G + temp.H;
startList.Add(point, temp);
}
else
{
Entity exist = startList[point];
if (s.G + 1.4 < exist.G)
{
exist.Par = s;
exist.G = 1.4;
exist.H = Math.Abs(point.X - endEB.Pos.X) + Math.Abs(point.Y - endEB.Pos.Y);
exist.F = exist.G + exist.H;
}
}
}
}
//****左下
point = new Point(s.Pos.X - 1, s.Pos.Y + 1);
if (!barrier.ContainsKey(point) && !closeList.ContainsKey(point) && (point.X < width && point.Y < height)) //排除障碍物
{
if (!leftBarrier && !downBarrier)
{
if (!startList.ContainsKey(point))
{
temp = new Entity(point);
temp.Par = s;
temp.G = 1.4;
temp.H = Math.Abs(point.X - endEB.Pos.X) + Math.Abs(point.Y - endEB.Pos.Y);
temp.F = temp.G + temp.H;
startList.Add(point, temp);
}
else
{
Entity exist = startList[point];
if (s.G + 1.4 < exist.G)
{
exist.Par = s;
exist.G = 1.4;
exist.H = Math.Abs(point.X - endEB.Pos.X) + Math.Abs(point.Y - endEB.Pos.Y);
exist.F = exist.G + exist.H;
}
}
}
}
//从开始列表中删除起点,并将其加到关闭列表中
if (startList.ContainsKey(s.Pos))
{
startList.Remove(s.Pos);
}
if (!closeList.ContainsKey(s.Pos))
{
closeList.Add(s.Pos, s);
}
//寻找F值最低的
double fMin = Double.MaxValue ;
foreach (KeyValuePair<Point, Entity> key in startList)
{
if (key.Value.F <= fMin)
{
fMin = key.Value.F;
temp = key.Value;
}
}
//将最低的从开始列表中删除,加载到关闭列表中
if (startList.ContainsKey(temp.Pos))
{
startList.Remove(temp.Pos);
}
if (!closeList.ContainsKey(temp.Pos))
{
closeList.Add(temp.Pos, temp);
}
//判断是否需要继续查找
if (closeList.ContainsKey(endEB.Pos) || startList.Count <= 0)
{
//如果F值最低的点就是目标点,停止查找
s = null;
}
else
{
s = temp;
}
}
//返回值
return ps;
}
/// 寻路
/// </summary>
public List<Point> PathFinding(Point startPos, Point endPos)
{
List<Point> ps = new List<Point>();
int width = Matrix.GetLength(0);
int height = Matrix.GetLength(1);
//起点
startEB = new Entity(startPos);
startEB.Par = null;
//终点
endEB = new Entity(endPos);
//起点加入到开始列表中
startList.Add(startEB.Pos, startEB);
Entity s = startList[startEB.Pos]; //起点
if (s.Pos == endEB.Pos) return ps;
//起点的八方向(为代码方便阅读,将8个方向单独处理)
Entity temp = new Entity();
Point point = new Point();
bool upBarrier = false;
bool downBarrier = false;
bool leftBarrier = false;
bool rightBarrier = false;
while (s != null)
{
#region 初始化
upBarrier = false;
downBarrier = false;
leftBarrier = false;
rightBarrier = false;
#endregion
//****右
point = new Point(s.Pos.X + 1, s.Pos.Y);
if (!barrier.ContainsKey(point) && !closeList.ContainsKey(point) && (point.X < width && point.Y < height)) //排除障碍物
{
if (!startList.ContainsKey(point))
{
temp = new Entity(point); //(*待判断是否越界)
temp.Par = s;
temp.G = 1;
temp.H = Math.Abs(point.X - endEB.Pos.X) + Math.Abs(point.Y - endEB.Pos.Y);
temp.F = temp.G + temp.H;
startList.Add(point, temp);
}
else //格子已经包括在开始列表中
{
Entity exist = startList[point];
if (s.G + 1 < exist.G)
{
exist.Par = s;
exist.G = 1;
exist.H = Math.Abs(point.X - endEB.Pos.X) + Math.Abs(point.Y - endEB.Pos.Y);
exist.F = exist.G + exist.H;
}
}
}
else
{
if (barrier.ContainsKey(point)) //右边有障碍物
{
rightBarrier = true;
}
}
//****上
point = new Point(s.Pos.X, s.Pos.Y - 1);
if (!barrier.ContainsKey(point) && !closeList.ContainsKey(point) && (point.X < width && point.Y < height)) //排除障碍物
{
if (!startList.ContainsKey(point))
{
temp = new Entity(point);
temp.Par = s;
temp.G = 1;
temp.H = Math.Abs(point.X - endEB.Pos.X) + Math.Abs(point.Y - endEB.Pos.Y);
temp.F = temp.G + temp.H;
startList.Add(point, temp);
}
else
{
Entity exist = startList[point];
if (s.G + 1 < exist.G)
{
exist.Par = s;
exist.G = 1;
exist.H = Math.Abs(point.X - endEB.Pos.X) + Math.Abs(point.Y - endEB.Pos.Y);
exist.F = exist.G + exist.H;
}
}
}
else
{
if (barrier.ContainsKey(point)) //上边有障碍物
{
upBarrier = true;
}
}
//****左
point = new Point(s.Pos.X - 1, s.Pos.Y);
if (!barrier.ContainsKey(point) && !closeList.ContainsKey(point) && (point.X < width && point.Y < height)) //排除障碍物
{
if (!startList.ContainsKey(point))
{
temp = new Entity(point);
temp.Par = s;
temp.G = 1;
temp.H = Math.Abs(point.X - endEB.Pos.X) + Math.Abs(point.Y - endEB.Pos.Y);
temp.F = temp.G + temp.H;
startList.Add(point, temp);
}
else
{
Entity exist = startList[point];
if (s.G + 1 < exist.G)
{
exist.Par = s;
exist.G = 1;
exist.H = Math.Abs(point.X - endEB.Pos.X) + Math.Abs(point.Y - endEB.Pos.Y);
exist.F = exist.G + exist.H;
}
}
}
else
{
if (barrier.ContainsKey(point)) //左边有障碍物
{
leftBarrier = true;
}
}
//****下
point = new Point(s.Pos.X, s.Pos.Y + 1);
if (!barrier.ContainsKey(point) && !closeList.ContainsKey(point) && (point.X < width && point.Y < height)) //排除障碍物
{
if (!startList.ContainsKey(point))
{
temp = new Entity(point);
temp.Par = s;
temp.G = 1;
temp.H = Math.Abs(point.X - endEB.Pos.X) + Math.Abs(point.Y - endEB.Pos.Y);
temp.F = temp.G + temp.H;
startList.Add(point, temp);
}
else
{
Entity exist = startList[point];
if (s.G + 1 < exist.G)
{
exist.Par = s;
exist.G = 1;
exist.H = Math.Abs(point.X - endEB.Pos.X) + Math.Abs(point.Y - endEB.Pos.Y);
exist.F = exist.G + exist.H;
}
}
}
else
{
if (barrier.ContainsKey(point))
{
downBarrier = true;
}
}
//****右上
point = new Point(s.Pos.X + 1, s.Pos.Y - 1);
if (!barrier.ContainsKey(point) && !closeList.ContainsKey(point) && (point.X < width && point.Y < height)) //排除障碍物
{
if (!rightBarrier && !upBarrier)
{
if (!startList.ContainsKey(point))
{
temp = new Entity(new Point(s.Pos.X + 1, s.Pos.Y - 1));
temp.Par = s;
temp.G = 1.4;
temp.H = Math.Abs(point.X - endEB.Pos.X) + Math.Abs(point.Y - endEB.Pos.Y);
temp.F = temp.G + temp.H;
startList.Add(point, temp);
}
else
{
Entity exist = startList[point];
if (s.G + 1.4 < exist.G)
{
exist.Par = s;
exist.G = 1.4;
exist.H = Math.Abs(point.X - endEB.Pos.X) + Math.Abs(point.Y - endEB.Pos.Y);
exist.F = exist.G + exist.H;
}
}
}
}
//****右下
point = new Point(s.Pos.X + 1, s.Pos.Y + 1);
if (!barrier.ContainsKey(point) && !closeList.ContainsKey(point) && (point.X < width && point.Y < height)) //排除障碍物
{
if (!rightBarrier && !downBarrier)
{
if (!startList.ContainsKey(point))
{
temp = new Entity(point);
temp.Par = s;
temp.G = 1.4;
temp.H = Math.Abs(point.X - endEB.Pos.X) + Math.Abs(point.Y - endEB.Pos.Y);
temp.F = temp.G + temp.H;
startList.Add(point, temp);
}
else
{
Entity exist = startList[point];
if (s.G + 1.4 < exist.G)
{
exist.Par = s;
exist.G = 1.4;
exist.H = Math.Abs(point.X - endEB.Pos.X) + Math.Abs(point.Y - endEB.Pos.Y);
exist.F = exist.G + exist.H;
}
}
}
}
//****左上
point = new Point(s.Pos.X - 1, s.Pos.Y - 1);
if (!barrier.ContainsKey(point) && !closeList.ContainsKey(point) && (point.X < width && point.Y < height)) //排除障碍物
{
if (!leftBarrier && !upBarrier)
{
if (!startList.ContainsKey(point))
{
temp = new Entity(point);
temp.Par = s;
temp.G = 1.4;
temp.H = Math.Abs(point.X - endEB.Pos.X) + Math.Abs(point.Y - endEB.Pos.Y);
temp.F = temp.G + temp.H;
startList.Add(point, temp);
}
else
{
Entity exist = startList[point];
if (s.G + 1.4 < exist.G)
{
exist.Par = s;
exist.G = 1.4;
exist.H = Math.Abs(point.X - endEB.Pos.X) + Math.Abs(point.Y - endEB.Pos.Y);
exist.F = exist.G + exist.H;
}
}
}
}
//****左下
point = new Point(s.Pos.X - 1, s.Pos.Y + 1);
if (!barrier.ContainsKey(point) && !closeList.ContainsKey(point) && (point.X < width && point.Y < height)) //排除障碍物
{
if (!leftBarrier && !downBarrier)
{
if (!startList.ContainsKey(point))
{
temp = new Entity(point);
temp.Par = s;
temp.G = 1.4;
temp.H = Math.Abs(point.X - endEB.Pos.X) + Math.Abs(point.Y - endEB.Pos.Y);
temp.F = temp.G + temp.H;
startList.Add(point, temp);
}
else
{
Entity exist = startList[point];
if (s.G + 1.4 < exist.G)
{
exist.Par = s;
exist.G = 1.4;
exist.H = Math.Abs(point.X - endEB.Pos.X) + Math.Abs(point.Y - endEB.Pos.Y);
exist.F = exist.G + exist.H;
}
}
}
}
//从开始列表中删除起点,并将其加到关闭列表中
if (startList.ContainsKey(s.Pos))
{
startList.Remove(s.Pos);
}
if (!closeList.ContainsKey(s.Pos))
{
closeList.Add(s.Pos, s);
}
//寻找F值最低的
double fMin = Double.MaxValue ;
foreach (KeyValuePair<Point, Entity> key in startList)
{
if (key.Value.F <= fMin)
{
fMin = key.Value.F;
temp = key.Value;
}
}
//将最低的从开始列表中删除,加载到关闭列表中
if (startList.ContainsKey(temp.Pos))
{
startList.Remove(temp.Pos);
}
if (!closeList.ContainsKey(temp.Pos))
{
closeList.Add(temp.Pos, temp);
}
//判断是否需要继续查找
if (closeList.ContainsKey(endEB.Pos) || startList.Count <= 0)
{
//如果F值最低的点就是目标点,停止查找
s = null;
}
else
{
s = temp;
}
}
//返回值
return ps;
}
由于实际需要,在代码中加了少许的修改,理解主要实现的思路即可!!!