构建好障碍物后运行程序测试的效果如下图:
障碍物终于绘制完毕了,那么接下来就是动画部分了。还记得我们第六章中实现2D人物移动动画吗?其中有提到人物的移动基于它的左上角坐标,这是不真实的,那么我们需要为主角定义X,Y坐标,实现真实的定位到主角的脚底,所以我们这里需要一个逻辑:
int count = 1;
Image Spirit = new Image(); //创建主角
int SpiritCenterX = 4; //主角脚底离主角图片左边的距离(游戏坐标系中)
int SpiritCenterY = 5; //主角脚底离主角顶部的距离(游戏坐标系中)
//游戏坐标系中Spirit坐标(缩小操作)
int _SpiritGameX;
int SpiritGameX {
get { return ((int)Canvas.GetLeft(Spirit) / GridSize) + SpiritCenterX; }
set { _SpiritGameX = value; }
}
int _SpiritGameY;
int SpiritGameY {
get { return ((int)Canvas.GetTop(Spirit) / GridSize) + SpiritCenterY; }
set { _SpiritGameY = value; }
}
//窗口坐标系中Spirit坐标(放大操作)
int SpiritWindowX {
get { return (SpiritGameX - SpiritCenterX) * GridSize; }
}
int SpiritWindowY {
get { return (SpiritGameY - SpiritCenterY) * GridSize; }
}
上一节有说到关于两个不同坐标系同时存在的问题,上面的代码就是对它们的定义并且实现它们之间相互转换,设置好以后,就可以根据情况的需要来分别调用不同坐标系下主角的X,Y坐标了。
定义好地图、障碍物和主角的坐标系以后,接着需要对主角和地图初始化:
InitializeComponent();
ResetMatrix(); //初始化二维矩阵
InitPlayer(); //初始化目标对象
InitMap(); //初始化地图
DispatcherTimer dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
dispatcherTimer.Interval = TimeSpan.FromMilliseconds(150);
dispatcherTimer.Start();
}
可以看到后面4行代码那么的眼熟?其实就是第三节所讲到的知识。最后就是本节的重头戏,实现鼠标点击事件:
private void Carrier_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
Point p = e.GetPosition(Carrier);
//进行坐标系缩小
int start_x = SpiritGameX;
int start_y = SpiritGameY;
Start = new System.Drawing.Point(start_x, start_y); //设置起点坐标
int end_x = (int)p.X / GridSize;
int end_y = (int)p.Y / GridSize;
End = new System.Drawing.Point(end_x, end_y); //设置终点坐标
……
if (path == null) {
MessageBox.Show("路径不存在!");
} else {
……
for (int i = 0; i < framePosition.Count(); i++) {
//加入X轴方向的匀速关键帧
LinearDoubleKeyFrame keyFrame = new LinearDoubleKeyFrame();
//平滑衔接动画
keyFrame.Value = i == 0 ? Canvas.GetLeft(Spirit) : (framePosition[i].X - SpiritCenterX * GridSize);
keyFrame.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(cost * i));
keyFramesAnimationX.KeyFrames.Add(keyFrame);
//加入X轴方向的匀速关键帧
keyFrame = new LinearDoubleKeyFrame();
keyFrame.Value = i == 0 ? Canvas.GetTop(Spirit): (framePosition[i].Y - SpiritCenterY * GridSize);
keyFrame.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(cost * i));
keyFramesAnimationY.KeyFrames.Add(keyFrame);
}
……
}
}
代码和上一节里的没有多大的区别,改动为我用黄色背景色描绘的区域(…….号表示该段代码与上一节不变)。主要就是针对如何进行主角真实脚底坐标在两个坐标系中的换算问题进行了布局修改,大家可以与上一节里的示例代码进行比较,非常容易就可以进行分析理解,这里我就不再累述了。大功告成啦,我将障碍物的表现去掉,然后国际惯例Ctrl+F5测试一下我们的成果吧:
至此,我们就实现了2D游戏人物在地图中的移动。大家再回头看看或许会发现:本节地图中的障碍物均是由正方形块组成,也就是说地图是基于直角坐标系的。但是在实际的游戏制作中,特别是SLG走格子回合制等类型的游戏中,基本都采用斜度的地图构造。那么下一节我将就如何构造斜度坐标系地图进行讲解,敬请关注。
原文地址:http://www.cnblogs.com/alamiye010/archive/2009/06/17/1505340.html