1. 程式人生 > >一步一步開發Game伺服器(五)地圖尋路

一步一步開發Game伺服器(五)地圖尋路

目前大多數使用的尋路演算法有哪些?

目前市面上大部分遊戲的尋路演算法是A*,或者B*。
A*通常所說的是最優演算法也就是尋找最短路徑。
B*碰撞式演算法也就是,也就是不斷的去碰撞能走就走,不管是不是繞路。
當然以上都是我的理解。

我這裡只描述一下A*演算法的一部分。

通常A*演算法分為四方向和八方向計算。

現目前的遊戲方式來看不管是2D還是2.5D,還是3D,幾乎都採用8方向方式,也有遊戲是採用360°點位方式。

本文重點剖析8方向的。

先來看一個效果圖

圖中你看到的圖案表示非阻擋地區,其餘是阻擋地區。

綠色的線是表示尋路走過路線。

尋路步驟

 1. 從起點A開始, 把它作為待處理的方格存入一個"開啟列表", 開啟列表就是一個等待檢查方格的列表.
 2. 尋找起點A周圍可以到達的方格, 將它們放入"開啟列表", 並設定它們的"父方格"為A.
 3. 從"開啟列表"中刪除起點 A, 並將起點 A 加入"關閉列表", "關閉列表"中存放的都是不需要再次檢查的方格

原諒我盜用了園友的圖。

圖中淺綠色描邊的方塊表示已經加入 "開啟列表" 等待檢查. 淡藍色描邊的起點 A 表示已經放入 "關閉列表" , 它不需要再執行檢查.

從 "開啟列表" 中找出相對最靠譜的方塊, 什麼是最靠譜? 它們通過公式 F=G+H 來計算.

廢話不多說了,直接來原始碼

原始碼來之園友,但是稍作修改。
修改1,原本演算法不支援複雜地形圖。
修改2,原本演算法foreach List列表,改為for迴圈,倒入迴圈。因為每一次的尋路下一個節點的時候8方向都是上一個節點。
修改3,修改單例模式。

來一張大圖看看目前我的地形圖

原始碼

  1     public class FindWayManager
  2     {
  3         static readonly FindWayManager instance = new FindWayManager();
  4         public static FindWayManager Instance { get { return instance; } }
  5 
  6         /// <summary>
  7         /// 阻擋點配置,,
  8         ///
</summary> 9 public int BlockConst = 1; 10 11 //從開啟列表查詢F值最小的節點 12 private Point GetMinFFromOpenList(List<Point> Open_List) 13 { 14 Point Pmin = null; 15 16 int count = Open_List.Count; 17 for (int i = count - 1; i >= 0; i--) 18 { 19 if (Pmin == null || Pmin.G + Pmin.H > Open_List[i].G + Open_List[i].H) 20 Pmin = Open_List[i]; 21 } 22 return Pmin; 23 } 24 25 //判斷關閉列表是否包含一個座標的點 26 private bool IsInCloseList(int x, int y, List<Point> Close_List) 27 { 28 if (Close_List == null || Close_List.Count == 0) 29 { 30 return false; 31 } 32 33 int count = Close_List.Count; 34 for (int i = count - 1; i >= 0; i--) 35 { 36 if (Close_List[i].X == x && Close_List[i].Y == y) 37 return true; 38 } 39 return false; 40 } 41 //從關閉列表返回對應座標的點 42 private Point GetPointFromCloseList(int x, int y, List<Point> Close_List) 43 { 44 int count = Close_List.Count; 45 for (int i = count - 1; i >= 0; i--) 46 { 47 if (Close_List[i].X == x && Close_List[i].Y == y) 48 return Close_List[i]; 49 } 50 return null; 51 } 52 53 //判斷開啟列表是否包含一個座標的點 54 private bool IsInOpenList(int x, int y, List<Point> Open_List) 55 { 56 int count = Open_List.Count; 57 for (int i = count - 1; i >= 0; i--) 58 { 59 if (Open_List[i].X == x && Open_List[i].Y == y) 60 return true; 61 } 62 return false; 63 } 64 //從開啟列表返回對應座標的點 65 private Point GetPointFromOpenList(int x, int y, List<Point> Open_List) 66 { 67 int count = Open_List.Count; 68 for (int i = count - 1; i >= 0; i--) 69 { 70 if (Open_List[i].X == x && Open_List[i].Y == y) 71 return Open_List[i]; 72 } 73 return null; 74 } 75 76 //計算某個點的G值 77 private int GetG(Point p) 78 { 79 if (p.Next == null) return 0; 80 if (p.X == p.Next.X || p.Y == p.Next.Y) return p.Next.G + 10; 81 else return p.Next.G + 14; 82 } 83 84 //計算某個點的H值 85 private int GetH(Point p, Point pb) 86 { 87 return Math.Abs(p.X - pb.X) + Math.Abs(p.Y - pb.Y); 88 } 89 90 //檢查當前節點附近的節點 91 private void CheckP8(Point p0, byte[,] map, Point pa, Point pb, List<Point> Open_List, List<Point> Close_List) 92 { 93 //這裡的迴圈其實就是8方向判斷 94 for (int xt = p0.X - 1; xt <= p0.X + 1; xt++) 95 { 96 for (int yt = p0.Y - 1; yt <= p0.Y + 1; yt++) 97 { 98 //排除超過邊界和等於自身的點 99 if ((xt >= 0 && xt < map.GetLongLength(1) && yt >= 0 && yt < map.GetLongLength(0)) && !(xt == p0.X && yt == p0.Y)) 100 { 101 //排除障礙點和關閉列表中的點 102 if (map[yt, xt] != BlockConst && !IsInCloseList(xt, yt, Close_List)) 103 { 104 Point pt = GetPointFromOpenList(xt, yt, Open_List); 105 if (pt != null) 106 { 107 //如果節點在開啟列表中更新帶價值 108 int G_new = 0; 109 if (p0.X == pt.X || p0.Y == pt.Y) G_new = p0.G + 10; 110 else G_new = p0.G + 14; 111 if (G_new < pt.G) 112 { 113 //Open_List.Remove(pt); 114 pt.Next = p0; 115 pt.G = G_new; 116 //Open_List.Add(pt); 117 } 118 } 119 else 120 { 121 //不在開啟列表中,如果不存在建立新增到開啟列表中 122 pt = new Point(); 123 pt.X = xt; 124 pt.Y = yt; 125 pt.Next = p0; 126 pt.G = GetG(pt); 127 pt.H = GetH(pt, pb); 128 Open_List.Add(pt); 129 } 130 } 131 } 132 } 133 } 134 } 135 136 public Point FindWay(byte[,] r, int sx, int sz, int ex, int ez) 137 { 138 //定義出發位置 139 Point pa = new Point(); 140 pa.X = sx; 141 pa.Y = sz; 142 //定義目的地 143 Point pb = new Point(); 144 pb.X = ex; 145 pb.Y = ez; 146 //如果點超出範圍,或者是阻擋點 147 if (0 < pb.X && pb.X < r.GetLength(1) 148 && 0 < pa.X && pa.X < r.GetLength(1) 149 && 0 < pb.Y && pb.Y < r.GetLength(0) 150 && 0 < pa.Y && pa.Y < r.GetLength(0) 151 && !CheckBlocking(r, pa) 152 && !CheckBlocking(r, pb)) 153 { 154 //開啟列表 155 List<Point> Open_List = new List<Point>(); 156 //關閉列表 157 List<Point> Close_List = new List<Point>(); 158 159 Open_List.Add(pa); 160 while (!(IsInOpenList(pb.X, pb.Y, Open_List) || Open_List.Count == 0)) 161 { 162 Point p0 = GetMinFFromOpenList(Open_List); 163 if (p0 == null) return null; 164 Open_List.Remove(p0); 165 Close_List.Add(p0); 166 CheckP8(p0, r, pa, pb, Open_List, Close_List); 167 } 168 Point p = GetPointFromOpenList(pb.X, pb.Y, Open_List); 169 return Reverse(p); 170 } 171 return null; 172 } 173 174 Point Reverse(Point point) 175 { 176 //新節點 177 Point newNode = null; 178 //當前節點 179 Point current = point; 180 while (current != null) 181 { 182 //取當前節點的下一個,放入臨時節點中 183 Point temp = current.Next; 184 //將當前節點的下一個設定為新節點 185 //(第一次將設定為null,也對著呢,因為第一個節點將作為尾節點) 186 current.Next = newNode; 187 //把當前節點給新節點 188 newNode = current; 189 //把臨時節點給當前節點(就是取當前節點的下一個而已) 190 current = temp; 191 } 192 //將最後的新節點給頭節點 193 return newNode; 194 } 195 196 public bool CheckBlocking(byte[,] r, Point point) 197 { 198 return CheckBlocking(r, point.X, point.Y); 199 } 200 201 public bool CheckBlocking(byte[,] r, int x, int y) 202 { 203 return r[y, x] == BlockConst; 204 } 205 206 public void PrintMap(byte[,] r) 207 { 208 Console.Clear(); 209 Console.ForegroundColor = ConsoleColor.Gray; 210 for (int y = 0; y < r.GetLongLength(0); y++)//Y軸 211 { 212 for (int x = 0; x < r.GetLongLength(1); x++)//X軸 213 { 214 Console.Write(r[y, x]); 215 } 216 Console.Write("\n"); 217 } 218 219 } 220 221 public void PrintWay(byte[,] r, Point way) 222 { 223 Console.ForegroundColor = ConsoleColor.Green; 224 while (way != null) 225 { 226 Console.CursorLeft = way.X; 227 Console.CursorTop = way.Y; 228 Console.Write("4"); 229 System.Threading.Thread.Sleep(50); 230 way = way.Next; 231 } 232 Console.ForegroundColor = ConsoleColor.Gray; 233 } 234 235 bool check(int x, int y, Point way) 236 { 237 Point f = way; 238 while (f != null) 239 { 240 if (f.X == x && f.Y == y) 241 { 242 return true; 243 } 244 f = f.Next; 245 } 246 return false; 247 } 248 } 249 250 public class Point 251 { 252 //座標點 253 public int Y { get; set; } 254 //座標點 255 public int X { get; set; } 256 //從起點到當前點的代價 257 public int G { get; set; } 258 //從終點到當前點的代價 259 public int H { get; set; } 260 261 public Point() 262 { 263 } 264 265 public Point Next { get; set; } 266 }

由於地圖阻擋點配置是由工具決定的,所以我根據我這裡的方式來建立測試程式碼

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 using System.Xml.Serialization;
 7 
 8 namespace ConsoleApplication1
 9 {
10     [XmlRootAttribute("SceneInfo_Server")]
11     [Serializable]
12     public class MapBlockConfig
13     {
14         public MapBlockConfig()
15         {
16 
17         }
18         [XmlAttribute("MapID")]
19         public int MapID { get; set; }
20 
21         [XmlElement("WalkSetting")]
22         public WalkSetting Walk { get; set; }
23                 
24         [Serializable]
25         public class WalkSetting
26         {
27             public WalkSetting()
28             {
29 
30             }
31             [XmlAttribute("RZLEN")]
32             public int Rzlen { get; set; }
33 
34 
35             [XmlAttribute("RXLEN")]
36             public int Rxlen { get; set; }
37 
38 
39             [XmlAttribute("STARTX")]
40             public int Startx { get; set; }
41 
42 
43             [XmlAttribute("STARTY")]
44             public int Starty { get; set; }
45 
46 
47             [XmlAttribute("STARTZ")]
48             public int Startz { get; set; }
49 
50 
51             [XmlAttribute("BLOCKINFO")]
52             public String Blockinfo { get; set; }
53         }
54 
55     }
56 }
View Code

阻擋配置

<?xml version="1.0" encoding="utf-8"?>
<SceneInfo_Server xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" MapID="3501">
  <WalkSetting RZLEN="120" RXLEN="120" STARTX="0" STARTY="200" STARTZ="0" BLOCKINFO="11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000001111111111111111111111111111111111111111111111111111111111111111111111111111000000000001111111111111111111111000000000000111111111111111111111111111111111111111110000000000111111111111111111111100000000000000111111111111111111110000000000000001111111111111111111111111111111111111100000000000011111111111111111111000000000000000011111111111111111100000000000000001111111111111111111111111111111111110000000000000001111111111111111111000000000000000011111111111111111000000000000000001111111111111111111111111111111111100000000000000000111111111111111110000000000000000001111111111111110000000000000000001111111111111111111111111111111111000000000000000000011111111111111110000000000000000001111111111111100000000000000000001111111111111111111111111111111110000000000000000000000111111111111110000000000000000000111111111111110000000000000000001111111111111111111111111111111110000000000000000000000011111111111110000000000000000000111111111111111000000000000000001111111111111111111111111111111110000000000000000000000001111111111111000000000000000000111111111111110000000000000000011111111111111111111111111111111110000000000000000000000000111111111111000000000000000000111111111111000000000000000000011111111111111111111111111111111110000000000000000000000000111111100000000000000000000000111111111110000000000000000000111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000111111111000000000000000000001111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000111111110000000000000000000011111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111111111111111111111111110000000000000000000000000111111100000000000000000000000000000000000000000000001111111111111111111111111111111111111111110000000000000000000000000111111100000000000000000000000000000000000000000000011111111111111111111111111111111111111111110000000000000000000000000111111100000000000000000000000000000000000000000001111111111111111111111111111111111111111111111110000000000000001111111111111110000000000000000000000000000000000000000011111111111111111111111111111111111111111111111110000000000000001111111111111111100000000000000000000000000000000000001111111111111111111111111111111111111111111111111110000000000000011111111111111111110000000000000000000001000000000000011111111111111111111111111111111111111111111111111110000000000000011111111111111111111100000000000000000011100000000000111111111111111111111111111111111111111111111111111110000000000000111111111111111111111110000000000000000111110000000000111111111111111111111111111111111111111111111111111110000000000000111111111111111111111111100000000000001111110000000000111111111111111111111111111111111111111111111111111110000000000000111111111111111111111111111111111110011111110000000000111111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111111111111111111110000000000111111111111111111111111111111111111111111111111111100000000000011111111111111111111111111111111111111111111111000000000111111111111111111111111111111111111111111111111111100000000000011111111111111111111111111111111111111111111111000000000111111111111111111111111111111111111111111111111111100000000000011111111111111111111111111111111111111111111111100000000111111111111111111111111111111111111111111111111111100000000000011111111111111111111111111111111111111111111111000000000111111111111111111111111111111111111111111111111111100000000000011111111111111111111111111111111111111111111111000000000111111111111111111111111111111111111111111111111111100000000000011111111111111111111111111111111111111111111111000000000111111111111111111111111111111111111111111111111111100000000000001111111111111111111111111111111111111111111111000000000111111111111111111111111111111111111111111111111111100000000000001111111111111111111111111111111111111111111111100000000011111111111111111111111111111111111111111111111111100000000000001111111111111110000111111111111111111111111111100000000000111111111111111111111111111111111111111111111111100000000000001111111111111100000000000000000111111111111111110000000000001111111111111111111111111111111111111111111111100000000000001111111111111000000000000000000000000001111111111000000000000001111111111111111111111111111111111111111111100000000000001111111111100000000000000000000000000000111111111110000000000000011111111111111111111111111111111111111111100000000000001111111111000000000000000000000000000000111111111110000000000000000111111111111111111111111111111111111111110000000000001111111110000000000000000000000000000000011111111110000000000000000001111111111111111111111111111111111111110000000000001111111000000000000000000000000000000000011111111110000000000000000000011111111111111111111111111111111111110000000000001111111000000000000000000000000000000000011111111110000000000000000000000111111111111111111111111111111111110000000000001111110000000000000000000000000000000000011111111110000000000000000000000001111111111111111111111111111111110000000000001111110000000000000000000000000000000000011111111110000000000000000000000000011111111111111111111111111111110000000000001111110000001100000000000000000000000000011111111110000000000000000000000000011111111111111111111111111111110000000000001111110000011111000000000000000000000000011111111110000000000000000000000000011111111111111111111111111111110000000000001111110000011111100000000000000000000000011111111110000000000000000000000000001111111111111111111111111111110000000000011111110000000111100000000000000000000000011111111110000000000000000000000000001111111111111111111111111111110000000000011111100000000000100000000000000000000000011111111110000000000000000000000000000111111111111111111111111111110000000000011111100000000000000000000000000000000000011111111110000000000000000000000000000111111111111111111111111111110000000000011111100000000000000000000000000000000000011111111110000000000000000000000000000011111111111100000000000011110000000000011111100000000000000000000000000000001000111111111110000000000000000000000000000011111111111100000000000011110000000000011111100000000001000000000000000000011111111111111110000000000000000000000000000001111111111100000000000011110000000000111111100000111111111111111111111111111111111111111110000000000000000000000000000001111111111100000000000011110000000000111111000000011111111111111111111111111111111111111110000000000000000000000000000001111111111100000000000011110000000000111111100000011111111111111111111111111111111110000000000000000000000000000000000000111111111100000000001111110000000000111111100000011111111111111111111111111111111100000000000000000000000000000000000000111111111100000000001111110000000000111111100000011111111111111111111111111111111100000000000000001110000000000000000000111111111100000000001111111000000000111111110000011111111111111111111111111111111100000000000000011111110000000000000000111111111100000000001111111000000000011111110000011111111111111111111111111111111100000000000000011111111110000000000000111111111100000000001111111000000000011111110000001111111111111111111111111111111000000000000000011111111110000000000000111111111100000000011111111000000000011111111000000111111111111111111111111111111000000000000000111111111110000000000000111111111100000000011111111000000000001111111000000011111111111111111111111111111000000000000000111111111100000000000000111111111100000000111111111000000000001111111000000001111111111111111111111111110000000000000001111111111100000000000000111111111100000000111111111100000000011111111000000000111111111111111111111111110000000000000001111111111100000000000000111111111100000000011111111100000000011111111100000000011111111111111111111111110000000000000001111111111000000000000000111111111100000000011111111100000000001111111100000000011111111111111111111111100000000000000011111111111000000000000000111111111100000000011111111100000000001111111100000000001111111111111111111111100000000000000011111111111000000000000000111111111100000000011111111100000000001111111110000000001111111111111111111111100000000000000011111111110000000000000000111111111100000000011111111100000000000111111110000000001111111111111111111111000000000000000111111111110000000000000000111111111100000000011111111100000000000111111110000000001111111111111111111100000000000000000111111111110000000000000000111111111100000000011111111100000000000111111111000000001111111111111111110000000000000000000111111111100000000000000000111111111100000000011111111100000000000001111111000000001111111111111111000000000000000000001111111111100000000000000000111111111100000000011111111100000000000001111111000000001111111111111100000000000000000000001111111111000000000000000000111111111100000000011111111100000000000000111111100000001111111111110000000000000000000000001111111111000000000000000000111111111100000000011111111100000000000000011111100000000000000000000000000000000000000000001111111111000000000000000000111111111100000000011111111100000000000000011111100000000000000000000000000000000000000000000111111111100000000000000000111111111100000000011111111100000000000000011111100000000000000000000000000000000000000000000111111111100000000000000000111111111100000000011111111100000000000000011111100000000000000000000000000000000000000000000011111111100000000000000001111111111100000000011111111100000000000000011111100000000000000000000000000000000000000000000011111111110000000000000011111111111100000000011111111100000000000000011111000000000000000000000000000000000000000000000011111111110000000000000111111111111100000000011111111100000000000000011111000000000000000000000000000000000000000000000001111111110000000000000111111111111100000000011111111100000000000000011111000000000000000000000000000000000000000000000001111111111000000111111111111111111100000000011111111100000000000000011111000000000000000000000000000000000000000000000000111111111000000111111111111111111100000000011111111100000000000000011111000000000000000000000000000000000000000000000000111111111100000111111111111111111100000000011111111110000000000000111111000000000000000000000000000000000000000000000000111111111111111111111111111111111100000000001111111000000000000011111110000000000000000000000000000000000010000000000000011111111111111111111111111111111100000000000111110000000000000111111110000000000000000000000000000000000111100000000000011111111111111111111111111111111100000000000111000000000000000111111110000000000000000000000000000000011111111100000000011111111111111111111111111111111100000000000010000000000000000111111110000000000000000000000000000000111111111111000000011111111111111111111111111111111100000000000000000000001000011111111110000000000000000000000000000001111111111111111000011111111111111111111111111111111100000000000000000000011111111111111111111111000000000000000000000011111111111111111111111111111111111111111111111111111100000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111