游戏之寻路算法

      玩游戏的人,都知道游戏中有自动寻路功能,鼠标点击想要到达的终点,主角则会自动走最短的一条路当然同时躲避障碍物,好了,不用多说,直接看效果吧(直观)。

     

     绿色表示起点,红色表示终点,蓝色表示障碍物,而会动的表示从起点运动到终点的轨迹。

     上面用的是寻路算法之曼哈顿算法,具体的表述可以参看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;
        }

 

       由于实际需要,在代码中加了少许的修改,理解主要实现的思路即可!!!

posted @ 2010-03-29 13:32  勇者归来  阅读(893)  评论(0编辑  收藏  举报