这里要特别讲解一下GridSize这个变量,它定义了窗口坐标系中以多大一个尺寸来确定游戏坐标系的一个单元格(大家可以这样理解这两种不同的坐标系:假如游戏窗口大小为800*600像素,那么窗口坐标系中的(80,100)这个坐标,根据GridSize = 20来换算,在游戏坐标系中的坐标则为(80/20,100/20)=(4,5))。大家同时可以联想一下SLG类型游戏,人物处于的每个单元格都是由N*N像素组成的方块,GridSize就相当于N了;而该格子在游戏坐标系中的显示坐标则为((N/20), (N/20)),这样应该很好理解了吧。这样根据不同的需要来使用GridSize对坐标系进行缩小(/GridSize)和放大(*GridSize)操作,从而可以非常方便的实现各种效果并且被不同的情况所调用,后面的内容及章节会涉及到相关知识。
那么接下来我们在窗体构造函数中初始化二维矩阵,代码如下:
public Window7() {
InitializeComponent();
ResetMatrix(); //初始化二维矩阵
}
private void ResetMatrix() {
for (int y = 0; y < Matrix.GetUpperBound(1); y++) {
for (int x = 0; x < Matrix.GetUpperBound(0); x++) {
//默认值可以通过(非障碍物)在矩阵中用1表示
Matrix[x, y] = 1;
}
}
//构建障碍物(举例)
for (int i = 0; i < 18; i++) {
//障碍物在矩阵中用0表示
Matrix[i, 12] = 0;
rect = new Rectangle();
rect.Fill = new SolidColorBrush(Colors.Red);
rect.Width = GridSize;
rect.Height = GridSize;
Carrier.Children.Add(rect);
Canvas.SetLeft(rect, i * GridSize);
Canvas.SetTop(rect, 12 * GridSize);
}
//构建其他障碍物……(省略)
Start = new System.Drawing.Point(1, 1); //设置起点坐标
}
那么有了我们前面6节的知识基础并结合相应的注释,这些代码应该很容易可以接受。主要作用是定义起点,初始化矩阵中所有元素(默认都是可以通行的赋值1),然后我们可以设置些障碍物来测试我们寻径的效果,即根据需要将矩阵中需要变成障碍物的元素赋值0,这样我们就将所有的准备工作做好了。
最后就是如何实现寻径啦,代码如下:
private void Carrier_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
Point p = e.GetPosition(Carrier);
int x = (int)p.X / GridSize;
int y = (int)p.Y / GridSize;
End = new System.Drawing.Point(x, y); //计算终点坐标
PathFinder = new PathFinderFast(Matrix);
PathFinder.Formula = HeuristicFormula.Manhattan; //使用我个人觉得最快的曼哈顿A*算法
PathFinder.SearchLimit = 2000; //即移动经过方块(20*20)不大于2000个(简单理解就是步数)
List<PathFinderNode> path = PathFinder.FindPath(Start, End); //开始寻径
if (path == null) {
MessageBox.Show("路径不存在!");
} else {
string output = string.Empty;
for (int i = path.Count - 1; i >= 0; i--) {
output = string.Format(output
+ "{0}"
+ path[i].X.ToString()
+ "{1}"
+ path[i].Y.ToString()
+ "{2}",
"(", ",", ") ");
rect = new Rectangle();
rect.Fill = new SolidColorBrush(Colors.Green);
rect.Width = GridSize;
rect.Height = GridSize;
Carrier.Children.Add(rect);
Canvas.SetLeft(rect, path[i].X * GridSize);
Canvas.SetTop(rect, path[i].Y * GridSize);
}
MessageBox.Show("路径坐标分别为:" + output);
}
}
这里我将鼠标左键点击的点作为寻径的动态终点,然后创建寻径类PathFinder,接着定义好参数后就可以通过List<PathFinderNode> path = PathFinder.FindPath(Start, End);来实现寻径了。最后通过MessageBox将我们找到的路径点逐一打印出来,至此就完成了我们完美的曼哈顿A*寻径了。
上图为程序运行图,绿色代表找到的路径,红色代表障碍物,找到的路径同样如此的完美!是不是很有成就感?
有了这A*算法寻径类,可以说地图引擎就好比完成了一半不为过;那么下一节我将介绍如何通过此节获取的List<PathFinderNode> path列表来实现按照此列表实现的动态关键帧动画,敬请期待。