分割統治法-UnityでFSMを使用する

有能なアーキテクチャは、あらゆるソフトウェア製品の開発において重要な役割を果たします。最も一般的なパフォーマンス、拡張性、または理解可能性の問題は、その欠如に根ざしています。厳密に定義されたプロジェクト構造がないため、開発者は抽象的に考え、同僚が書いたコードを一目で理解し、エラーが発生する場所を予測することができません。また、場合によっては、エンティティやコンポーネントで飽和状態になっている自分のコードでも混乱する可能性があります。しかし、ほとんどすべてのプログラマーは、遅かれ早かれ、自分自身であろうと巧妙な本の助けを借りようと、状況に関係なく優れたソリューションに精通します。彼らは非常に効果的で用途が広いので、多くの問題を解決する場所を見つけます、そして...はい、私は知っています、あなたは続けることができません、誰もが私が話していたことをすでに理解していましたデザインパターン。彼らのために祈る人もいれば、自転車を見つけた人もいます。インタビューの中で、彼らはそれらを内外で研究し、完全に役に立たなくなったと主張する人もいます。しかし、誰もが、何らかの形で、それらについて聞いた。今日は、パターンの1つである「状態」について説明します。より正確には、有限状態マシンについて上記の最後のグループに属している場合でも、おそらく次のツールに出くわしたことがあります。





プラットフォーマーの最小限の主人公アニメーター
プラットフォーマーの最小限の主人公アニメーター

Unityのアニメーターはステートマシン上に構築されています。オブジェクトのグループの各アニメーションは、状態として表されます。それらの間の条件と遷移の順序は、ステートマシンであるアニメーターで決定されます。また、有限状態マシンを使用して、複雑な動作をするオブジェクトの作業のロジックを記述するというトピックが繰り返し提起されています。 AIボット、主人公のコントロール、それだけです。





. . , - , . , , , . , . , - :





  • . , , . , Play . - , . , isPaused, , .





  • , . , , , .





  • , , . , , , , , AI.





  • , . Play, WaitMatch "match_ready", , , "room_left" .





  • . , , , . , , "" .





. , . . . . , .





- . , . , .





, . :





FSM





AState





- public FSM(AState initState)





- public void Signal(string name, object data = null)





- private void ChangeState(AState newState)





- void Enter()





- void Exit()





- AState Signal()





, 2 :





. . , , . , . Exit



Enter



. , :





 public class FSM
 {
   private AState currentState;

   public FSM(AState initState) => ChangeState(initState);
   
   private void ChangeState(AState newState)
   {
     if (newState == null) return;
     currentState?.Exit();
     currentState = newState;
     currentState.Enter();
   }

   public void Signal(string name, object arg = null)
   {
     var result = currentState.Signal(name, arg);
     ChangeState(result);
   }
 }
      
      



. , , .





public class AState
{
  public virtual void Enter() => null;
  public virtual void Exit() => null;
  public virtual AState Signal(string name, object arg) => null;
}
      
      







public class SLoad : AState
{
    public override void Enter()
    {
        Game.Data.Set("loader_visible",true);
        var load = SceneManager.LoadSceneAsync("SceneGameplay");
        load.completed+=a=>Game.Fsm.Signal("scene_loaded");
    }

    public override void Exit()
    {
        Game.Data.Set("loader_visible",false);
    }
    
    public override AState Signal(string name, object arg)
    {
        if (name == "scene_loaded")
            return new SLobby();
        return null;
    }
    
}
      
      



, , . , , . 3 , . - , - . ! , , . , , ,





public class SMessage : AState
{
    private string msgText;
    private AState next;
    public SMessage(string messageText, AState nextState)
    {
        msgText = messageText;
        btnText = buttonText;
        next = nextState;
    }
    
    public override void Enter()
    {
        Game.Data.Set("message_text", msgText);
        Game.Data.Set("window_message_visible",true);
    }

    public override void Exit()
    {
        Game.Data.Set("window_message_visible",false);
    }
    
    public override AState Signal(string name, object arg)
    {
        if (name == "message_btn_ok") 
            return next;
        return null;
    }
}
      
      



, c , .





...
case "iap_ok":
	return new SMessage("Item purchased! Going back to store.", new SStore());
...
      
      



Game.Data



, , , , "". , , UI, . , . , .





public class ButtonFSM : MonoBehaviour, IPointerClickHandler
{
    public string key;
    
    public override void OnPointerClick(PointerEventData eventData)
    {
        Game.Fsm.Signal(key);
    }
}
      
      



つまり、ボタンをクリックすると(実際には、CanvasRendererに)、対応するシグナルがマシンに送信されます。状態間を移行するとき、私たちは、私たちのために便利な任意の方法で別のキャンバスにオンオフに使用されるマスクを変更することができますPhysics.Raycast



し、時にはTime.timeScaleを変更します!一見、どんなにひどくて文明化されていないように見えても、で行われていることEnter



がキャンセルされている限り、Exit



不便を引き起こさないことが保証されていますので、どうぞ!主なことはそれをやり過ぎないことです。








All Articles