{"id":23496436,"url":"https://github.com/macawls/oceanfsm","last_synced_at":"2025-08-11T00:14:39.455Z","repository":{"id":65435513,"uuid":"589411981","full_name":"Macawls/OceanFSM","owner":"Macawls","description":"A Fully Featured State Machine for your Unity Projects!","archived":false,"fork":false,"pushed_at":"2024-06-14T14:37:31.000Z","size":826,"stargazers_count":22,"open_issues_count":1,"forks_count":2,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-04-15T13:54:46.958Z","etag":null,"topics":["finite-state-machine","fsm","package","state-machine","unity","unity3d","utilities"],"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/Macawls.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,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-01-16T03:24:31.000Z","updated_at":"2025-03-11T20:25:07.000Z","dependencies_parsed_at":"2024-06-14T15:46:26.521Z","dependency_job_id":"1acb4992-5072-44f1-9c83-285c130c9247","html_url":"https://github.com/Macawls/OceanFSM","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/Macawls/OceanFSM","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Macawls%2FOceanFSM","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Macawls%2FOceanFSM/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Macawls%2FOceanFSM/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Macawls%2FOceanFSM/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Macawls","download_url":"https://codeload.github.com/Macawls/OceanFSM/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Macawls%2FOceanFSM/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":269809789,"owners_count":24478615,"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","status":"online","status_checked_at":"2025-08-10T02:00:08.965Z","response_time":71,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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","package","state-machine","unity","unity3d","utilities"],"created_at":"2024-12-25T04:13:02.615Z","updated_at":"2025-08-11T00:14:39.429Z","avatar_url":"https://github.com/Macawls.png","language":"C#","readme":"\u003ch1 align=\"center\"\u003e Ocean Finite State Machine\u003c/h1\u003e\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://i.imgur.com/foM5qZO.png\" alt=\"apu\" /\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n  A code-only, simple and easy to use Finite State Machine for your Unity Projects!\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n\t\u003cimg alt=\"GitHub package.json version\" src =\"https://img.shields.io/github/package-json/v/Macawls/OceanFSM\" /\u003e\n\t\u003ca href=\"https://github.com/Macawls/OceanFSM/blob/main/LICENSE.md\"\u003e\n\t\t\u003cimg alt=\"GitHub license\" src =\"https://img.shields.io/github/license/Macawls/OceanFSM\" /\u003e\n\t\u003c/a\u003e\n\t\u003cimg alt=\"GitHub last commit\" src =\"https://img.shields.io/github/last-commit/Macawls/OceanFSM\"/\u003e\n    \u003ca href=\"https://openupm.com/packages/com.macawls.oceanfsm/\"\u003e\n    \u003cimg src=\"https://img.shields.io/npm/v/com.macawls.oceanfsm?label=openupm\u0026amp;registry_uri=https://package.openupm.com\"  alt=\"OpenUPM\"/\u003e\n\u003c/a\u003e\n\u003c/p\u003e\n\nhttps://user-images.githubusercontent.com/80009513/212888509-3f0e4358-f7f9-4acc-9f89-594ea925bd11.mp4\n\n# Getting Started\n\n## Installation\n### OpenUPM (Recommended)\n```bash\nopenupm add com.macawls.oceanfsm\n```\n### Git URL (Recommended)\n\n1. Open the package manager window\n2. Click the plus icon\n3. Choose ``\"Add package from git URL...\"``\n4. Use the link below.\n\n```\nhttps://github.com/Macawls/OceanFsm.git\n```\n\n### Manual (Not Recommended)\nAdd the following to your manifest.json.\n\n```json\n{\n  \"scopedRegistries\": [\n    {\n      \"name\": \"OpenUPM\",\n      \"url\": \"https://package.openupm.com\",\n      \"scopes\": [\n        \"com.macawls.oceanfsm\"\n      ]\n    }\n  ],\n  \"dependencies\": { \n    // Replace with latest version or version of your choice\n    \"com.macawls.oceanfsm\": \"{version}\" \n  }\n}\n```\n\n## Samples \nAfter adding the package, you can use the **import** button from the package manager window to inspect the samples.\n\nThe samples were created from the Default 3D Unity template.\n\n# How to Use\n\n## States\n\n### 1. Functionality\n\nTo add functionality to a state, you can override the following methods.\n\n```csharp\nvirtual void OnInitialize() { }  // called once\nvirtual void OnEnter() { } \nvirtual void OnExit() { } \nvirtual void OnUpdate(float deltaTime) { } // depends on how you decide to update the state machine\n```\n\n### 2. Creating a State\nAll states have to inherit from the ```State\u003cT\u003e``` class.\n\n#### Generic Usage\nThe generic reference type ```T``` is used to associate your states and state machines.\n\nYou can use whatever you want, but I recommend using an interface to keep things tidy.\nLets define ```IDoor``` as our reference type.\n\n```csharp\npublic interface IDoor\n{\n    void Close();\n    void Open();\n}\n```\n```csharp\npublic class Door : MonoBehaviour, IDoor \n{\n    private IPollingMachine\u003cIDoor\u003e _mFsm;\n    \n    // Instance of IDoor passed to constructor of the builder, because Door implements IDoor\n    _mFsm = new PollingBuilder\u003cIDoor\u003e(this) \n    ...\n }\n```\n\nHere, all the states will have access to instance which implements ```IDoor``` using the ```Runner``` property. Like so.\n\n```csharp\nclass Closed : State\u003cIDoor\u003e\n{\n    public override void OnEnter()\n    {\n\tRunner.Close();\n    }\n}\n```\n\nStates also have a ```Machine``` property. If the machine is not castable to ```IAutonomousStateMachine\u003cT\u003e```, it will be null.\n```csharp\nclass Closed : State\u003cIDoor\u003e\n{\n    public override void OnUpdate()\n    {\n        if (PlayerIsNearby() \u0026\u0026 Input.GetKeyDown(unlockKey))\n        {\n            Machine.ChangeState\u003cOpen\u003e(() =\u003e {\n                Debug.Log(\"Player has opened the door\");\n            });\n        }\n    }\n}\n```\n\n### 4. Inheritance Example\nFor a simple use case for inheritance, suppose we have a base class called PlayerStateBase where when we enter a new state, we'd like to play a specific animation.\nIt would look something like this.\n\n```csharp\n[Serializable]\npublic abstract class PlayerStateBase : State\u003cIPlayer\u003e\n{\n    [SerializeField] private AnimationClip stateAnimation;\n\n    public override void Enter()\n    {\n        Runner.PlayAnimation(stateAnimation);\n    }\n}\n```\n\n```csharp\n[Serializable]\npublic class Jump : PlayerStateBase\n{\n    // whatever fields you need\n    \n    public override void Enter()\n    {\n        base.Enter(); // play the animation\n        // other logic\n    }\n}\n```\n\n\n### 5. Utilities\nSince all states have to inherit from ```State\u003cT\u003e``` class, you can use the ```State Generator``` tool to generate a state boilerplate class for you. \n\nYou'll find it under the ```Tools``` dropdown menu.\n\n\u003cp align=\"center\"\u003e\n\t\u003cimg alt=\"State generation tool\" src =\"https://i.imgur.com/SVG6GjB.jpg\" /\u003e\n\u003c/p\u003e\n\n\n\n## State Machines\n\n### 1. State Machine Types\n\nThere are two types at the moment :)\n\n#### Autonomous State Machine\n- States are responsible for transitioning to other states.\n- The machine can receive commands to transition to a specific state.\n- Can freely transition to any state.\n\n#### Polling State Machine\n- The machine holds an internal dictionary of states and their transitions.\n- Transitions are triggered by a condition/predicate.\n- States cannot transition by themselves.\n\n### 2. Creating the State Machine\nThere are two builders to aid in creating state machines.\n#### Polling State Machine\n```csharp\nprivate IPollingMachine\u003cIDoor\u003e _mFsm;\n\nprivate void Awake()\n{\n    var closed = new Closed();\n    var open = new Open();\n\n    _mFsm = new PollingBuilder\u003cIDoor\u003e(this)\n        .SetStartingState(nameof(Closed))\n        .AddTransition(closed, open, () =\u003e {\n            return PlayerIsNearby \u0026\u0026 Input.GetKeyDown(KeyCode.Space) \u0026\u0026 !_mIsLocked)\n        })\n        .AddTransition(open, closed, () =\u003e {\n            return PlayerIsNearby() \u0026\u0026 Input.GetKeyDown(KeyCode.Space)\n        }, onTransition: () =\u003e {\n            Debug.Log(\"Closing the door\"); // optional\n        })\n        .Build();\n}\n```\n\n#### Autonomous State Machine\n```csharp\nprivate IAutonomousMachine\u003cIPlayer\u003e _mFsm;\n\nprivate void Awake()\n{\n    _mFsm = new AutonomousBuilder\u003cIDoor\u003e(this)\n        .SetStartingState(nameof(Idle))\n        .AddState(new Idle())\n        .AddState(new Walk())\n        .AddState(new Jump())\n        .Build();\n}\n```\n\n### 3. Command Usage (WIP)\nCurrently, only the ```AutonomousStateMachine``` supports commands.\nCommands are useful for triggering actions or responding to events from outside the state machine. Conditions and the actions are optional.\n\n```csharp\nprivate void Awake()\n{\n    _mFsm = new AutonomousBuilder\u003cIPlayer\u003e(this)\n        .SetInitialState(nameof(Idle)) \n        .AddStates(idle, run, jump)\n        .Build();\n    \n    _mFsm.AddCommand(\"Jump\")\n        .SetTargetState\u003cJump\u003e()\n        .SetCondition(() =\u003e _mFsm.CurrentState is Run \u0026\u0026 IsGrounded)\n        .OnSuccess(() =\u003e Debug.Log(\"Hi mom\")) // visual fx for example\n        .OnFailure(() =\u003e Debug.Log(\"depression\")); // negative sound effect for example\n}\n\nprivate void OnJump(InputAction.CallbackContext ctx)\n{\n    if (ctx.performed)\n    {\n        _mFsm.ExecuteCommand(\"Jump\");\n    }\n}\n```\n\n### 4. Running the State Machine\nIt is completely up to you how you want to run the state machine.\nThe key methods are:\n\n```csharp\nvoid Start();\nvoid Stop();\nvoid Update(float deltaTime);\nvoid Evaluate(); // only for Polling State machines\n```\n\nImportant to note that the state machine will not run until you call ```Start()```\n\nif you're using the ```Polling``` state machine, I would recommend calling ```Evaluate()``` in [Late Update](https://docs.unity3d.com/ScriptReference/MonoBehaviour.LateUpdate.html).\n\n```Evaluate()``` will continuously check all transitions of the current state. If a transition is met, it will change to the new state.\n\n#### Using Monobehaviour Hooks\n```csharp\nprivate void OnEnable()\n{\n    _mFsm.Start();\n}\n\nprivate void OnDisable()\n{\n    _mFsm.Stop();\n}\n\nprivate void Update()\n{\n    _mFsm.Update(Time.deltaTime);\n}\n\nprivate void LateUpdate()\n{\n    _mFsm.Evaluate();\n}\n```\n\n### 5. Which one should I use?\nI've found that if it's a simple entity with a few states and transitions, the ```Polling``` state machine is good.\nFor example a door, checkpoint, traffic light, treasure chest etc.\n\nIf it's an entity that is fairly complex and or reacts to external input , the ```Autonomous``` state machine is the way to go.\nSomething like a player, enemy, NPC, UI system etc.\n\nThe ```Autonomous``` one is easier to use and more flexible. Most of the time I recommend using it.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmacawls%2Foceanfsm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmacawls%2Foceanfsm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmacawls%2Foceanfsm/lists"}