障礙物終於繪制完畢了,那麼接下來就是動畫部分了。還記得我們第六章中實現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坐標了。
定義好地圖、障礙物和主角的坐標系以後,接著需要對主角和地圖初始化:
public Window9() {
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);
}
……
}
}