本文參考自:html
在閱讀完本文後,請查看上述連接內容。git
本文使用的示例工程:FINCTIVE/lost-in-the-wilderness-nightmare(荒野迷蹤:噩夢)歡迎Star!github
因爲水平有限,文章內容可能有誤,歡迎探討、交流、或直接批評。
┗|`O′|┛設計模式
本文做者: FINCTIVE
聯繫郵箱: finctive@qq.comide
轉載請標明原文連接以及做者名字,謝謝。this
原文發佈於語雀:www.yuque.com/finctive/ga…spa
在荒野迷蹤:噩夢中,敵人的行爲以下圖(在線運行demo):
設計
看起來能夠用大大的 if{...}else if{...}else{...} 語句實現,但實際上手開發以後我發現……3d
切入正題:一個狀態指AI的一系列行爲,例如本項目中的靜止、追逐、自爆狀態,能夠使用一個類描述。對於一個狀態,應該把處理代碼寫在一個類中。好比,「追逐玩家」狀態相關的代碼,儘可能不要寫到其餘狀態的類裏面。code
敵人AI遊戲對象截圖
public abstract class BaseState : MonoBehaviour
{
// 執行本狀態的相關操做,返回值是下一次遊戲循環的狀態
public abstract BaseState Tick();
// 與本狀態有關的初始化代碼
public virtual void OnStateStart(){}
// 與本狀態有關的退出代碼
public virtual void OnStateExit(){}
}
複製代碼
狀態機
public class StateMachine : MonoBehaviour
{
public BaseState defaultState;
[HideInInspector]public BaseState currentState;
private void Awake() {
currentState = defaultState;
}
void FixedUpdate() {
BaseState nextStateType = currentState.Tick();
if (nextStateType != currentState)
{
nextStateType.OnStateStart();
currentState.OnStateExit();
}
currentState = nextStateType;
}
}
複製代碼
我把與全部狀態相關的控制腳本寫在了EnemyController組件中,暴露出公共方法讓狀態機腳本調用。這樣能夠複用代碼,而且讓狀態機的邏輯代碼只負責更高一層的控制,而無論細節如何。
如下是追逐狀態的代碼,其餘狀態同理。
public class EnemyChasingState : BaseState
{
public EnemyAttackingState enemyAttackingState;
public EnemyIdlingState enemyIdlingState;
private EnemyController _enemyController;
private void Awake() {
_enemyController = GetComponent<EnemyController>();
}
private static readonly int AnimMove = Animator.StringToHash("move");
public override BaseState Tick() {
Vector3 targetPos = PlayerController.playerTransform.position;
_enemyController.MoveToTarget(targetPos);
float distanceSqrMag = (targetPos - transform.position).sqrMagnitude;
// 距離足夠近,開始攻擊(自爆)
if(distanceSqrMag < _enemyController.enemyInfo.startAttackingDistance*_enemyController.enemyInfo.startAttackingDistance)
{
return enemyAttackingState;
}
// 距離太遠,放棄追逐
if(distanceSqrMag > _enemyController.enemyInfo.stopChasingDistance*_enemyController.enemyInfo.stopChasingDistance)
{
return enemyIdlingState;
}
return this;
}
public override void OnStateExit() {
_enemyController.modelAnimator.SetFloat(AnimMove, 0f);
}
}
複製代碼
做者:FINCTIVE(finctive@qq.com)歡迎轉載,請附上原文連接以及做者名字,謝謝!