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.擊中; } }
上述代碼部分比較分散,要看還是直接看代碼吧。代碼在這裡
本文轉自nowpaper 51CTO部落格,原文連結:http://blog.51cto.com/nowpaper/712587