早在之前Animator剛在Unity上發表的時候
一直就覺得似乎可以用來做 Finite State Machine(FSM)
但真的去試了之後… 發現還是用來管管Animation就好 Orz…
現在!
Unity 5 新功能 - State Machine Behaivours
看起好像是真的可以用來做這件事!
看看手邊剛出爐的boss
就決定是你啦!
首先來確認一下boss的AI需求:
無目標時:發呆 > 亂走 (移動)
有目標時:決定招式 > 接近目標(移動) > 攻擊
在用Animator隨意拉一拉之後變成這樣 (BadArmor是部位破壞)
... Oh ... No... 看了我頭都暈了,連Trigger都不知道要怎麼下
於是在爬了一些文章之後… 變成這樣
嗯嗯,看起來簡單明瞭
這裡用了兩個Layer,一個管理Animation,一個管理AI

(加入新layer的時候別忘了weight預設是0,手動改成1)
下面是動作的Layer
主要是因為攻擊動作有四組,所以並沒有直接掛在AI的State上面,而是另外拉一個Layer出來
這裡可以看到Attack 1(鎚地),2(橫掃),4(砲擊)都是做完直接exit,而3(衝刺)比較特別,
3分成三個動作,s舉槍,m快跑,e停下,舉槍之後馬上進入快跑是ok的
但停下的剎車動作則是由程式觸發,所以做一個從Any State拉過來的處理。
等等… 現在在講AI。
所以重點是AILayer這裡
Unity 這次提供的StateMachineBehaviours有幾個Event可以用
下面是Idle State掛的Behaviours
float timer = 0;
float randomPosDis = 1;
public float timeMax = 3;
public float moveSpeed = o.5f;
override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex){
timer = 0;
//把MotionLayer切到Idle
animator.SetTrigger("MIdleStart");
}
override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex){
timer += Time.deltaTime;
if (timer >= timeMax)
{
//亂數一個方向後將目標位置設定給MoveState
Vector3 dir = new Vector3(Random.Range(-1.0f, 1.0f), Random.Range(-1.0f, 1.0f), 0).normalized;
Vector3 targetPos = dir * randomPosDis + animator.transform.position;
BossMoveState moveState = animator.GetBehaviour<BossMoveState>();
moveState.targetPos = targetPos;
moveState.moveSpeed = moveSpeed;
//將AILayer切到Move,讓Move這個State去做走到目標點的更新
animator.SetTrigger("AIMove");
}
}
另外幾個State也分別加入對應的Behaviours,都大同小異,
OnStateEnter做初始化,OnStateUpdate做該State的更新,符合條件就把自已切走
於是我們的Boss就動起來啦
心得:
方便在RunTime觀看現在的State,加State也不困難,不用寫FSM只需要專注在State
但有時會不知道為什麼State會沒有切換成功
估計是Transition做到一半又想要切走時會失敗(未找到確切原因)
而發生AI與動作不同步QQ
不同State之間資料交換不易
上面的例子是用GetBehaviour把MoveState拿出來設值
但這樣又變成跟MoveState相依
不知道有沒有更好的做法
