首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 開發 WPF/Silverlight 動畫與遊戲系列教程(二十):第一部分拓展小結篇

     編輯:關於C#

前言

二十節不間斷更新,暫作小結整理思緒,為第二部分更精彩內容鋪路:跟隨式地圖移動、NPC/怪物互動、AI、攻擊魔法、傷害計算、完美 RPG 界面等。

一、改進型完美 A* 尋路移動模式

第十九節雖實現全方向動作,但每次移動皆啟動 A*,造成資源浪費且非完美。改進型完美 A* 模式:移動時先建立兩點直線移動,即時檢測障礙物;無碰撞則保持直線至終點;一旦碰到障礙物,即時啟動 A* 繞行至目的地。

關鍵技術:啟發式預測法

傳統座標還原法會造成畫面彈跳,啟發式預測法即時預測前方單元格:

// 判斷是否將要碰撞障礙物(障礙物預測法)
private bool WillCollide() {
    switch ((int)Spirit.Direction) {
        case 0: return Matrix[(int)(Spirit.X / GridSize), (int)(Spirit.Y / GridSize) - 1] == 0;
        case 1: return Matrix[(int)(Spirit.X / GridSize) + 1, (int)(Spirit.Y / GridSize) - 1] == 0;
        case 2: return Matrix[(int)(Spirit.X / GridSize) + 1, (int)(Spirit.Y / GridSize)] == 0;
        case 3: return Matrix[(int)(Spirit.X / GridSize) + 1, (int)(Spirit.Y / GridSize) + 1] == 0;
        case 4: return Matrix[(int)(Spirit.X / GridSize), (int)(Spirit.Y / GridSize) + 1] == 0;
        case 5: return Matrix[(int)(Spirit.X / GridSize) - 1, (int)(Spirit.Y / GridSize) + 1] == 0;
        case 6: return Matrix[(int)(Spirit.X / GridSize) - 1, (int)(Spirit.Y / GridSize)] == 0;
        case 7: return Matrix[(int)(Spirit.X / GridSize) - 1, (int)(Spirit.Y / GridSize) - 1] == 0;
        default: return true;
    }
}

直線移動方法 NormalMoveTo() 新增朝向動畫,計算 totalcost 確保任意角度勻速移動:

private void NormalMoveTo(Point p) {
    int totalcost = (int)Math.Sqrt(Math.Pow(p.X - Spirit.X, 2) + Math.Pow(p.Y - Spirit.Y, 2)) / GridSize * UnitMoveCost;
    ...
    double direction = Super.GetDirectionByTan(p.X, p.Y, Spirit.X, Spirit.Y);
    var doubleAnimation = new DoubleAnimation(direction, direction, new Duration(TimeSpan.FromMilliseconds(totalcost)));
    Storyboard.SetTarget(doubleAnimation, Spirit);
    Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("Direction"));
    storyboard.Children.Add(doubleAnimation);
    storyboard.Begin();
}

滑鼠點擊啟動直線移動,設定 IsAStarMoving = false:

private void Carrier_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
    Point p = e.GetPosition(Map);
    if (Matrix[(int)p.X / GridSize, (int)p.Y / GridSize] != 0) {
        Spirit.Destination = p; Spirit.Action = Actions.Run;
        Spirit.IsAStarMoving = false; NormalMoveTo(p);
    }
}

視窗刷新線程中銜接邏輯:

private void Timer_Tick(object sender, EventArgs e) {
    if (ArriveTarget()) Spirit.Action = Actions.Stop;
    else if (!Spirit.IsAStarMoving && WillCollide()) {
        AStarMoveTo(Spirit.Destination);
        Spirit.IsAStarMoving = true;
    }
}

IsAStarMoving 為直線與 A* 移動的樞紐,避免重複判斷。測試成果:

二、完美遮罩層

第十一節遮罩層有瑕疵。新增標誌物 Mask3.png,設定 Canvas.SetZIndex(Mask, 612)(高度 + Y 值),精靈 ZIndex = Y 即時更新,實現畫家算法完美遮擋:

三、完美換裝

UI 添加下拉選單與按鈕,三行代碼實現:

private void ChangeEquipment(object sender, RoutedEventArgs e) {
    Spirit.Equipment[0] = Convert.ToInt32(comboBox1.SelectionBoxItem.ToString());
    Spirit.Equipment[1] = Convert.ToInt32(comboBox2.SelectionBoxItem.ToString());
    Spirit.Source = Super.EquipPart(Spirit.Equipment, Spirit.DirectionNum, Spirit.DirectionFrameNum,
        Spirit.TotalWidth, Spirit.TotalHeight, Spirit.SingleWidth, Spirit.SingleHeight);
}

首次換裝因合成計算會卡頓,再次換裝因快取極快,符合網遊體驗:

四、A* 尋路大補充

針對讀者反饋 A* 難度高,補充核心概念 GridSize(單位格尺寸):

  • 簡化障礙物陣列,地圖構造伸縮自如:GridSize=20 時 10000×10000 地圖只需 Matrix[500,500]
  • 提高尋路速度:40×40 區域內 GridSize=20 僅 4 個節點,GridSize=1 需 1600 個節點
  • SLG/回合制遊戲地圖引擎必備參數

第二部分展望

本節結束,第二部分開始,將深入真正 2D 遊戲製作核心領域。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved