接下來就是對A*尋路移動方法進行改造了:
private void AStarMoveTo(Point p) {
//進行坐標系縮小
int start_x = GameSystemX;
int start_y = GameSystemY;
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 {
......
//創建X軸方向逐幀動畫
DoubleAnimationUsingKeyFrames keyFramesAnimationX = new DoubleAnimationUsingKeyFrames();
//總共花費時間 = path.Count * cost
keyFramesAnimationX.Duration = new Duration(TimeSpan.FromMilliseconds(path.Count * cost));
Storyboard.SetTarget(keyFramesAnimationX, Spirit);
Storyboard.SetTargetProperty(keyFramesAnimationX, new PropertyPath("X"));
//創建Y軸方向逐幀動畫
DoubleAnimationUsingKeyFrames keyFramesAnimationY = new DoubleAnimationUsingKeyFrames();
keyFramesAnimationY.Duration = new Duration(TimeSpan.FromMilliseconds(path.Count * cost));
Storyboard.SetTarget(keyFramesAnimationY, Spirit);
Storyboard.SetTargetProperty(keyFramesAnimationY, new PropertyPath("Y"));
for (int i = 0; i < framePosition.Count(); i++) {
//加入X軸方向的勻速關鍵幀
LinearDoubleKeyFrame keyFrame = new LinearDoubleKeyFrame();
//平滑銜接動畫(將尋路坐標系中的坐標放大回地圖坐標系中的坐標)
keyFrame.Value = i == 0 ? Spirit.X : (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 ? Spirit.Y : (framePosition[i].Y - SpiritCenterY) * GridSize;
keyFrame.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(cost * i));
keyFramesAnimationY.KeyFrames.Add(keyFrame);
}
......
}
}
以上代碼中用黃色背景突出的即為需要修改的地方,其中Storyboard.SetTargetProperty(keyFramesAnimationX, new PropertyPath("X"));和Storyboard.SetTargetProperty(keyFramesAnimationY, new PropertyPath("Y"));這兩句作用是將主角(Spirit)的X,Y屬性值作為Storyboard動畫的更新對象目標,值得注意的是keyFrame.Value = i == 0 ? Spirit.X : (framePosition[i].X - SpiritCenterX) * GridSize;與keyFrame.Value = i == 0 ? Spirit.Y : (framePosition[i].Y - SpiritCenterY) * GridSize;這兩句話,它們的作用是將尋路後得到的所有路徑點按從角色起點到終點這樣的順序依次做為Storyboard的關鍵幀添加進Storyboard動畫中,並且首先捨棄尋路得到的第一個點而以坐標(Spirit.X,Spirit.Y)作為動畫起點(…i == 0 ? Spirit.X ……i == 0 ? Spirit.Y…)從而起到平滑銜接動畫的效果。千萬別小看它,很多人往往忽略了它導致動畫銜接粗糙(大家可以嘗試將keyFrame.Value = i == 0 ? Spirit.X : (framePosition[i].X - SpiritCenterX) * GridSize;替換成keyFrame.Value = (framePosition[i].X - SpiritCenterX) * GridSize;將keyFrame.Value = i == 0 ? Spirit.Y : (framePosition[i].Y - SpiritCenterY) * GridSize;替換成keyFrame.Value = (framePosition[i].Y - SpiritCenterY) * GridSize;後再運行一下程序看看,當角色正在移動且還未到達終點的時候,此時你用鼠標再點擊別的地方讓主角向新的目的地移動,由於未采取平滑處理將導致角色會突然跳動一下的效果(起始坐標定位錯誤BUG)。為了配合大家更好的理解,我用張圖來說明(圖中的網格即為單位為20*20的單元格,即GridSize=20的效果):