程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> C#開發WPF/Silverlight動畫及游戲系列教程(Game Course):(十九)(2)

C#開發WPF/Silverlight動畫及游戲系列教程(Game Course):(十九)(2)

編輯:關於C語言

原理在上圖右半部分的注釋中描述很清楚;我依據此原理寫了個通用判斷朝向的方法,精華哦:

/// <summary>
/// 通過正切值獲取精靈的朝向代號
/// </summary>
/// <param name="targetX">目標點的X值</param>
/// <param name="targetY">目標點的Y值</param>
/// <param name="currentX">當前點的X值</param>
/// <param name="currentY">當前點的Y值</param>
/// <returns>精靈朝向代號(以北為0順時針依次1,2,3,4,5,6,7)</returns>
public static double GetDirectionByTan(double targetX, double targetY, double currentX, double currentY) {
 double tan = (targetY - currentY) / (targetX - currentX);
 if (Math.Abs(tan) >= Math.Tan(Math.PI * 3 / 8) && targetY <= currentY) {
   return 0;
 } else if (Math.Abs(tan) > Math.Tan(Math.PI / 8) && Math.Abs(tan) < Math.Tan(Math.PI * 3 / 8) && targetX > currentX && targetY < currentY) {
   return 1;
 } else if (Math.Abs(tan) <= Math.Tan(Math.PI / 8) && targetX >= currentX) {
   return 2;
 } else if (Math.Abs(tan) > Math.Tan(Math.PI / 8) && Math.Abs(tan) < Math.Tan(Math.PI * 3 / 8) && targetX > currentX && targetY > currentY) {
   return 3;
 } else if (Math.Abs(tan) >= Math.Tan(Math.PI * 3 / 8) && targetY >= currentY) {
   return 4;
 } else if (Math.Abs(tan) > Math.Tan(Math.PI / 8) && Math.Abs(tan) < Math.Tan(Math.PI * 3 / 8) && targetX < currentX && targetY > currentY) {
   return 5;
 } else if (Math.Abs(tan) <= Math.Tan(Math.PI / 8) && targetX <= currentX) {
   return 6;
 } else if (Math.Abs(tan) > Math.Tan(Math.PI / 8) && Math.Abs(tan) < Math.Tan(Math.PI * 3 / 8) && targetX < currentX && targetY < currentY) {
   return 7;
 } else {
   return 0;
 }
}

由於Math.Tan()函數的參數為弧度單位,因此需要將角度通過公式換算成弧度,並且至於之中的比較算法邏輯是否為最優,仍然那句老話:仁者見仁,智者見智。或許你寫的算法更優秀呢?

有了該方法,接下來就是在鼠標左鍵點擊事件中獲取目標點,並且將主角的當前動作切換成跑步狀態,並啟動A*尋路:

private void CarrIEr_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
 Point p = e.GetPosition(Map); //點擊的地方在Map中的坐標點
 Spirit.Action = Actions.Run; //主角動作切換成跑步狀態
 AStarMoveTo(p); //開始尋路
}

上兩節的AstarMoveTo()方法中的Storyboard動畫只創建X,Y序列點,而為了實現角色時時朝向,我們還需要創建對應的角色方向(Direction)序列點,因此我們還需要對本節中的AstarMoveTo()方法進行如下改進:

private void AStarMoveTo(Point p) {
 ……
 //創建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"));
 //創建朝向動畫
 DoubleAnimationUsingKeyFrames keyFramesAnimationDirection = new DoubleAnimationUsingKeyFrames();
 keyFramesAnimationDirection.Duration = new Duration(TimeSpan.FromMilliseconds(path.Count * cost));
 Storyboard.SetTarget(keyFramesAnimationDirection, Spirit);
 Storyboard.SetTargetProperty(keyFramesAnimationDirection, new PropertyPath("Direction"));
  for (int i = 0; i < framePosition.Count(); i++) {
   //加入X軸方向的勻速關鍵幀
   LinearDoubleKeyFrame keyFrame = new LinearDoubleKeyFrame();
   //平滑銜接動畫(將尋路坐標系中的坐標放大回地圖坐標系中的坐標)
   keyFrame.Value = i == 0 ? Spirit.X : framePosition[i].X * 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 * GridSize;
   keyFrame.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(cost * i));
   keyFramesAnimationY.KeyFrames.Add(keyFrame);
   //加入朝向勻速關鍵幀
   keyFrame = new LinearDoubleKeyFrame();
   keyFrame.Value = i == framePosition.GetUpperBound(0)
   ? Super.GetDirectionByTan(framePosition[i].X, framePosition[i].Y, framePosition[i - 1].X, framePosition[i - 1].Y)
   : Super.GetDirectionByTan(framePosition[i + 1].X, framePosition[i + 1].Y, framePosition[i].X, framePosition[i].Y)
   ;
   keyFrame.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(cost * i));
   keyFramesAnimationDirection.KeyFrames.Add(keyFrame);
 }
 storyboard.Children.Add(keyFramesAnimationX);
 storyboard.Children.Add(keyFramesAnimationY);
 storyboard.Children.Add(keyFramesAnimationDirection);
……
}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved