關於FSM(有限狀態機)的學習2
阿新 • • 發佈:2019-02-06
以下內容參照《unity3d 人工智慧程式設計》--Aung Sithu Kyaw,Clifford Peters ,Thet Naing Swe編著</span>
最近在研究此書,花費幾天時間,略有收穫,所以寫下此編文章,計劃是3章,這是第一章,受個人能力限制,這個只是我的粗陋之見。
首先貼下此書原始碼下載地址,http://hzbook.com/Books/8580.html,請大家尊重智慧財產權,如果有需要自行購買(非廣告)。
本文主要講述的是有限狀態機的框架第二篇是人工智慧所要實現的行為,部分程式碼沒有註釋,但應該不影響閱讀
這個是繼承AdvanceFSM的子類,前文,已經說過了,這個是坦克人工智慧所實現的行為
using UnityEngine; using System.Collections; public class NPCTankController : AdvancedFSM { //子彈預製 public GameObject bullet; //生命值 private int health; /// <summary> /// 重寫初始化方法 /// </summary> protected override void Initialize() { health = 100; elapsedTime = 0.0f; shootRate = 2.0f; GameObject objPlayer = GameObject.FindGameObjectWithTag("Player"); playerTransform = objPlayer.transform; if (!playerTransform) { print("沒有新增Player標籤"); return; } //獲得子類的坦克炮塔以及炮塔下的旋轉點,由於每個人的設計不同,可以相應的改變 turret = gameObject.transform.GetChild(0).transform; bulletSpwanPoint = turret.GetChild(0).transform; //開始實現有限狀態機 ConstructFSM(); } protected override void FSMUpdate() { //更新計時器 elapsedTime += Time.deltaTime; } /// <summary> /// 有限狀態機 /// </summary> private void ConstructFSM() { //獲得巡邏點的 pointList = GameObject.FindGameObjectsWithTag("WandarPoint"); //給巡邏點賦值 Transform[] waypoints = new Transform[pointList.Length]; int i = 0; foreach (GameObject obj in pointList ) { waypoints[i] = obj.transform; i++; } //把對應的狀態的鍵和值加入字典 //巡邏 PatrolState patrol = new PatrolState(waypoints); //發現玩家,並追逐玩家 patrol.AddTransition(Transition.SawPlayer, FSMStateID.Chasing); //死亡 patrol.AddTransition(Transition.NoHealth, FSMStateID.Dead); //追逐 ChaseState chase = new ChaseState(waypoints); //丟失玩家,轉為巡邏 chase.AddTransition(Transition.LostPlayer, FSMStateID.Patrolling); //接近玩家並且能攻擊玩家 chase.AddTransition(Transition.ReachPlayer, FSMStateID.Attacking); //死亡 chase.AddTransition(Transition.NoHealth, FSMStateID.Dead); //進攻 AttackState attack = new AttackState(waypoints); //丟失玩家,轉為巡邏 attack.AddTransition(Transition.LostPlayer, FSMStateID.Patrolling); //發現玩家,並追逐玩家 attack.AddTransition(Transition.SawPlayer, FSMStateID.Chasing); //死亡 attack.AddTransition(Transition.NoHealth, FSMStateID.Dead); //死亡 DeadState dead = new DeadState(); dead.AddTransition(Transition.NoHealth, FSMStateID.Dead); //新增轉移和狀態 AddFSMState(patrol); AddFSMState(chase); AddFSMState(attack); AddFSMState(dead); } //碰撞檢測 void OnCollisionEnter(Collision collision) { if (collision.gameObject.tag == "Bullet") { health -= 30; if (health <= 0) { SetTransition(Transition.NoHealth); } } } /// <summary> /// 設定狀態轉移 /// </summary> /// <param name="t"></param> public void SetTransition(Transition t) { PerformTransition(t); } public void ShootBullet() { if (elapsedTime >= shootRate) { Instantiate(bullet, bulletSpwanPoint.position, bulletSpwanPoint.rotation); elapsedTime = 0.0f; } } }
巡邏狀態
using UnityEngine; using System.Collections; using System.Collections .Generic ; public class PatrolState : FSMState { public PatrolState (Transform [] wp) { wayPoints = wp; stateID = FSMStateID.Patrolling; curSpeed = 1.0f; curRotSpeed = 1.0f; } /// 該方法用於檢查當前狀態是否需要轉移到另外一個狀態 public override void Reason(Transform player, Transform npc) { //轉換狀態 if (Vector3.Distance(npc.position, player.position)<=300.0f) { npc.GetComponent<NPCTankController>().SetTransition(Transition.SawPlayer); } } /// 該方法為currentState變數執行實際的任務 public override void Act(Transform player, Transform npc) { //尋找下一個巡邏點 if (Vector3.Distance(npc.position, destinationPos) <= 100.0f) { FindNextPoint(); } //旋轉炮塔 Quaternion targetRotation = Quaternion.LookRotation(destinationPos - npc.position); npc.rotation = Quaternion.Slerp(npc.rotation, targetRotation, Time.deltaTime * curSpeed); //移動 npc.Translate(Vector3.forward * Time.deltaTime * curSpeed); } }
追逐狀態
using UnityEngine;
using System.Collections;
public class ChaseState : FSMState {
private Transform[] waypoints;
public ChaseState(Transform[] wp)
{
this.waypoints = wp;
stateID = FSMStateID.Chasing;
curRotSpeed = 1.0f;
curSpeed = 100.0f;
FindNextPoint();
}
public override void Reason(Transform player, Transform npc)
{
destinationPos = player.position;
float dist = Vector3.Distance(npc.position, destinationPos);
if (dist <= 200.0f)
{
npc.GetComponent<NPCTankController>().SetTransition(Transition.ReachPlayer);
}
else if (dist >= 300.0f)
{
npc.GetComponent<NPCTankController>().SetTransition(Transition.LostPlayer);
}
}
public override void Act(Transform player, Transform npc)
{
destinationPos = player.position;
Quaternion targetRotation = Quaternion.LookRotation(destinationPos - npc.position);
npc.rotation = Quaternion.Slerp(npc.rotation, targetRotation, Time.deltaTime * curRotSpeed);
npc.Translate(Vector3.forward * Time.deltaTime * curSpeed);
}
}
進攻狀態
using UnityEngine;
using System.Collections;
public class AttackState : FSMState {
//初始化相關屬性
public AttackState(Transform[] wp)
{
wayPoints = wp;
stateID = FSMStateID.Attacking;
curRotSpeed = 1.0f;
curSpeed = 100.0f;
FindNextPoint();
}
public override void Reason(Transform player, Transform npc)
{
float dist = Vector3.Distance(npc.position, player.position);
if (dist >= 200.0f && dist <= 300.0f)
{
Quaternion targetRotation = Quaternion.LookRotation(destinationPos - npc.position);
npc.rotation = Quaternion.Slerp(npc.rotation, targetRotation, Time.deltaTime * curRotSpeed);
npc.Translate(Vector3.forward * Time.deltaTime * curSpeed);
npc.GetComponent <NPCTankController >().SetTransition (Transition.SawPlayer );
}
else if (dist >= 300.0f)
{
npc.GetComponent<NPCTankController>().SetTransition(Transition.LostPlayer);
}
}
public override void Act(Transform player, Transform npc)
{
destinationPos = player.position;
Transform turret = npc.GetComponent<NPCTankController>().turret;
Quaternion turretRotation = Quaternion.LookRotation(destinationPos - turret.position);
turret.rotation = Quaternion.Slerp(turret.rotation, turretRotation, Time.deltaTime * curRotSpeed);
npc.GetComponent<NPCTankController>().ShootBullet();
}
}
using UnityEngine;
using System.Collections;
public class DeadState : FSMState {
public DeadState()
{
stateID = FSMStateID.Dead;
}
public override void Reason(Transform player, Transform npc)
{
}
public override void Act(Transform player, Transform npc)
{
//死亡狀態什麼都不做,如果有死亡動作,可以寫個方法播放
}
}
此篇結束,下一文是我就這次學習的總結