C#開發WPF/Silverlight動畫及游戲系列教程(Game Course):(二十九) 人工智能(AI)之追蹤者
經過前面28節的不斷完善,主角已經具備了MMORPG游戲中的大多數功能;但是其他精靈例如怪物等暫時還是無法行動的,上一節中它們無辜的充當了主角的肉靶子,它們開始吶喊:上帝呀,請給予我們靈魂與智慧吧!其實靈魂早就有了,就是精靈的生命線程。那麼該如何賦予精靈智慧呢?
精靈智慧的實現其實就是為精靈賦予AI(人工智能)。完整的游戲引擎或多或少都必須擁有一定的AI,例如棋牌類型游戲有著它們獨特出牌AI,射擊類型游戲同樣也擁有相應的計算AI等等。AI的類型在不同類型游戲中有著不同的體現與定位,可深可淺,甚至無限擴充的可能。在MMORPG類型的游戲中則以“追蹤者”為最基礎的精靈用AI,同時也是游戲中使用率高達80%以上的AI類型。何謂“追蹤者”?簡單的說就是當怪物發現敵對玩家或是其他敵對精靈時即會鎖定目標並向其位置移動,一旦對方進入自己的攻擊范圍後即刻發起物理或魔法攻擊;同時,如果對方跑開,自己會繼續追擊且循環重復前面過程,就好比一個幽靈纏著你。這段描述大家是否有種四曾相似的感覺?沒錯,“追蹤者”AI其實就是上一節中主角戰斗功能模塊實現的最直接體現。下面我將為大家講解如何通過代碼實現怪物的“追蹤者”人工智能。
游戲AI設計同樣是對游戲引擎框架合理性的重要考驗,大家回想一下,主角與怪物均為QXSpirit類型控件,通過前面的章節我們已經實現了主角大多數的功能,如移動、攻擊、追擊、傷害等等;同樣的,我們是否可以將用於實現這些功能的方法為其他所有精靈通用?這是肯定的。比如障礙物預測使用的方法WillCollide(),直線移動方法StraightMoveTo(),尋路移動方法AstarMoveTo(),判斷移動到達目的地方法ArriveTarget()等等,這些方法在前面章節中均是無參數的,裡面的處理均以Leader為主元素進行相應的屬性設置及修改。此時我們不妨為這些方法均添加一個QXSpirit spirit參數,然後將方法裡的Leader全部改成spirit;如此,在除法AI後,所有的精靈對象就都可以重用這些方法了:
舉個例子,好比原先的ArriveTarget()方法寫法如下:
private bool ArriveTarget() {
return (storyboard != null && storyboard.GetCurrentProgress(Leader) == 1) ? true : false;
}
改成AI通用的則為:
private bool ArriveTarget(QXSpirit spirit) {
return (Super.storyboard.ContainsKey(spirit.Name) && SpiritStoryBoard(spirit.Name).GetCurrentProgress(spirit) == 1) ? true : false;
}
不光是多了個參數,同時大家是否有注意到我將storyboard定義成了一個字典以存放所有精靈的移動動畫板:
public static Dictionary<string, Storyboard> storyboard = new Dictionary<string, Storyboard>();
每個精靈在移動的時候會首先判斷以自身名字(spirit.Name)為鍵名的Storyboard鍵值是否存在,如果不存在則創建一個新的,接著在此Storyboard上執行移動屬性動畫,例如直線移動方法改為:
private void StraightMoveTo(QXSpirit spirit, Point p) {
……
if (!Super.storyboard.ContainsKey(spirit.Name)) { Super.storyboard.Add(spirit.Name, new Storyboard()); }
……
}
使用字典來管理所有精靈的移動動畫板即方便又高效,我們只需要通過Lambda即可以輕松獲取指定鍵名的Storyboard:
private Storyboard SpiritStoryBoard(string key) {
return Super.storyboard.Single(X => X.Key == key).Value;
}
同樣的也可以在每次移動時這樣創建新的Storyboard:
private void NewSpiritStoryboard(string key) {
if (!Super.storyboard.ContainsKey(key)) {
Super.storyboard.Add(key, new Storyboard());
}
}
額外的,我們也可以使用類似的方法在精靈停止跑動時或死亡時移除掉對應的Storyboard以釋放資源。
以創建精靈對象AI為目的的重構完成後,接下來需要進行具體功能的實現—如何啟動AI?
從原理上我們可以這樣設定:每個怪物精靈賦予一個索敵范圍(視線距離)SeekRange,當玩家進入這個區域後他就會將攻擊對象鎖定為玩家並向其發起攻擊;該索敵范圍同樣為以怪物精靈X、Y坐標為圓心,以視線距離為半徑的圓,判斷方法可以復用上一節中的InCircle():
大家在玩網游的時候是否注意到,玩家引怪容易,甩怪卻需要更長一些的時間與距離。難道我們還得多設定一個OutRange來定義擺脫怪物視線的距離?這裡其實有個小技巧,僅僅SeekRange一個參數就夠了。我們可以將怪物索敵方法放在游戲的輔助線程的異步方法中,這樣怪物每間隔1秒進行1次掃描,因此主角在與怪物距離小於SeekRange時即會引上怪,而只有當主角與怪物的距離大於SeekRange並持續1秒後才能甩掉怪物,這樣就間接的產生了兩個距離:索敵距離與擺脫距離:
private void RefreshFace(){
……
if (spirit.VLife != 0
&& Super.InCircle(Leader.X, Leader.Y, spirit.X, spirit.Y, spirit.SeekRange)
&& IsOpposition(spirit, Leader)) {
spirit.LockObject = Leader.Name;
} else {
spirit.LockObject = null;
}
……
}
當怪物視線范圍內發現主角時,鎖定它為攻擊目標;一旦視線范圍內無法找到主角且持續1秒以上則取消攻擊鎖定,此時怪物會停止追蹤原地站立。
至此就全部完成了。“追蹤者”AI的實現其實也不過如此,下面是三張運行測試圖:
怪物們已經具備了索敵與戰斗AI,盡管是簡單的智慧,但這在MMORPG中占據著80%AI份額呢,嘿嘿,小有成就吧?僅僅的砍殺或許太過單調了一些,華麗即將登場,下一節我將為大家展示一場魔法盛宴,敬請期待。
出處:http://alamiye010.cnblogs.com/