From 69c42be7dd1a09cfb577738d343b7be751e3dcfe Mon Sep 17 00:00:00 2001 From: Chloe Date: Fri, 25 Oct 2024 07:58:48 -0400 Subject: [PATCH] Added how to make a Finite state machine --- .obsidian/workspace.json | 41 ++----- .../Enemy AI - Unity NavMesh (tutorial).md | 2 +- ...ow to make a Finite State Machine (FSM).md | 109 ++++++++++++++++++ 3 files changed, 121 insertions(+), 31 deletions(-) create mode 100644 Tutorials/How to make a Finite State Machine (FSM).md diff --git a/.obsidian/workspace.json b/.obsidian/workspace.json index 32df698..14df508 100644 --- a/.obsidian/workspace.json +++ b/.obsidian/workspace.json @@ -4,39 +4,20 @@ "type": "split", "children": [ { - "id": "6b652dc38b9873a1", + "id": "9f8b5d21e348d59f", "type": "tabs", "children": [ { - "id": "eca0df4907039a3d", + "id": "973dac369b06c184", "type": "leaf", "state": { - "type": "markdown", - "state": { - "file": "Tutorials/Enemy AI - Unity NavMesh (tutorial).md", - "mode": "source", - "source": false - }, + "type": "empty", + "state": {}, "icon": "lucide-file", - "title": "Enemy AI - Unity NavMesh (tutorial)" - } - }, - { - "id": "be6bc070960af330", - "type": "leaf", - "state": { - "type": "markdown", - "state": { - "file": "Tutorials/Enemy AI - Unity NavMesh (tutorial).md", - "mode": "source", - "source": false - }, - "icon": "lucide-file", - "title": "Enemy AI - Unity NavMesh (tutorial)" + "title": "New tab" } } - ], - "currentTab": 1 + ] } ], "direction": "vertical" @@ -184,23 +165,23 @@ "daily-notes:Open today's daily note": false, "templates:Insert template": false, "command-palette:Open command palette": false, - "obsidian-git:Open Git source control": false, - "copilot:Copilot Chat": false + "obsidian-git:Open Git source control": false } }, - "active": "be6bc070960af330", + "active": "973dac369b06c184", "lastOpenFiles": [ + "Tutorials/How to make a Finite State Machine (FSM).md", + "Tutorials/Enemy AI - Unity NavMesh (tutorial).md", + "Tutorials/README.md", "Scripting/UnityEngine.AI/Classes/NavMesh.md", "Scripting/Classes/Physics/Raycast.md", "Scripting/Classes/Physics", "Scripting/Classes", "copilot-conversations/Robot_can_you_search_the_web@20241023_164312.md", "copilot-conversations", - "Tutorials/Enemy AI - Unity NavMesh (tutorial).md", "Scripting/UnityEngine.AI/Classes", "Scripting/UnityEngine.AI", "Scripting", - "Tutorials/README.md", "README.md", "LICENSE", "Unity-Notes/README.md", diff --git a/Tutorials/Enemy AI - Unity NavMesh (tutorial).md b/Tutorials/Enemy AI - Unity NavMesh (tutorial).md index da5c06d..c958cc4 100644 --- a/Tutorials/Enemy AI - Unity NavMesh (tutorial).md +++ b/Tutorials/Enemy AI - Unity NavMesh (tutorial).md @@ -22,7 +22,7 @@ using UnityEngine.AI; public class EnemyMovement : MonoBehaviour { - public transform target; + public Transform target; private NavMesh agent; // Remember: Start runs **AT THE START OF THE GAME** and only once. diff --git a/Tutorials/How to make a Finite State Machine (FSM).md b/Tutorials/How to make a Finite State Machine (FSM).md new file mode 100644 index 0000000..d95aa32 --- /dev/null +++ b/Tutorials/How to make a Finite State Machine (FSM).md @@ -0,0 +1,109 @@ +This is a tutorial i didn't know I needed, so here we go: + +## Create the State Interface +When using state interfaces, it's essentially a "Manager" it holds sub classes within, and it helps you manage the states of your characters. + +Here is an example of a State Interface. When writing this code to your project, it should be outside of the main class, it will be it's own class. + +```csharp +public interface IState +{ + void Enter(); // Called when entering the state + void Exit(); // Called when exiting the state + void Update(); // Called every frame while in the state +} +``` +### What are we doing in this code sample +1. We are defining three methods that the class will essentially automatically run, assuming it implements the `IState` interface. +## Create the States +You can now create the "State" itself, In this case, our state will be "Idle" which means it will **not have any goals** it'll just be sitting there. + +```csharp +public class IdleState : IState +{ + public void Enter() + { + Debug.Log("Entering Idle State"); + } + + public void Exit() + { + Debug.Log("Exiting Idle State"); + } + + public void Update() + { + Debug.Log("Updating Idle State"); + } +} +``` + +### What does this code do? +This code is doing the same as the other code snippet, but it is defined for a specific state. **Each state must include three methods: `Enter()`, `Exit()`, `Update()`.** + +**Remember:** The code is not meant to go within your main class, in fact, **It could even be added to it's own script** if you so pleased. + +## The final result + +```csharp +using UnityEngine; + +public class EnemyAI : MonoBehaviour +{ + private StateMachine _stateMachine; + private IdleState _idleState; + private PatrolState _patrolState; + private ChaseState _chaseState; + + private void Start() + { + _stateMachine = new StateMachine(); + + // Initialize the states + _idleState = new IdleState(); + _patrolState = new PatrolState(); + _chaseState = new ChaseState(); + + // Start with the Idle state + _stateMachine.ChangeState(_idleState); + } + + private void Update() + { + // Call the State Machine's Update method + _stateMachine.Update(); + + // Example of switching between states for demonstration purposes + if (Input.GetKeyDown(KeyCode.I)) + { + _stateMachine.ChangeState(_idleState); + } + else if (Input.GetKeyDown(KeyCode.P)) + { + _stateMachine.ChangeState(_patrolState); + } + else if (Input.GetKeyDown(KeyCode.C)) + { + _stateMachine.ChangeState(_chaseState); + } + } +} +``` + +### What does this code do? +The code does the following: +1. Defines a StateMachine as `_stateMachine;` which will be handling our state transitions. +2. Defines an IdleState, PatrolState, and ChaseState as `_idleState;`, `_patrolState;`, `_chaseState;` respectively, which are our classes, remember? +3. In the start method, it + 1. Creates a new `StateMachine();` on `_stateMachine` + 2. Creates new individual states (I like to say this is essentially "Making the state available" to the StateMachine.) + 3. Then changes the state to idle +4. In the update method, it + 1. Runs the "Update" method on the state machine (Which means it will run the state functionality) + 2. Based on the keyboard input, **it switches the state for testing purposes.** You are free to change this. + +## Attach it to a GameObject +Now that the script is done, you can add your script to your enemy game object. **Make sure it has a Nav Mesh Agent!** + +## That's it! +Thanks for reading! Forgive me if I am wrong about some details, this is a learning exercise for me too. \ No newline at end of file