此方法的優點是精確,可以定位到精靈有效實體的任一像素角落;而缺點是只能在WPF中使用且性能不好,更麻煩的是必須將之放 Try{}Catch{}塊內使用,否則極易出錯,因為精靈的圖片切換太快了。
解決此問題的另一方式為通過定義精靈實體區域參數public double[] EfficaciousSection來實現,此方法也是我推薦使用的方法,兼顧WPF/Silverlight。
EfficaciousSection由4個數組成,以上圖為例,它的EfficaciousSection = new double []{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);
}
}
然後再運行一下游戲,結果更奇怪的事情出現了:
如上圖,此時當鼠標停在主角身上時竟然沒有變換光標圖片,是代碼出問題了嗎?當然也不是。我們還是得從圖片上找原因。此時怪物的圖片遮擋住了主角,因此當鼠標懸停在主角身上時,系統卻仍然判斷當前捕獲的是“絕對無敵”,並且鼠標也未進入它的有效實體范圍,因此鼠標光標仍然是0號。
怎麼辦?搞了這麼久到頭來仍然是一場空。有朋友提出了將圖片裁剪成剛好包裹住精靈有效實體區域不就好了。想法是好的,但是將造成每一幀圖片都為不同尺寸規格,在動作中如何切換?每張圖片都得定義它距離容器Canvas左上角的距離,一個怪物幾百張圖片,每張都要定義,這將大大增加游戲的開發負擔。
難道沒有完美的解決方案了嗎?WPF/Silverlight中最不起眼但卻有著極其重要作用的神器登場了!對,就是它了:HitTest(命中測試)。
稱之為命中測試,不如叫它穿透點擊來得更形象些。因為它強大到只要游戲窗口中有的東西,它都能抓出來,想抓幾個抓幾個,想抓到什麼深度(Zindex)就抓到什麼深度;更甚者,它可以肢解封裝的控件直接抓取其內部任意對象控件;完成以上各種任務如若探囊取物搬輕盈且高效,僅僅是通過模擬鼠標點擊幾乎忽略不計的敏捷捕獲。關於HitTest的更多相關知識及原理請大家自行網上查閱,這裡不具體講解了。接下來我們看下圖:
在游戲中如何使用HitTest進行對象捕獲的原理在上圖中已經描述得非常清楚了,接下來看我如何通過代碼進行實現:
首先我定義一個精靈容器用於將捕獲到的所有精靈進行收容管理:
List<QXSpirit> SpiritList = new List<QXSpirit>();
接下來定義HitTest的過濾器HitFilter,用於篩選HitTest捕獲的對象,我們只需要捕獲QXSpirit類型對象即可,然後將之添加進精靈容器:
public HitTestFilterBehavior HitFilter(DependencyObject dObject) {
if (dObject is QXSpirit) {
SpiritList.Add(dObject as QXSpirit);
}
return HitTestFilterBehavior.Continue;
}