{"id":20718779,"url":"https://github.com/shamim-akhtar/fsm-generic","last_synced_at":"2025-04-23T14:14:22.855Z","repository":{"id":47044593,"uuid":"380639816","full_name":"shamim-akhtar/fsm-generic","owner":"shamim-akhtar","description":"This tutorial implements a generic Finite State Machine using C#. We then illustrate the concept by applying the implemented Finite State Machine using Unity in a few scenarios.","archived":false,"fork":false,"pushed_at":"2024-02-27T15:00:17.000Z","size":53,"stargazers_count":25,"open_issues_count":0,"forks_count":6,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-23T14:14:21.213Z","etag":null,"topics":["csharp","finite-state-machine","unity"],"latest_commit_sha":null,"homepage":"https://faramira.com/generic-finite-state-machine-using-csharp/","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/shamim-akhtar.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-06-27T03:09:03.000Z","updated_at":"2025-03-04T05:46:46.000Z","dependencies_parsed_at":"2022-09-10T19:41:55.412Z","dependency_job_id":"021d1380-99bf-4343-a9c4-f2da8dc80512","html_url":"https://github.com/shamim-akhtar/fsm-generic","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shamim-akhtar%2Ffsm-generic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shamim-akhtar%2Ffsm-generic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shamim-akhtar%2Ffsm-generic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shamim-akhtar%2Ffsm-generic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shamim-akhtar","download_url":"https://codeload.github.com/shamim-akhtar/fsm-generic/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250447979,"owners_count":21432165,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["csharp","finite-state-machine","unity"],"created_at":"2024-11-17T03:14:53.109Z","updated_at":"2025-04-23T14:14:22.805Z","avatar_url":"https://github.com/shamim-akhtar.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align='left'\u003e\n  \u003ca href=\"https://www.linkedin.com/in/shamim-akhtar/\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/linkedin-%230077B5.svg?\u0026flat-square\u0026logo=linkedin\u0026logoColor=white\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"mailto:shamim.akhtar@gmail.com\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Gmail-D14836?flat-square\u0026logo=gmail\u0026logoColor=white\" /\u003e        \n  \u003c/a\u003e\n  \u003ca href=\"https://www.facebook.com/faramiraSG/\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Facebook-1877F2?flat-square\u0026logo=facebook\u0026logoColor=white\" /\u003e        \n  \u003c/a\u003e\n\u003c/p\u003e\n\n# Generic Finite State Machine Using C#\n![](https://faramira.com/wp-content/uploads/2020/05/FSM-930x620.jpg)\n\nOur objective for this tutorial is to make our Finite State Machine generic by using a generic identifier for the state type.\n\nThere are several ways you can implement a finite state machine using C#. The easiest and fastest way probably is to use the enumerator type and the switch-case statement. However, in this tutorial, we are not going to do that. Instead, we will use a slightly sophisticated, more robust, generic class-based approach that will be reusable across multiple projects.\n\n\u003cp align='left'\u003e\n  \u003ca href=\"#\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Unity-2020.3.5f1-green\" /\u003e        \n  \u003c/a\u003e\n  \u003ca href=\"#\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/%20-C%23-blue\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\nAt the same time, we also want to extend the functionality of using delegates in the same framework.\nBut first, let’s recap on what is a Finite State Machine.\n\n![Turnstile Wikipedia](https://faramira.com/wp-content/uploads/2021/06/image-61.png)\n\n## Definition\nFinite State Machine (or FSM in short) is a **computational pattern** that defines and models state behaviour.\nAt any given time, a **Finite State Machine can exist in only one State out of a set of a possible number of states**. This State can change to another in response to some inputs (sometimes called events).\n\nThe process of switching from one State to another is called a **transition**.\n\n![](https://faramira.com/wp-content/uploads/2020/08/image-36.png)\n\n\n## The Classes\nFor organization purposes, we will put the generic reusable codes in the Patterns namespace. You can put them in any other namespace as well.\n\n### The State Class\nThe State class is the base class for a Finite State Machine state. This is a data structure (class) that encapsulates the state-related functionalities. We will implement this class in the section after FiniteStateMachine class implementation. For now, we just define the basic structure.\n\n```csharp\nnamespace Patterns\n{\n    public class State\u003cT\u003e\n    {\n        // The name for the state.\n        public string Name { get; set; }\n \n        // The ID of the state.\n        public T ID { get; private set; }        \n        public State(T id)\n        {\n            ID = id;\n        }\n        public State(T id, string name) : this(id)\n        {\n            Name = name;\n        }\n    }\n}\n```\nWe have added two constructors. One takes in the type T (unique ID) as a parameter, and the other takes in the type T (unique ID of the State) and a string value (name of the State) as parameters.\n\n### The Finite State Machine\n\nAs defined above, a Finite State Machine\n\n\u003e consists of a set of states, \n\u003e \n\u003e and at any given time, a Finite State Machine can exist in only one State out of these possible states. \n\nThus, we will need a variable to store the collection of states. This collection will represent a set of states. And then we will need a variable to keep the current state of the Finite State Machine.\n\n```csharp\n// A Finite State Machine\n//    - consists of a set of states,\n//    - and at any given time, an FSM can exist in only one \n//      State out of these possible set of states.\n \n// A dictionary to represent the set of states.\nprotected Dictionary\u003cT, State\u003cT\u003e\u003e mStates;\n \n// The current state.\nprotected State\u003cT\u003e mCurrentState;\n```\n\nTo construct the FiniteStateMachine class, we probably won’t need any arguments. At least, not for now. We will proceed with a default constructor.\n\n```csharp\npublic FiniteStateMachine()\n{\n    mStates = new Dictionary\u003cT, State\u003cT\u003e\u003e();\n}\n```\n\n#### Add State to the Finite State Machine\nIn the previous section, we created the variable that stores the set of states. Now we will create a method that will fill that set by adding state.  \n\n```csharp\npublic void Add(State\u003cT\u003e state)\n{\n    mStates.Add(state.ID, state);\n}\n \npublic void Add(T stateID, State\u003cT\u003e state)\n{\n    mStates.Add(stateID, state);\n}\n```\n\n#### Get State from the Finite State Machine\nA method that returns a State based on the key.\n\n```csharp\npublic State\u003cT\u003e GetState(T stateID)\n{\n    if(mStates.ContainsKey(stateID))\n        return mStates[stateID];\n    return null;\n}\n```\n\nNote that the method will return null if a State of the same key has not been added previously to the FSM. This method is a convenient function.\n\n#### Set the current State to the Finite State Machine\nNow perhaps the most critical function of the Finite State Machine, SetCurrentState. This method will set the current state of the Finite State Machine\n\nWhat happens when we set a state to the current State? There are two possible code paths to it. The first code path is when the previous-current State is valid, and the second code path is when the previous-current state is invalid (or null). \n\n```csharp\npublic void SetCurrentState(State\u003cT\u003e state)\n{\n    if (mCurrentState != null)\n    {\n    }\n \n    mCurrentState = state;\n}\n```\n\nThe above code implements the SetCurrentState method. If the previous-current State of Finite State Mchine is invalid, then the implementation directly sets the State to the mCurrentState. However, if the previous-current State was not null, then what happens?\n\nCan we still overwrite the previous-current state with the new current state?\n\nThe answer is probably not. We might want to implement specific functions whenever a state exits and a new state enters. How do we then implement this into our current code?\n\n##### Enter and Exit\nThe answer is simple. Create two virtual methods in the State class called Enter and Exit. The base State class implements nothing for both the Enter and Exit methods and instead relies on the application to create concrete implementations of the base State class. Then call these two methods whenever there is a change in the State.\n\n```csharp\npublic void SetCurrentState(State\u003cT\u003e state)\n{\n    if (mCurrentState == state)\n    {\n        return;\n    }\n \n    if (mCurrentState != null)\n    {\n        mCurrentState.Exit();\n    }\n \n    mCurrentState = state;\n \n    if (mCurrentState != null)\n    {\n        mCurrentState.Enter();\n    }\n}\n```\n\nWe will finally put the Unity context to the FSM and the State class by adding two methods called Update and FixedUpdate. These two methods we will call from Unity Monobehavior for every Update and FixedUpdate.\n\n```csharp\npublic void Update()\n{\n    if (mCurrentState != null)\n    {\n        mCurrentState.Update();\n    }\n}\n \npublic void FixedUpdate()\n{\n    if (mCurrentState != null)\n    {\n        mCurrentState.FixedUpdate();\n    }\n}\n```\n\nThis completes our implementation of a Finite State Machine in C#. We will now continue by completing the State class.\n\n### Completing the State Class\nWe have four key function calls. These are Enter, Exit, Update and FixedUpdate. We will keep these methods as virtual.\n\n```csharp\nvirtual public void Enter()\n{\n}\nvirtual public void Exit()\n{\n}\nvirtual public void Update()\n{\n}\nvirtual public void FixedUpdate()\n{\n}\n```\nFor convenience, we will add delegates to handle the key function calls such as Enter, Exit, Update and FixedUpdate.\n\n```csharp\npublic delegate void DelegateNoArg();\n \npublic DelegateNoArg OnEnter;\npublic DelegateNoArg OnExit;\npublic DelegateNoArg OnUpdate;\npublic DelegateNoArg OnFixedUpdate;\n```\n\nNow we amend the four key functions as below by calling the respective delegate is valid.\n\n```csharp\nvirtual public void Enter()\n{\n    OnEnter?.Invoke();\n}\n \nvirtual public void Exit()\n{\n    OnExit?.Invoke();\n}\nvirtual public void Update()\n{\n    OnUpdate?.Invoke();\n}\n \nvirtual public void FixedUpdate()\n{\n    OnFixedUpdate?.Invoke();\n}\n```\n\nFinally, we add two more constructors so that we can construct a State class with the given delegates as parameters.\n\n```csharp\npublic State(T id,\n    DelegateNoArg onEnter,\n    DelegateNoArg onExit = null,\n    DelegateNoArg onUpdate = null,\n    DelegateNoArg onFixedUpdate = null) : this(id)\n{\n    OnEnter = onEnter;\n    OnExit = onExit;\n    OnUpdate = onUpdate;\n    OnFixedUpdate = onFixedUpdate;\n}\npublic State(T id, \n    string name,\n    DelegateNoArg onEnter,\n    DelegateNoArg onExit = null,\n    DelegateNoArg onUpdate = null,\n    DelegateNoArg onFixedUpdate = null) : this(id, name)\n{\n    OnEnter = onEnter;\n    OnExit = onExit;\n    OnUpdate = onUpdate;\n    OnFixedUpdate = onFixedUpdate;\n}\n```\n\nWe have implemented a generic reusable Finite State Machine that we can reuse/override and apply based on what is required by our application domain down the stream. We can also use delegates to do the provide the necessary behaviour of a state without deriving a new State class.\n\n\nThis tutorial is an extension of my past tutorial on Implementing a Finite State Machine Using C# in Unity.\n\nTo read more about Finite State Machine please refer to my other series of tutorials on Finite State Machine.\n\n\u003e [Part 1: Implementing a Finite State Machine Using C# in Unity](https://faramira.com/implementing-a-finite-state-machine-using-c-in-unity-part-1/)\n\u003e \n\u003e [Part 2: Implement a Splash Screen Using a Finite State Machine in Unity](https://faramira.com/implement-a-splash-screen-using-a-finite-state-machine-in-unity/)\n\u003e \n\u003e [Part 3: Player Controls With Finite State Machine Using C# in Unity](https://faramira.com/implementing-player-controls-with-finite-state-machine-using-c-in-unity/)\n\u003e \n\u003e [Part 4: Finite State Machine Using C# Delegates in Unity](https://faramira.com/finite-state-machine-using-csharp-delegates-in-unity/)\n\u003e \n\u003e [Part 5: Enemy Behaviour With Finite State Machine Using C# Delegates in Unity](https://faramira.com/enemy-behaviour-with-finite-state-machine-using-csharp-delegates-in-unity/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshamim-akhtar%2Ffsm-generic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshamim-akhtar%2Ffsm-generic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshamim-akhtar%2Ffsm-generic/lists"}