創建一個魔獸RPG的AI系統
--------------------------------------------------------------------------------
如果英雄的狀態良好,檢測他是否處在一個普通命令中(防止它打斷了通魔技能).如果是一個標準命令,我們再檢測在500的半徑內是否有敵人存在.如果存在敵人,簡單的發出一個攻擊命令(不要改變"e"的值,5秒對於這個情況剛剛好).
function AIFilterEnemyConditions takes nothing returns boolean
return GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) > 0 and IsPlayerEnemy(GetOwningPlayer(GetFilterUnit()), GetOwningPlayer(GetAttachedUnit(GetExpiredTimer(), "hero")))
endfunction
…
else
if ((o == "smart") or (o == "attack") or (o == "patrol") or (o == "move") or (o == "stop") or (o == "hold") or (o == null)) then
set g = CreateGroup()
set b = Condition(function AIFilterEnemyConditions)
call GroupEnumUnitsInRange(g, x, y, 500, b)
set f = FirstOfGroup(g)
if f == null then
…
else
call IssueTargetOrder(h, "attack", f)
endif
call DestroyGroup(g)
call DestroyBoolExpr(b)
endif
…
--------------------------------------------------------------------------------
如果沒有敵人存在,再檢測物品.如果發現物品,再檢測是否為一個提升狀態的物品.如果不是,檢測英雄物品欄是否有空欄,有的話就命令英雄將它揀起來.
function AISetItem takes nothing returns nothing
set bj_lastRemovedItem=GetEnumItem()
endfunction
function AIItemFilter takes nothing returns boolean
return IsItemVisible(GetFilterItem()) and GetWidgetLife(GetFilterItem()) > 0
endfunction
function AIHasEmptyInventorySlot takes unit u returns boolean
return UnitItemInSlot(u, 0) == null or UnitItemInSlot(u, 1) == null or UnitItemInSlot(u, 2) == null or UnitItemInSlot(u, 3) == null or UnitItemInSlot(u, 4) == null or UnitItemInSlot(u, 5) == null
endfunction
…
if f == null then
set i = Rect(x-800, y-800, x+800, y+800)
set be = Condition(function AIItemFilter)
set bj_lastRemovedItem=null
call EnumItemsInRect(i, be, function AISetItem)
if bj_lastRemovedItem != null and (GetItemType(bj_lastRemovedItem) == ITEM_TYPE_POWERUP or AIHasEmptyInventorySlot(h)) then
call IssueTargetOrder(h, "smart", bj_lastRemovedItem)
else
…
endif
call RemoveRect(i)
call DestroyBoolExpr(be)
…
--------------------------------------------------------------------------------
如果物品欄沒有空位,或者沒有發現物品,則命令英雄到一個隨機地點尋找新的目標.
…
else
set r = GetRandomLocInRect(bj_mapInitialPlayableArea)
call IssuePointOrderLoc(h, "patrol", r)
call RemoveLocation(r)
…
--------------------------------------------------------------------------------
現在我們需要檢測的是英雄是否有未使用的技能點(將這個函數與進攻/揀取物品/前進到隨機地點等模組分開). 如果英雄有未使用的技能點,調用函數來使英雄學習技能.在我的演示地圖中,我是用一個函數來保存將要讓英雄學習的技能的,使用的是下面這個模式:
function AILearnSkill takes unit h, string a returns nothing
local integer i = GetTableInt(a, "LearnSkillOrder")+1
if i == 1 or i == 4 or i == 8 then
call SelectHeroSkill(h, GetStoredInteger(udg_GameCache, UnitId2String(GetUnitTypeId(h)), "BaseSkill1"))
elseif i == 2 or i == 5 or i == 9 then
call SelectHeroSkill(h, GetStoredInteger(udg_GameCache, UnitId2String(GetUnitTypeId(h)), "BaseSkill2"))
elseif i == 3 or i == 7 or i == 10 then
call SelectHeroSkill(h, GetStoredInteger(udg_GameCache, UnitId2String(GetUnitTypeId(h)), "BaseSkill3"))
elseif i == 6 then
call SelectHeroSkill(h, GetStoredInteger(udg_GameCache, UnitId2String(GetUnitTypeId(h)), "UltimateSkill"))
endif
call SetTableInt(a, "LearnSkillOrder", i)
endfunction
…
if GetHeroSkillPoints(h) > 0 and l > 0 then
call AILearnSkill(h, a)
endif
…
--------------------------------------------------------------------------------
現在所需要做的是使計時器在"e"秒之後再次開啟:
…
call TimerStart(GetExpiredTimer(), e, true, function AILoop)
…
--------------------------------------------------------------------------------
最後我們將區域變數設置為空:
…
set h = null
set i = null
set r = null
set g = null
set b = null
set f = null
set be = null
…
--------------------------------------------------------------------------------
最後需要注意的事情
這些就是英雄AI系統的基礎,它並不完美,但是它可以做為你的起點. 這個系統一點都不複雜,但是我希望你能對照我的演示地圖看,這樣可以讓你更加徹底的明白我的意思. 當你完成了一個屬於你自己的AI系統時,嘗試一下在你的系統中加入一個或者多個以下特徵:
■嘗試使它可以尋找周圍最虛弱的敵人.
■嘗試在殺死特殊的敵人時讓不同的AI玩家合作.
■當大部分戰鬥都以生命泉為中心的時候,讓英雄離開生命泉.
■讓AI玩家根據情況的不同說出不同的話(比如在殺死你的時候AI玩家會說"死吧~可憐的孩子")
我希望這篇文章可以使你們有所收穫.
|