為了之後AI的彈性與好維護,加入狀態機管理機制是有必要的,但如何在LUA實作狀態機
呢?在此以一個隨機行走、攻擊的AI來介紹一下有狀態機的差別及相關實作:
沒有狀態機的情況:
math.randomseed(os.time())
gScrollMoveTime = 0.0
gResponseTime = 0.0
function Stroll(fDeltaTime)
if gResponseTime > 0.0 then
gResponseTime = gResponseTime-fDeltaTime
end
if gScrollMoveTime > 0.0 then
gScrollMoveTime = gScrollMoveTime-fDeltaTime
end
if gResponseTime <= 0.0 then
gResponseTime = 2.0
local iRandomValue = math.random(7)
if iRandomValue >= 7 then
Brain:ChangeBehavior("CMDJumpBehavior")
end
if iRandomValue >= 5 then
Brain:InsertAction("ATTACK")
end
if gScrollMoveTime <= 0.0 then
if iRandomValue <= 4 then
local fRandomValue = math.random()
gScrollMoveTime = fRandomValue*3.0
Brain:ReplaceYaw(fRandomValue*360.0)
Brain:ChangeBehavior("CMDMoveBehavior")
else
Brain:ChangeBehavior("CMDIdleBehavior")
end
end
end
end
由上得知,為了區分是不是要走或不走,會導致複雜的巢狀判斷式,就算走處理的部份移
到不同的函式中,仍然避免不了複雜的if、elase。
有狀態機的情況:
math.randomseed(os.time())
gScrollMoveTime = 0.0
gResponseTime = 0.0
function RandomAttackAndJump(iRandomValue)
if iRandomValue >= 7 then
Brain:ChangeBehavior("CMDJumpBehavior")
end
if iRandomValue >= 5 then
Brain:InsertAction("ATTACK")
end
end
function IsCanProcess(fDeltaTime)
local Result = 1
if gResponseTime > 0.0 then
gResponseTime = gResponseTime-fDeltaTime
end
if gResponseTime > 0.0 then
Result = 0
return 0
else
gResponseTime = 2.0
end
return 1
end
function MoveByTimeLength_Enter(FromStateName)
fRandomValue = math.random()
gScrollMoveTime = fRandomValue*3.0
Brain:ReplaceYaw(fRandomValue*360.0)
if FromStateName == "Stroll" then
Brain:ChangeBehavior("CMDMoveBehavior")
end
end
function MoveByTimeLength_Update(fDeltaTime)
if IsCanProcess(fDeltaTime) == 1 then
RandomAttackAndJump(math.random(7))
end
gScrollMoveTime = gScrollMoveTime-fDeltaTime
if gScrollMoveTime <= 0.0 then
Brain:ChangeState("Stroll")
end
end
function MoveByTimeLength_Exit()
Brain:ChangeBehavior("CMDIdleBehavior")
end
function Stroll_Enter(FromStateName)
end
function Stroll_Update(fDeltaTime)
if IsCanProcess(fDeltaTime) == 1 then
local iRandomValue = math.random(7)
RandomAttackAndJump(iRandomValue)
if iRandomValue <= 4 then
Brain:ChangeState("MoveByTimeLength")
end
end
end
function Stroll_Exit()
end
Script的進入點是Stroll_Enter。由上得知,狀態機可以讓我們專心做此狀態下該做的事,而
不用去判斷目前是什麼狀態或flag(上述的例子還好,但AI的狀態會越來越多,之後就很難維護
了)。另外值得一提的是此框架提供進入點和離開點,且在進入點會帶舊的狀態參數,以上例
而言,如果是是Stroll狀態進入的,才需要切換走路行為。為什麼要這麼做呢?原因是如果從其
他已經切換成走路行為的狀態進入,可能會多切一次走路行為而造成走路動作重新撥放而產生
動作抖動的問題。
此框架提供在Scirpt裡自訂任何的狀態,新狀態的產生及切換不用修改任何的native c++
source code,在此提供給大家參考。
夢癡大~
回覆刪除感謝分享
希望有幫助,xd.
回覆刪除夢癡大有想過使用QT4來取代MFC開發工具嗎@@?
回覆刪除最近在研究QT4@@!
目前沒這個打算,要的話也會轉向wxWidgets。
回覆刪除