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

WPF/Silverlight 遊戲開發教程 (15):精靈控件核心實作 — 依賴屬性、專屬執行緒與地圖跟隨邏輯

     編輯:關於C#

精靈控件架構總覽

本章完成 QXSpirit 用戶控件的後台邏輯,核心包含三大支柱:

  1. 依賴屬性:X、Y 支援 Storyboard 動畫、Binding、樣式觸發
  2. 專屬 DispatcherTimer:作為精靈「生命線」,驅動幀動畫、狀態機、AI 邏輯
  3. 圖片來源與幀率控制:ImageAddress、Timer.Interval 實現動作速度動態調整

依賴屬性實作:X 與 Y

// X 依賴屬性
public double X
{
    get => (double)GetValue(XProperty);
    set => SetValue(XProperty, value);
}
public static readonly DependencyProperty XProperty =
    DependencyProperty.Register("X", typeof(double), typeof(QXSpirit),
        new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.None));

// Y 依賴屬性(結構相同)
public double Y { get => (double)GetValue(YProperty); set => SetValue(YProperty, value); }
public static readonly DependencyProperty YProperty =
    DependencyProperty.Register("Y", typeof(double), typeof(QXSpirit),
        new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.None));

為何必須用依賴屬性? 普通 CLR 屬性(double _X; public double X { get; set; })無法作為 Storyboard 目標屬性、不支援資料繫結、不支援樣式/觸發器/動畫繼承。依賴屬性雖樣板碼較多,但在 WPF/Silverlight 視覺樹與動畫系統中不可或缺。

專屬執行緒:DispatcherTimer 初始化

public QXSpirit()
{
    InitializeComponent();
    InitThread();
}

DispatcherTimer Timer = new DispatcherTimer();
private void InitThread()
{
    Timer.Tick += Timer_Tick;
    Timer.Start();
}

int count = 1;
private void Timer_Tick(object sender, EventArgs e)
{
    Body.Source = new BitmapImage(new Uri(ImageAddress + count + ".png", UriKind.Relative));
    count = count == 7 ? 0 : count + 1;
}

每個精靈實例擁有獨立 DispatcherTimer,優先級預設 Normal,間隔由外部設定(Spirit.Timer.Interval)。Timer_Tick 目前僅演示循環切換 0~7 幀圖片,後續將擴展為狀態機:待機、移動、攻擊、施法、受擊、死亡等狀態各自對應不同幀序列與幀率。

一般屬性:ImageAddress

string _ImageAddress;
public string ImageAddress
{
    get => _ImageAddress;
    set => _ImageAddress = value;
}

圖片目錄路徑不需動畫/繫結,普通屬性即可。

遊戲主視窗整合精靈

using WPFGameCourse.Controls;

QXSpirit Spirit = new QXSpirit();
private void InitSpirit()
{
    Spirit.X = 300;
    Spirit.Y = 400;
    Spirit.Timer.Interval = TimeSpan.FromMilliseconds(150); // 幀率 ~6.67 FPS
    Spirit.ImageAddress = @"..\Player\";
    Carrier.Children.Add(Spitit);
}

地圖移動時精靈與障礙物跟隨邏輯

在主視窗的 CompositionTarget.Rendering 或 DispatcherTimer.Tick 中:

int scrollspeed = 3;
private void Timer_Tick(object sender, EventArgs e)
{
    double mapLeft = Canvas.GetLeft(Map);
    double mapTop = Canvas.GetTop(Map);

    // 主角跟隨
    Canvas.SetLeft(Spirit, Spirit.X + mapLeft);
    Canvas.SetTop(Spirit, Spirit.Y + mapTop);

    // 障礙物跟隨(示範用,實際建議用虛擬化面板)
    foreach (UIElement uie in Carrier.Children)
    {
        if (uie is Rectangle rect)
        {
            Point p = GetPointFromTag(rect.Tag); // 解析 Tag 存儲的邏輯座標
            Canvas.SetLeft(rect, mapLeft + p.X * GridSize);
            Canvas.SetTop(rect, mapTop + p.Y * GridSize);
        }
    }
}

公式核心:視覺位置 = 邏輯位置 + 地圖偏移量。精靈因有 X/Y 依賴屬性直接存儲邏輯座標,無需解析 Tag,效能更佳。

障礙物 Tag 座標解析輔助方法

private Point GetPointFromTag(object tag)
{
    string[] s = tag.ToString().Split(',');
    return new Point(double.Parse(s[0]), double.Parse(s[1]));
}

建構障礙物時將邏輯格座標存入 Tag:rect.Tag = $"{x},{y}";。

執行效果確認

按 Ctrl+F5 執行,拖曳地圖時主角與障礙物同步移動,位置精確無誤差。但此時主角尚無「點擊地圖自主寻路移動」能力,下一章將整合第 16 章的 A* 尋路邏輯,完成牽引式地圖模式下的完整角色移動系統。

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