有了以上的基础知识作铺垫,后面的内容可谓小儿科了。
首要任务:构造W坐标系与G坐标系的换算公式。假设W坐标系下某点坐标为(W(x),W(y)),该点在G坐标系中的坐标为(G(x),G(y)),那么它们之间的换算公式即为:
W(y)=(G(x)+G(y))*cosα
G(x)=(W(y)*sinα+W(x)*cosα)/2*sinα*cosα
G(y)=(W(y)*sinα-W(x)*cosα)/2*sinα*cosα
这乃本节之精华所在,好比上帝的右手,阿拉丁的神灯无所不能、天下无敌!汗一个。。。好了,有了该法宝,那么我们开始练练手吧,看看一个斜度60的地图是如何构造的。
首先我将该公式用代码来表示写成两个方法,方法名很明确,它们的作用是分别获取某点在G坐标系和W坐标系中的坐标:
//将窗口坐标系中的坐标换算成游戏坐标系中的坐标(缩小操作)
private Point getGamePosition(double x, double y) {
return new Point(
(int)((y + (x / 1.732)) / GridSize),
(int)((y - (x / 1.732)) / GridSize)
);
}
//将游戏坐标系中的坐标换算成窗口坐标系中的坐标(放大操作)
private Point getWindowPosition(double x, double y) {
return new Point(
(x - y) * 0.886 * GridSize,
(x + y) * 0.5 * GridSize
);
}
这里我进行了简单的正弦与余弦的取值,即sin60=1.732,cos60=0.5,那么(sin60)/2=1.732/2=0.886。一张地图中是不可能存在两个α值的,所以本例在定义好α=60度后,我直接取它的正弦与余弦值这将有效的提高运算效率。
接下来就是构建障碍物了,只有通过它我们才能非常直观的看到这个斜度α地图的构造:
//构建障碍物
for (int x = 10; x < 20; x++) {
for (int y = 1; y < 10; y++) {
Matrix[x, y] = 0;
rect = new Rectangle();
//构建菱形
TransformGroup transformGroup = new TransformGroup();
SkewTransform skewTransform = new SkewTransform(-10, -25);
RotateTransform rotateTransform = new RotateTransform(54);
transformGroup.Children.Add(skewTransform);
transformGroup.Children.Add(rotateTransform);
rect.RenderTransform = transformGroup;
rect.Fill = new SolidColorBrush(Colors.GreenYellow);
rect.Opacity = 0.3;
rect.Stroke = new SolidColorBrush(Colors.Gray);
rect.Width = GridSize;
rect.Height = GridSize+2;
Carrier.Children.Add(rect);
Point p = getWindowPosition(x, y);
Canvas.SetLeft(rect, p.X);
Canvas.SetTop(rect, p.Y);
}
}
这里我用菱形方块真实的模拟障碍物视觉效果。接下来就是在上一节代码的基础上将窗口鼠标左键事件中相关的坐标值通过上面写的两个方法getGamePosition(double x, double y)和getWindowPosition(double x, double y)进行替换,实际上改动的地方不过4处,我用黄色背景色进行了标识(…….号表示该段代码与上一节不变),具体如下:
private void Carrier_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
Point p = e.GetPosition(Carrier);
//进行坐标系缩小
Point start = getGamePosition(Canvas.GetLeft(Spirit) + SpiritCenterX,
Canvas.GetTop(Spirit) + SpiritCenterY);
Start = new System.Drawing.Point((int)start.X, (int)start.Y); //设置起点坐标
Point end = getGamePosition(p.X, p.Y);
End = new System.Drawing.Point((int)end.X, (int)end.Y); //设置终点坐标
…….
if (path == null) {
MessageBox.Show("路径不存在!");
} else {
Point[] framePosition = new Point[path.Count]; //定义关键帧坐标集
for (int i = path.Count - 1; i >= 0; i--) {
//从起点开始以GridSize为单位,顺序填充关键帧坐标集,并进行坐标系放大
framePosition[path.Count - 1 - i] = getWindowPosition(path[i].X, path[i].Y);
}
…….
//用白色点记录移动轨迹
for (int i = path.Count - 1; i >= 0; i--) {
rect = new Rectangle();
rect.Fill = new SolidColorBrush(Colors.Snow);
rect.Width = 4;
rect.Height = 4;
Carrier.Children.Add(rect);
Point target = getWindowPosition(path[i].X, path[i].Y);
Canvas.SetLeft(rect, target.X);
Canvas.SetTop(rect, target.Y);
}
}
}
如果大家能将上一节中讲解的内容都吸收的话,那么可以将修改的部分与上一节的代码进行对比,再结合本节前部分内容的讲解就会慢慢的理解了(请大家发散自己的思维吧)。
到这我们就完成了该斜度60的地图构造。按Ctrl+F5看看我们的成果吧:
