1. 程式人生 > >Unity3d實現有限狀態機系統

Unity3d實現有限狀態機系統

在之前有過介紹一個視覺化有限狀態機編輯器外掛PlayerMaker

在這裡也可以在我們的程式碼中實現一個狀態機

首先建立一個指令碼,來管理我們的各個狀態

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;

/// <summary>
/// 狀態ID
/// </summary>
public enum FSMStateID
{
    NullFSMStateID,
    PatrolFSMStateID,//巡邏狀態
    ChaseFSMStateID,//追逐狀態
}


/// <summary>
/// 狀態轉化條件
/// </summary>
public enum FSMTransition
{
    SeePlayer,//看到主角(目標)
    LeavePlayer,//遠離敵人(目標)
}

public class FSMSystem
{
    private FSMStateID mCurrentStateID;
    private FSMBaseState mCurrentState;

    private Dictionary<FSMStateID, FSMBaseState> mFSMStateDic = new Dictionary<FSMStateID, FSMBaseState>();


    public void AddFSMSate(FSMBaseState state)
    {
        if (state == null)
        {
            Debug.Log("角色狀態為空,無法新增");
            return;
        }
        if (mCurrentState == null)
        {
            //第一個新增的狀態被作為系統首個執行的狀態
            mCurrentStateID = state.mStateID;
            mCurrentState = state;
            mCurrentState.StateStart();
        }
        if (mFSMStateDic.ContainsValue(state))
        {
            Debug.Log("容器記憶體在該狀態");
            return;
        }
        mFSMStateDic.Add(state.mStateID, state);
    }

    public void DeleteFSMSate(FSMBaseState state)
    {
        if (state == null)
        {
            Debug.Log("角色狀態為空,無法新增");
            return;
        }
        if (!mFSMStateDic.ContainsValue(state))
        {
            Debug.Log("容器內不存在該狀態");
            return;
        }
        mFSMStateDic.Remove(state.mStateID);
    }

    //更新(執行)系統
    public void UpdateSystem()
    {
        if (mCurrentState != null)
        {
            mCurrentState.StateUpdate();
            mCurrentState.TransitionReason();
        }
    }

    //轉換狀態
    public void TransitionFSMState(FSMTransition transition)
    {
        FSMStateID stateID = mCurrentState.GetStateIdByTransition(transition);
        if (stateID != FSMStateID.NullFSMStateID)
        {
            mCurrentStateID = stateID;
            mCurrentState.StateEnd();
            //換狀態
            mCurrentState = mFSMStateDic.FirstOrDefault(q => q.Key == stateID).Value;
            mCurrentState.StateStart();
        }
    }
}



各個狀態(巡邏狀態、追逐狀態)抽象理解為一個物件

建立一個狀態基類,各個狀態子類中可以繼承重寫這個基類方法

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;

public abstract class FSMBaseState
{
    public FSMStateID mStateID { get; set; }    //狀態ID
    public FSMSystem mFSMSystem { get; set; }   //該物件屬於在哪個狀態機

    public Dictionary<FSMTransition, FSMStateID> mFSMStateIdDic = new Dictionary<FSMTransition, FSMStateID>();

    public FSMBaseState(FSMSystem fsmSystem, FSMStateID stateID)
    {
        this.mFSMSystem = fsmSystem;
        this.mStateID = stateID;
    }

    public void AddTransition(FSMTransition transition, FSMStateID stateID)
    {
        if (mFSMStateIdDic.ContainsKey(transition))
        {
            Debug.Log("本狀態已經包含了該轉換條件");
            return;
        }
        mFSMStateIdDic.Add(transition, stateID);
    }

    public void DeleteTransition(FSMTransition transition)
    {
        if (!mFSMStateIdDic.ContainsKey(transition))
        {
            Debug.Log("容器中沒有該轉換條件");
            return;
        }
        mFSMStateIdDic.Remove(transition);
    }

    public FSMStateID GetStateIdByTransition(FSMTransition transition)
    {
        if (!mFSMStateIdDic.ContainsKey(transition))
        {
            Debug.Log("容器內沒有該轉換條件,無法獲取狀態");
            return FSMStateID.NullFSMStateID;
        }

        return mFSMStateIdDic.FirstOrDefault(q => q.Key == transition).Value;
    }

    public abstract void StateStart();
    public abstract void StateUpdate();
    public abstract void StateEnd();
    //轉化狀態條件
    public abstract void TransitionReason();
}


以下是巡邏狀態

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FSMPatrolState : FSMBaseState
{
    //路徑點
    private List<Transform> mStargetPointTransform = new List<Transform>();
    //路徑點索引
    private int mPointIndex = 0;
    //士兵
    private GameObject mSliderObj { get; set; }
    //主角
    private GameObject mPlayerObj { get; set; }
    //士兵移動速度
    private float mMoveSpeed = 4f;

    public FSMPatrolState(FSMSystem fsmSystem) : base(fsmSystem, FSMStateID.PatrolFSMStateID) { }

    public override void StateStart()
    {
        //獲取路徑點
        Transform[] transforms = GameObject.Find("Points").GetComponentsInChildren<Transform>();
        foreach (var m_transform in transforms)
        {
            if (m_transform != GameObject.Find("Points").transform)
            {
                mStargetPointTransform.Add(m_transform);
                Debug.Log(m_transform.position);
            }
        }

        //獲取士兵物件
        mSliderObj = GameObject.Find("Slider");
        //獲取主角物件
        mPlayerObj = GameObject.Find("Player");
    }

    public override void StateUpdate()
    {
        //確實目標點並移動  
        mSliderObj.transform.LookAt(this.mStargetPointTransform[this.mPointIndex].position);
        mSliderObj.transform.Translate(Vector3.forward * Time.deltaTime * mMoveSpeed);

        if (Vector3.Distance(mSliderObj.transform.position, this.mStargetPointTransform[this.mPointIndex].position) < 0.5f)
        {
            //切換目標點
            this.mPointIndex++;
            if (this.mPointIndex >= this.mStargetPointTransform.Count)
            {
                this.mPointIndex = 0;
            }    
        }
    }

    public override void StateEnd()
    {
        
    }

    public override void TransitionReason()
    {
        if (Vector3.Distance(mSliderObj.transform.position, mPlayerObj.transform.position) <= 2.0f)
        {
            //轉化狀態
            if (this.mFSMSystem == null)
            {
                Debug.Log("目標狀態機為空");
                return;
            }
            mFSMSystem.TransitionFSMState(FSMTransition.SeePlayer);
        }
    }
}


以下是追逐狀態

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FSMChaseState : FSMBaseState
{
    private GameObject mPlayerObj { get; set; }
    private GameObject mSliderObj { get; set; }
    private float mSliderMoveSpeed = 6.0f;

    public FSMChaseState(FSMSystem fsmSystem) : base(fsmSystem, FSMStateID.ChaseFSMStateID) { }

    public override void StateStart()
    {
        mPlayerObj = GameObject.Find("Player");
        mSliderObj = GameObject.Find("Slider");
    }

    public override void StateUpdate()
    {
        if (Vector3.Distance(mPlayerObj.transform.position, mSliderObj.transform.position) <= 10.0f)
        {
            //開始面向主角
            mSliderObj.transform.LookAt(mPlayerObj.transform.position);
            //開始追逐
            mSliderObj.transform.Translate(Vector3.forward * Time.deltaTime * mSliderMoveSpeed);
        }
    }

    public override void StateEnd()
    {
        
    }

    public override void TransitionReason()
    {
        //當主角遠離敵人
        if (Vector3.Distance(mPlayerObj.transform.position, mSliderObj.transform.position) > 10.0f)
        {
            //轉化狀態
            if (this.mFSMSystem == null)
            {
                Debug.Log("目標狀態機為空");
                return;
            }
            mFSMSystem.TransitionFSMState(FSMTransition.LeavePlayer);
        }
    }
}

該狀態機的優點在於當有不同型別的狀態時候,可以直接新增到狀態系統內,而不要需要狀態系統內部的執行邏輯
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Slider : MonoBehaviour
{
    private FSMSystem fsmSystem { get; set; }

	void Start ()
    {
        fsmSystem = new FSMSystem();

        //巡邏狀態,在構造引數傳一個系統引數,確定該狀態是在哪個狀態系統中管理的,狀態轉換的時候呼叫
        FSMBaseState patrolState = new FSMPatrolState(fsmSystem);
        patrolState.AddTransition(FSMTransition.SeePlayer, FSMStateID.ChaseFSMStateID);//巡邏狀態轉化條件

        //追逐狀態
        FSMBaseState chaseState = new FSMChaseState(fsmSystem);
        chaseState.AddTransition(FSMTransition.LeavePlayer, FSMStateID.PatrolFSMStateID);
        
        fsmSystem.AddFSMSate(patrolState);
        fsmSystem.AddFSMSate(chaseState);
	}
	
	void Update ()
    {
        fsmSystem.UpdateSystem();	
	}
}

相關推薦

Unity3d實現有限狀態系統

在之前有過介紹一個視覺化有限狀態機編輯器外掛PlayerMaker在這裡也可以在我們的程式碼中實現一個狀態機首先建立一個指令碼,來管理我們的各個狀態using System.Collections; using System.Collections.Generic; usin

C語言實現有限狀態FSM

FSM(finite state machine),它是一種協議,是一個數學概念,用於有限數量的子程式(狀態)的變化,每個子程式進行一些處理並選擇下一種狀態(通常取決於下一段輸入); 它可以用作程式的控制,對於那些基於輸入的在幾個不同的可選動作中進行迴圈的程式尤為合適。 C

基於有限狀態Unity3D實現的簡單搓招系統

在諸如街霸、拳皇等格鬥遊戲中,搓招指的是玩家通過在短時間內連續輸入特定的指令來釋放角色的招式(比如右下右拳釋放升龍拳) 那麼如何通過狀態機來實現搓招呢? 我們可以讓每個招式都持有一個狀態機,把這個招式要求的輸入指令作為狀態機的狀態而存在。依然以升龍拳為例,我們可以

基於委託與事件的有限狀態設計與實現(Unity3d)

有限狀態機設計與實現 前言 最近看到一句話,就是優秀是一種習慣,所以突然就總想寫點什麼,當作是遊戲開發這條路上的學習筆記吧,另外也時刻提醒自己需要不斷努力。 什麼是狀態機? 先貼百度百科的概念內容吧: 有限狀態機,(英語:Finite-state machine

Unity簡單有限狀態實現

【前言】 本篇來說一下關於簡單有限狀態機的演算法實現,當然我們的幾個狀態會比較簡單,而且本身我也是處於入門狀態,所以當成一個簡單的知識積累。有限狀態機,顧名思義,狀態是有限個的,而且狀態之間是關聯的,本篇寫的狀態機,其實是類似寫遊戲裡面的AI機器人,就是那些遊戲

Unity3d 有限狀態

using System.Collections; using System.Collections.Generic; using UnityEngine; //裝換條件 public enum Transition { NullTransition=0, SeePlayer, LostPlaye

學習筆記(三) 簡單的狀態模式&FSM有限狀態框架的實現(二)

之前釋出的那篇部落格可能說的並是不非常清楚,所以整理了一下,也參考了一些文件,於是又寫了一篇總結。 一、有限狀態機FSM的要點 1、擁有一組狀態,並且可以再這組狀態之間進行切換。 2、狀態機同時只能存在一個狀態,英雄不能能同時處於跳躍和站立。而防止這一點就是使用

【遊戲設計模式】之三 狀態模式、有限狀態 & Unity版本實現

毛星雲,網路ID「淺墨」,90後,熱愛遊戲開發、遊戲引擎、計算機圖形、實時渲染等技術,就職於騰訊互娛。 微軟最有價值專家 著作《Windows遊戲程式設計之從零開始》、《OpenCV3程式設計入門》 碩士就讀於南京航空航天大學航天學院(2013級碩士研究生),已於2016年三月畢業。本科

FSM有限狀態學習及Unity3D案例講解

引言:近日忙於畢業論文,今天看到漲了3個粉絲,不甚驚喜。遂今日更新FSM有限狀態機學習,希望大家共同進步! 開發版本:Unity 2017.1.1f1、VS 2017 適合人群:初學Unity者 一.有限狀態機定義 有限狀態機(英文:Finite State Mach

Unity 有限狀態(Finite State Machine)的理解 與 實現簡單的可插拔(Pluggable)AI指令碼物件。

#Unity 有限狀態機(Finite State Machine)的理解 與 實現簡單的可插拔AI指令碼物件。   一般的遊戲AI都是使用狀態機的設計模式來實現的。發現官方有教程,就跟了一遍,這裡就總結一下。   先簡單說一下狀態模式。就是根據當前狀態

Unity3D有限狀態(FSM)學習筆記【7】使用例項

using UnityEngine; using System.Collections; public class TestUIState : MonoBehaviour { public static EventSystem.Dispatcher Events = new EventSystem.Di

Unity3D有限狀態的使用

FSM(有限狀態機):多型 在各個小狀態類中因為是在保持動作的過程中執行的退出動作,所以將退出動畫的函式放在了保持動畫的函式中 在各個小狀態的類中判斷狀態是否在執行是根據動畫本身的播放屬性來判斷的,與其它的無關,是動畫自己的事情 簡而言之:在英雄類中的Upd

在Unity中實現FSM有限狀態

簡介 有限狀態機,(英語:Finite-state machine, FSM),又稱有限狀態自動機,簡稱狀態機,是表示有限個狀態以及在這些狀態之間的轉移和動作等行為的數學模型 -- 引用百度百科的解釋: 有限狀態機(FSM)是遊戲AI的一種常用模型,我做一個簡單的

Unity 內的敵人AI 或者 有限狀態FSM實現AI

孫廣東  2015.8.15一、Enemy Aim Ai           目的: 這篇文章的主要目的是為了讓您瞭解有關如何使用 Enemy Aim Ai 。你會得到結果:          Enemy aim AI是非常有用的,當你想要敵人一直監視player。適當爭取物

Unity3D有限狀態(FSM)學習筆記【3】FSState類

本系列筆記轉載自遊戲蠻牛專欄作家Jackel的論壇文章,詳細介紹了FSM的建立與使用,特與眾分享。連結:http://www.manew.com/thread-37136-1-1.html 該類主要是狀態的基本操作及事件的新增與觸發。程式碼如下: using System;

lua實現有限狀態

       在做的一個專案,由於人物的狀態較多,切換比較麻煩不便管理,所以打算引入狀態機,方便管理。下面是fsm的簡易版本,還有些待完善的地方。 local inspect = require "inspect" local FSMState = {} functi

確定有限狀態和非確定有限狀態詳解 包含Java實現原始碼(Nondeterministic finite automata)

本文將講解確定有限自動狀態機和非確定有限自動狀態機的特點和區別。將結合圖片例子重點講解什麼是非確定有限自動狀態機。最後講解如何將非確定狀態機轉換為確定的狀態機。多圖預警!! 有限自動狀態機可以分為確定的和不確定的。“確定性”將在下文詳講。“有限”性表示存在一個

有限狀態(FSM)的設計與實現(二)

轉自:http://www.cnblogs.com/chencheng/archive/2012/06/28/2564336.html 分層狀態機的設計: 對於狀態較多的狀態機,通常的設計會維護一個龐大的二維矩陣,所有狀態耦合在一起,這往往導致維護困難,由於可能存在許

獨立項目-角色控制器-有限狀態(FSM)

技術分享 OS pos .com com 過渡 動畫過渡 unity 狀態機   學習內容:     Unity5的新動畫系統       1.動畫導入 分動畫       2.創建動畫狀態機       3.設置動畫過渡 設置動畫跳轉條件       4.動畫重定向 獨立

go - FSM(有限狀態)初體驗

層次 time lba 當前 時機 警告 pen nil 自定義 FSM有限狀態機 /** * @Author: wsp * @Time : 2018/4/11 16:45 * @Description: */ package fsmStrudy import