{"id":13730491,"url":"https://github.com/ashblue/fluid-state-machine","last_synced_at":"2025-04-10T21:22:04.009Z","repository":{"id":41791170,"uuid":"181066876","full_name":"ashblue/fluid-state-machine","owner":"ashblue","description":"A finite state machine micro-framework for Unity3D focused on a pure code implementation.","archived":false,"fork":false,"pushed_at":"2023-04-30T21:30:09.000Z","size":838,"stargazers_count":65,"open_issues_count":8,"forks_count":6,"subscribers_count":4,"default_branch":"develop","last_synced_at":"2025-03-24T18:52:25.446Z","etag":null,"topics":["finite-state-machine","fsm","unity-package-manager","unity3d","unity3d-plugin"],"latest_commit_sha":null,"homepage":"","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/ashblue.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2019-04-12T18:53:38.000Z","updated_at":"2025-02-19T17:38:16.000Z","dependencies_parsed_at":"2024-01-11T14:12:07.530Z","dependency_job_id":"a4dc142b-f294-43bc-b300-7dea5299b113","html_url":"https://github.com/ashblue/fluid-state-machine","commit_stats":{"total_commits":57,"total_committers":2,"mean_commits":28.5,"dds":0.01754385964912286,"last_synced_commit":"2e84357d9f8dfbb7c62edf0856e60137ea02de6b"},"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ashblue%2Ffluid-state-machine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ashblue%2Ffluid-state-machine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ashblue%2Ffluid-state-machine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ashblue%2Ffluid-state-machine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ashblue","download_url":"https://codeload.github.com/ashblue/fluid-state-machine/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247980817,"owners_count":21027803,"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":["finite-state-machine","fsm","unity-package-manager","unity3d","unity3d-plugin"],"created_at":"2024-08-03T02:01:15.578Z","updated_at":"2025-04-10T21:22:03.986Z","avatar_url":"https://github.com/ashblue.png","language":"C#","funding_links":[],"categories":["C#"],"sub_categories":[],"readme":"# Fluid State Machine [![Build Status](https://travis-ci.org/ashblue/fluid-state-machine.svg?branch=master)](https://travis-ci.org/ashblue/fluid-state-machine)\n\nFluid State Machine is a Unity plugin aimed at creating state machines in pure code. It allows state actions to be re-used and customized on a per-project basis.\n\n* Extendable, write your own re-usable state actions\n* Heavily tested with TDD\n* Open source and free\n\n## Support\n\nJoin the [Discord Community](https://discord.gg/8QHFfzn) if you have questions or need help.\n\nSee upcoming features and development progress on the [Trello Board](https://trello.com/b/4EXulH1t/fluid-state-machine).\n\n## Getting Started\n\nHere we have a door that demonstrates a simple open and close mechanism. By changing the `Open` variable, the state machine will automatically change the door's state.\n\n```c#\nusing UnityEngine;\nusing CleverCrow.Fluid.FSMs;\n\npublic class Door : MonoBehaviour {\n    private IFsm _door;\n    public bool Open { private get; set; }\n\n    public enum DoorState {\n        Opened,\n        Closed,\n    }\n\n    private void Start () {\n        _door = new FsmBuilder()\n            // Declares the FSMs associated GameObject\n            .Owner(gameObject)\n            \n            // What is the default starting state?\n            .Default(DoorState.Closed)\n            \n            // Creates a state called DoorState.Closed and assigns new actions to it\n            .State(DoorState.Closed, (close) =\u003e {\n                close.SetTransition(\"open\", DoorState.Opened)\n                    .Update((action) =\u003e {\n                        if (Open) action.Transition(\"open\");\n                    });\n            })\n            \n            .State(DoorState.Opened, (open) =\u003e {\n                open.SetTransition(\"close\", DoorState.Closed)\n                    .Update((action) =\u003e {\n                        if (!Open) action.Transition(\"close\");\n                    });\n            })\n            \n            .Build();\n    }\n\n    private void Update () {\n        // Update the state machine every frame\n        _door.Tick();\n    }\n}\n```\n\nIf you want to write you own custom state actions to bundle up complex chunks of code. You can easily do so with [C# extensions](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods). This allows you to adjust the functionality of Fluid State Machine on a per project basis or write your own custom extension library for it. All without forking the core library, which allows you to still get future version updates.\n\n```c#\nusing CleverCrow.Fluid.FSMs;\n\npublic class MyCustomAction : ActionBase {\n    protected override void OnUpdate () {\n        // Custom logic goes here\n    }\n}\n\npublic static class StateBuilderExtensions {\n    public static StateBuilder MyCustomAction (this StateBuilder builder) {\n        return builder.AddAction(new MyCustomAction());\n    }\n}\n\npublic class ExampleUsage {\n    private enum StateId {\n        A,\n    }\n\n    public void Init () {\n        var fsmBuilder = new FsmBuilder()\n            .State(StateId.A, (state) =\u003e {\n                state\n                    .MyCustomAction()\n                    .Update((action) =\u003e { });\n            })\n            .Build();\n    }\n}\n```\n\n### Installation\n\nFluid State Machine is used through [Unity's Package Manager](https://docs.unity3d.com/Manual/CustomPackages.html). In order to use it you'll need to add the following lines to your `Packages/manifest.json` file. After that you'll be able to visually control what specific version you're using from the package manager window in Unity. This has to be done so your Unity editor can connect to NPM's package registry.\n\n```json\n{\n  \"scopedRegistries\": [\n    {\n      \"name\": \"NPM\",\n      \"url\": \"https://registry.npmjs.org\",\n      \"scopes\": [\n        \"com.fluid\"\n      ]\n    }\n  ],\n  \"dependencies\": {\n    \"com.fluid.state-machine\": \"2.0.0\"\n  }\n}\n```\n\nArchives of specific versions and release notes are available on the [releases page](https://github.com/ashblue/fluid-state-machine/releases).\n\n### Examples\n\nAn [examples repo](https://github.com/ashblue/fluid-state-machine-examples) is available that demonstrates concepts found in this README.md file. Useful for seeing how these concepts might be used in an actual game.\n\n## Table of Contents\n\n* [Action Library](#action-library)\n  + [Defaults](#defaults)\n    - [Enter](#enter)\n    - [Exit](#exit)\n    - [Update](#update)\n    - [RunFsm](#runfsm)\n  + [Triggers](#triggers)\n    - [Enter](#enter-1)\n    - [Exit](#exit-1)\n    - [Stay](#stay)\n  + [Animators](#animators)\n    - [Set Animator Bool](#set-animator-bool)\n    - [Set Animator Float](#set-animator-float)\n    - [Set Animator Int](#set-animator-int)\n    - [Set Animator Trigger](#set-animator-trigger)\n* [Creating Custom Actions](#creating-custom-actions)\n* [Development](#development)\n\n## Action Library\n\nPre-made actions included in this library are as follows.\n\n### Defaults\n\nActions targeted at hooking the default state machine lifecycle.\n\n#### Enter\n\nTriggers whenever a state is initially entered.\n\n```c#\n.State(MyEnum.MyState, (state) =\u003e {\n    state.Enter((action) =\u003e Debug.Log(\"Code goes here\"));\n})\n```\n\n#### Exit\n\nTriggers whenever a state is exited.\n\n```c#\n.State(MyEnum.MyState, (state) =\u003e {\n    state.Exit((action) =\u003e Debug.Log(\"Code goes here\"));\n})\n```\n\n#### Update\n\nEvery frame a FSM's `Fsm.Tick()` method is called and the state is active this will run.\n\n```c#\n.State(MyEnum.MyState, (state) =\u003e {\n    state.Update((action) =\u003e Debug.Log(\"Code goes here\"));\n})\n```\n\n#### RunFsm\n\nUsed to run a nested FSM inside of a state. This action will continue running until the nested FSM triggers an Exit event through `Fsm.Exit()`. When exit is triggered the passed transition will automatically fire.\n\n```c#\nvar nestedFsm = new FsmBuilder()\n    .Default(OtherStateId.A)\n    .State(OtherStateId.A, (state) =\u003e {\n        state.Enter((action) =\u003e Debug.Log(\"Nested FSM triggered\"));\n        // This will notify the fsm that triggered nestedFsm to stop running it\n        state.FsmExit();\n    })\n    .Build();\n\nvar fsm = new FsmBuilder()\n    .Default(StateId.A)\n    .State(StateId.A, (state) =\u003e {\n        state.SetTransition(\"next\", StateId.B);\n        // First argument is the transition triggered when `nestedFsm.Exit()` is detected\n        state.RunFsm(\"next\", nestedFsm);\n    })\n    .State(StateId.B, (state) =\u003e {\n        state.Enter((action) =\u003e Debug.Log(\"Success\"));\n    })\n    .Build();\n```\n\n### Triggers\n\nHook's Unity's collider trigger system. Note that a collider component set to trigger must be included in order for this to work.\n\n#### Enter\n\nLogic fired when trigger is entered with a specific tag.\n\n```c#\n.State(MyEnum.MyState, (state) =\u003e {\n    state.TriggerEnter(\"Player\", (action) =\u003e Debug.Log(\"Code goes here\"));\n})\n```\n\n#### Exit\n\nLogic fired when trigger is exited with a specific tag.\n\n```c#\n.State(MyEnum.MyState, (state) =\u003e {\n    state.TriggerExit(\"Player\", (action) =\u003e Debug.Log(\"Code goes here\"));\n})\n```\n\n#### Stay\n\nLogic fired when Unity's stay trigger activates.\n\n```c#\n.State(MyEnum.MyState, (state) =\u003e {\n    state.TriggerStay(\"Player\", (action) =\u003e Debug.Log(\"Code goes here\"));\n})\n```\n\n### Animators\n\nTalks to the current Animator. Note that an Animator component must be included on the passed GameObject owner.\n\n#### Set Animator Bool\n\nSets an animator bool by string.\n\n```c#\n.State(MyEnum.MyState, (state) =\u003e {\n    state.SetAnimatorBool(\"myBool\", true);\n})\n```\n\n#### Set Animator Float\n\nSets an animator float by string.\n\n```c#\n.State(MyEnum.MyState, (state) =\u003e {\n    state.SetAnimatorFloat(\"myFloat\", 2.2);\n})\n```\n\n#### Set Animator Int\n\nSets an animator int by string.\n\n```c#\n.State(MyEnum.MyState, (state) =\u003e {\n    state.SetAnimatorInt(\"myInt\", 7);\n})\n```\n\n#### Set Animator Trigger\n\nSets an animator trigger by string.\n\n```c#\n.State(MyEnum.MyState, (state) =\u003e {\n    state.SetAnimatorTrigger(\"myInt\");\n})\n```\n\n## Creating Custom Actions\n\nHere we'll cover how to create a custom action and use it in a way that gets free updates from this library. It's important you create new actions this way to prevent new versions from causing errors.\n\n\nThe first thing you'll need to do is create a **custom action**.\n\n```c#\nusing UnityEngine;\nusing CleverCrow.Fluid.FSMs;\n\npublic class MyAction : ActionBase {\n    public MyAction (string newName) {\n        Name = newName;\n    }\n\n    // Triggers when entering the state\n    protected override void OnEnter () {\n        Debug.Log($\"Custom action {Name} activated\");\n    }\n    \n    // Triggers when exiting the state\n    protected override void OnExit () {\n    }\n    \n    // Runs every time `Fsm.Tick()` is called\n    protected override void OnUpdate () {\n    }\n}\n```\n\nAfter the custom action is complete you'll need to create a `StateBuilder` C# extension that adds it. Then you'll be able to call it as if it's a native method on the library.\n\n```c#\nusing CleverCrow.Fluid.FSMs;\n\npublic static class StateBuilderExtensions {\n    public static StateBuilder MyAction (this StateBuilder builder, string name) {\n        return builder.AddAction(new MyAction(name));\n    }\n}\n```\n\nThat's it! You're done. Try it out with this snippet.\n\n```c#\nusing UnityEngine;\nusing CleverCrow.Fluid.FSMs;\n\npublic class FsmBuilderCustomUsage : MonoBehaviour {\n    private enum StateId {\n        A,\n    }\n    \n    private void Awake () {\n        var fsmBuilder = new FsmBuilder()\n            .State(StateId.A, (state) =\u003e {\n                state\n                    .MyAction(\"custom name\")\n                    .Update((action) =\u003e { });\n            });\n        \n        var fsm = fsmBuilder.Build();\n        fsm.Tick();\n    }\n}\n```\n\n## Development\n\nIf you want to work on the code in this repo you'll need to install Node.js and Git. Then run the following command to setup Node.js from the repo's root.\n\n```bash\nnpm install\n```\n\n### Making Commits\n\nAll commits should be made using [Commitizen](https://github.com/commitizen/cz-cli) (which is automatically installed when running `npm install`). Commits are automatically compiled to version numbers on release so this is very important. PRs that don't have Commitizen based commits will be rejected.\n\nTo make a commit type the following into a terminal from the root.\n\n```bash\nnpm run commit\n```\n\n### Build testing\n\nBuilds can be manually run with the following command\n\n```bash\nnpm run build\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fashblue%2Ffluid-state-machine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fashblue%2Ffluid-state-machine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fashblue%2Ffluid-state-machine/lists"}