Flyer04講過了如何產生敵人並且開始進行漂亮的“搖擺”,真正的困難才剛剛開始,因為現在主角是完全無敵的,那些什麼什麼東西必須對主角造成傷害才顯得有趣,對於遊戲中如何進行傷害判定是一個有趣的問題,要先解決的是如何判定是否碰撞,在這段當中,我們將完成碰撞的檢測以及生命值的減少,搏鬥現在就開始了。
在遊戲開發中,對於碰撞的檢測有很多,3D一般用射線判定法(Vector),而2D遊戲就不需要那麼複雜,雖然使用向量能作出最準確的判定,但是在一個平面中有更加簡便的解決方案,當然,這取決於開發人員是否嚴格要求最準確的碰撞判定。
我簡單介紹兩種2D遊戲中最準確的判定方法:射線判定和色值判定
第一,射線判定來自於一個數學判斷一個點是否在任意一個封閉形狀內的方法:一個點向任意一個方向發出射線如果這條線經過線的數量是奇數,那麼這個點就在這個形狀內。
很顯然這種方法不但複雜還很麻煩,需要計算經過線的數量還要對很多個點進行判斷,我相信大多數人都不會對這個方法感興趣。
第二,色值判定,這個原理通過對比兩張映像的色值看看是否有重合點判斷是否碰撞,使用數組儲存所有的色值,然後進行“與”運算,如果這個數組中出現了“true”,那麼就可以判斷是有重合點,這個判定方法非常準確,但是準確的代價是效率的降低,當遊戲中有n個圖片對象,進行的對比判定將是一個n的幾何數字,進行如此之海量的判定,玩家的機器和不會買單。
上面介紹的是兩種最準確的方法,但是很顯然在實現上還是在效率上都不是我們所期望的解決方案,所以,偉大的遊戲開發人員先驅們在更加偉大的數學面前,找出了更為簡單及更為有效率的方案——圓形判定和矩形判定,具體請參看圖片。
圓形判定方法來自一個經典的數學導論,兩個圓的中心點的距離如果小於兩個圓的半徑之和,那麼它們兩個必然重合,具體做法也是很簡單,首先求出兩個點之間的向量,然後求出長度即可,這方面沒學好的朋友可以研究一下勾股定理,中國人早就明白如何取得弦的長度。
矩形判定更加容易,只需要對四個點進行逐次判斷,取得兩個矩形是否重合。
為什麼遊戲開發人員比較普遍用後面的兩種法,因為第一在遊戲中對於碰撞的檢測並非那麼非常嚴格,而是達到目的即可,第二遊戲中也不太可能設計非常複雜的奇怪形狀,第三使用圖形進行判斷(注意是圖形而不是映像)較為好控制,而且效率也高。
那麼,我們在這裡使用的方法就是矩形判斷法。
為了更加直觀,為每個可碰撞的角色加入一個Rectangle
Rectangle _rectangle = new Rectangle() { Width = 32, Height = 32, Stroke = new SolidColorBrush(Colors.Red) };
然後在主要邏輯裡進行Rect的判斷,看起來是一件很容易的事,但是難度可不小,往往在這裡容易“卡殼”,要知道這是兩個控制項之間的互動,飛行員和固體組,在這裡需要進行特定的技巧才可以達到應有的目的,兩個不同的類互相之間的互動應在主迴圈中完成邏輯運算。可是我們使用了兩個Timer分別來處理主角的移動和Solid移動,為了讓它們之間產生互動,需要將兩個迴圈合并到一起,因此,需要對ClassSolidGroup、ClassFlyer的Loop進行修改,使用MainPage的主迴圈去分別調用它們兩個的分迴圈。
public void TickGameFrameLoop(object sender, EventArgs e)
{
solidgroup.TickGameFrameLoop(sender, e);
Hero.TickGameFrameLoop(sender, e);
}
要為每個需要檢測的物體取得Rect
public Rect MyRect
{
get
{
return new Rect(X, Y, _rectangle.Width, _rectangle.Height);
}
}
利用下段代碼,完成碰撞檢測。
Rect herorect = Hero.MyRect;
foreach(ClassSolid solid in solidgroup.Children)
{
Rect rt = solid.MyRect;
rt.Intersect(herorect);
if (!double.IsInfinity(rt.Height) && !double.IsInfinity(rt.Width))
{
if (!Hero.isLose)
flyerlife.Lose(10);
Hero.Flyerstate = EmFlyerState.擊中;
}
}
上述代碼部分比較分散,要看還是直接看代碼吧。代碼在這裡