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

C# 開發 WPF/Silverlight 動畫與遊戲系列教程(二十五):完美捕捉精靈之神器 — HitTest

     編輯:關於C#

滑鼠游標狀態規範

為區分滑鼠狀態,約定四種游標:空曠地圖區域顯示預設游標(0 號);滑鼠懸停精靈上方顯示發光游標(1 號);指向敵對精靈顯示攻擊游標(2 號);使用魔法快捷鍵顯示凝法狀態游標(3 號)。

游標載入與管理

新增 Cursors 資料夾存放 4 個 .ani 檔案,透過靜態陣列快取:

public static Cursor[] GameCursors = new Cursor[4];

public static Cursor getCursor(int sign) {
    if (GameCursors[sign] == null) {
        GameCursors[sign] = new Cursor(new FileStream(string.Format(@"Cursors\{0}.ani", sign), FileMode.Open, FileAccess.Read, FileShare.Read));
    }
    return GameCursors[sign];
}

初步嘗試:簡單型別判斷

在視窗 MouseMove 事件中:

private void Window_MouseMove(object sender, MouseEventArgs e) {
    this.Cursor = e.Source is QXSpirit ? Super.getCursor(1) : Super.getCursor(0);
}

問題:精靈圖片為透明背景 PNG/GIF,整個 200×200 區域皆屬 Image 控件範圍,導致滑鼠在透明區域也觸發 1 號游標。

方案一:像素級顏色拾取(僅限 WPF、效能差)

對當前拾取物件圖片源進行逐點顏色檢測:

public static Color getImagePointColor(BitmapSource bitmapsource, int x, int y) {
    CroppedBitmap crop = new CroppedBitmap(bitmapsource as BitmapSource, new Int32Rect(x, y, 1, 1));
    byte[] pixels = new byte[4];
    try {
        crop.CopyPixels(pixels, 4, 0);
        crop = null;
    } catch (Exception ee) { MessageBox.Show(ee.ToString()); }
    return Color.FromArgb(pixels[3], pixels[2], pixels[1], pixels[0]);
}

優點:精確到像素;缺點:僅限 WPF、效能差、需包在 Try-Catch 中、圖片切換快易出錯。

方案二:有效實體區域參數(推薦,相容 WPF/Silverlight)

定義 public double[] EfficaciousSection 參數:{左邊距, 右邊距, 上邊距, 下邊距},僅在滑鼠進入此矩形區域才判定捕獲。例如 200×200 怪物圖片,有效區域 {80, 125, 50, 145}。

改進滑鼠移動事件:

if (e.Source is QXSpirit) {
    QXSpirit Spirit = e.Source as QXSpirit;
    Point p = e.GetPosition(Spirit);
    if (p.X >= Spirit.EfficaciousSection[0] && p.X <= Spirit.EfficaciousSection[1]
        && p.Y >= Spirit.EfficaciousSection[2] && p.Y <= Spirit.EfficaciousSection[3]) {
        this.Cursor = Super.getCursor(1);
    } else {
        this.Cursor = Super.getCursor(0);
    }
}

新問題:怪物圖片遮擋主角時,滑鼠懸停主角上方實捕獲到怪物,且滑鼠未進怪物有效區域,導致主角游標不變。

終極方案:HitTest 命中測試(穿透點擊)

HitTest 能穿透所有層級捕獲視覺樹中任意深度的物件,效能極高。原理示意圖如下:

實現步驟

  1. 定義精靈容器收集捕獲物件:List<QXSpirit> SpiritList = new List<QXSpirit>();
  2. 定義過濾器 HitFilter,僅保留 QXSpirit 型別:
public HitTestFilterBehavior HitFilter(DependencyObject dObject) {
    if (dObject is QXSpirit) SpiritList.Add(dObject as QXSpirit);
    return HitTestFilterBehavior.Continue;
}
  1. 定義結果處理 HitResult,繼續向深層遞迴:
public HitTestResultBehavior HitResult(HitTestResult result) {
    return HitTestResultBehavior.Continue;
}
  1. 在滑鼠移動事件執行 HitTest:
private void Window_MouseMove(object sender, MouseEventArgs e) {
    SpiritList.Clear();
    Point p = e.GetPosition(Carrier);
    VisualTreeHelper.HitTest(Carrier, new HitTestFilterCallback(HitFilter), new HitTestResultCallback(HitResult), new PointHitTestParameters(p));
    if (SpiritList.Count > 0) {
        for (int i = 0; i < SpiritList.Count; i++) {
            if (isEfficaciousSection(SpiritList[i].EfficaciousSection, e.GetPosition(SpiritList[i]))) {
                this.Cursor = Super.getCursor(1);
                label3.Content = SpiritList[i].Name; // 除錯用
                break;
            } else {
                this.Cursor = Super.getCursor(0);
            }
        }
    }
}

每次移動清空容器,對 Carrier 中滑鼠位置執行點擊測試,過濾後遍歷容器內精靈,僅當滑鼠在有效實體區域才判定捕獲成功。

測試成果:密集怪物區精準捕獲

地圖密集區加入 30 隻不同名稱怪物,滑鼠移動捕獲極其準確:

捕獲特效:半透明高亮(相容 WPF/Silverlight)

描邊方案 (OuterGlowBitmapEffect) 僅限 WPF 且效能極差。採用半透明方案,僅增改 6 行代碼:

private void Window_MouseMove(object sender, MouseEventArgs e) {
    ...
    if (SpiritList.Count > 0) {
        bool targetIsFound = false;
        for (int i = 0; i < SpiritList.Count; i++) {
            if (!targetIsFound && isEfficaciousSection(SpiritList[i].EfficaciousSection, e.GetPosition(SpiritList[i]))) {
                this.Cursor = Super.getCursor(1);
                SpiritList[i].Opacity = 0.6;
                targetIsFound = true;
                label3.Content = SpiritList[i].Name;
            } else {
                if (!targetIsFound) this.Cursor = Super.getCursor(0);
                SpiritList[i].Opacity = 1;
            }
        }
    }
}

效果圖:

小結

HitTest 功能強大,是實現打怪與施法的前提。下節將講解精靈面板界面及生命、魔力、經驗值三大屬性表現形式。

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