目次
1. 有限状態マシンとは何ですか
有限ステート マシンは、オブジェクトのさまざまな状態を相互に変換する方法を記述するために使用されるモデルです。ここでの最も単純な例は、アニメーション ステート マシン アニメーターです。一度に 1 つの状態しか存在できず、各状態は相互作用できます。特定の条件を介して相互に変換します。
2. 達成方法
1. 原理を簡単に説明します
今回はScriptableObjectを使用します. 実装の考え方は、ある状態から別の状態に遷移することですが、最初に考えられるのは、状態と条件を別々に宣言してから、その 2 つを関連付けるということです。
2. 実現
①準備:まず以下のフォルダを作成します。
②具体的な実装:ベース配下に以下の4つのスクリプトを作成
using UnityEngine;
public abstract class ContionOS : ScriptableObject
{
/// <summary>
/// 判断条件是否成立
/// </summary>
/// <returns>bool</returns>
public abstract bool SetUP();
}
using UnityEngine;
public class stateMachine : MonoBehaviour
{
public StateOS currentstate;
public trasitionOS trasitionos;
private void Awake()
{
trasitionos.Init(this);
}
private void Update()
{
currentstate?.OnUpdate();
trasitionos.TryGetEnableCondition();//每一帧都查看是否成立
}
}
using UnityEngine;
public abstract class StateOS : ScriptableObject
{
public virtual void OnEnter() { }// 新状态进入 虚方法 子类可实现可不实现
public abstract void OnUpdate(); // 状态更新 抽象方法子类必须实现该方法 不然会报错
public virtual void OnExit() { } // 状态退出
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
[CreateAssetMenu(fileName ="tranlsationos",menuName ="statemachine/create/tranlasition")]
public class trasitionOS : ScriptableObject
{
//一个状态转变为其他状态可以有很多个条件 stateOS 状态 ContionOS 条件
private Dictionary<StateOS, List<ContionOS>> _transition = new Dictionary<StateOS, List<ContionOS>>();
// 转换列表:用来存储状态和条件的装欢关系
[SerializeField] private List<translationState> currentState = new List<translationState>();
//状态机 控制状态的更新
private stateMachine statemachine;
public void Init(stateMachine statemachine)
{
this.statemachine = statemachine;
AddTransition();
}
// 当前 状态的条件是否成立
public void TryGetEnableCondition()
{
if (_transition.ContainsKey(statemachine.currentstate))
{
foreach (var item in _transition[statemachine.currentstate])
{
if (item.SetUP())
{
translatinon(item);
}
}
}
}
/// <summary>
/// 切换状态
/// </summary>
/// <param name="condition">当前状态的条件</param>
public void translatinon(ContionOS condition)
{
statemachine.currentstate?.OnExit();
statemachine.currentstate = GetNextstate(condition);
statemachine.currentstate?.OnEnter();
}
public StateOS GetNextstate(ContionOS condition)
{
foreach (var item in currentState)
{
if (item.condition == condition && statemachine.currentstate == item.fromState)
{
return item.toState;
}
}
return null;
}
/// <summary>
/// 将状态和条件加入到装欢列表
/// </summary>
public void AddTransition()
{
if (currentState.Count != 0)
{
foreach (var item in currentState)
{
if (!_transition.ContainsKey(item.fromState))
{
_transition.Add(item.fromState, new List<ContionOS>());
_transition[item.fromState].Add(item.condition);
Debug.Log("创建并添加");
}
else
{
if (_transition[item.fromState].Contains(item.condition))
{
_transition[item.fromState].Add(item.condition);
Debug.Log("存在并再次添加条件");
}
}
}
}
}
[Serializable]
private class translationState
{
public StateOS fromState;
public StateOS toState;
public ContionOS condition;
private translationState(StateOS fromState, StateOS toState, ContionOS condition)
{
this.fromState = fromState;
this.toState = toState;
this.condition = condition;
}
}
}
③テスト: stateMachine スクリプトをオブジェクトにハングし、次のスクリプトを作成し、そのスクリプトに基づいて ScriptableObject を作成します
例と翻訳例
[CreateAssetMenu(fileName = "condition_idel", menuName = "statemachine/create/Condition/condition_idel")]
public class condition_idel: ContionOS
{
public override bool SetUP()
{
return true;
}
}
[CreateAssetMenu(fileName = "condition_walk", menuName = "statemachine/create/Condition/condition_walk")]
public class condition_walk : ContionOS
{
public override bool SetUP()
{
return Input.GetKeyDown(KeyCode.W);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "idel", menuName = "statemachine/create/stateos/idel")]
public class idel : StateOS
{
public override void OnUpdate()
{
Debug.Log("正处于idel");
}
public override void OnEnter()
{
Debug.Log("进入idel");
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "walk", menuName = "statemachine/create/stateos/walk")]
public class walk : StateOS
{
public override void OnUpdate()
{
Debug.Log("正处于walk");
}
public override void OnEnter()
{
Debug.Log("进入walk");
}
}
パスに従って対応するインスタンスを作成し、作成したインスタンスに対して次の操作を実行します。
これは単なる基本的な fsm であり、拡張することができます。