Added how to make a Finite state machine
This commit is contained in:
parent
691fe3e36b
commit
69c42be7dd
41
.obsidian/workspace.json
vendored
41
.obsidian/workspace.json
vendored
@ -4,39 +4,20 @@
|
|||||||
"type": "split",
|
"type": "split",
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"id": "6b652dc38b9873a1",
|
"id": "9f8b5d21e348d59f",
|
||||||
"type": "tabs",
|
"type": "tabs",
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"id": "eca0df4907039a3d",
|
"id": "973dac369b06c184",
|
||||||
"type": "leaf",
|
"type": "leaf",
|
||||||
"state": {
|
"state": {
|
||||||
"type": "markdown",
|
"type": "empty",
|
||||||
"state": {
|
"state": {},
|
||||||
"file": "Tutorials/Enemy AI - Unity NavMesh (tutorial).md",
|
|
||||||
"mode": "source",
|
|
||||||
"source": false
|
|
||||||
},
|
|
||||||
"icon": "lucide-file",
|
"icon": "lucide-file",
|
||||||
"title": "Enemy AI - Unity NavMesh (tutorial)"
|
"title": "New tab"
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"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)"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"currentTab": 1
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"direction": "vertical"
|
"direction": "vertical"
|
||||||
@ -184,23 +165,23 @@
|
|||||||
"daily-notes:Open today's daily note": false,
|
"daily-notes:Open today's daily note": false,
|
||||||
"templates:Insert template": false,
|
"templates:Insert template": false,
|
||||||
"command-palette:Open command palette": false,
|
"command-palette:Open command palette": false,
|
||||||
"obsidian-git:Open Git source control": false,
|
"obsidian-git:Open Git source control": false
|
||||||
"copilot:Copilot Chat": false
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"active": "be6bc070960af330",
|
"active": "973dac369b06c184",
|
||||||
"lastOpenFiles": [
|
"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/UnityEngine.AI/Classes/NavMesh.md",
|
||||||
"Scripting/Classes/Physics/Raycast.md",
|
"Scripting/Classes/Physics/Raycast.md",
|
||||||
"Scripting/Classes/Physics",
|
"Scripting/Classes/Physics",
|
||||||
"Scripting/Classes",
|
"Scripting/Classes",
|
||||||
"copilot-conversations/Robot_can_you_search_the_web@20241023_164312.md",
|
"copilot-conversations/Robot_can_you_search_the_web@20241023_164312.md",
|
||||||
"copilot-conversations",
|
"copilot-conversations",
|
||||||
"Tutorials/Enemy AI - Unity NavMesh (tutorial).md",
|
|
||||||
"Scripting/UnityEngine.AI/Classes",
|
"Scripting/UnityEngine.AI/Classes",
|
||||||
"Scripting/UnityEngine.AI",
|
"Scripting/UnityEngine.AI",
|
||||||
"Scripting",
|
"Scripting",
|
||||||
"Tutorials/README.md",
|
|
||||||
"README.md",
|
"README.md",
|
||||||
"LICENSE",
|
"LICENSE",
|
||||||
"Unity-Notes/README.md",
|
"Unity-Notes/README.md",
|
||||||
|
@ -22,7 +22,7 @@ using UnityEngine.AI;
|
|||||||
|
|
||||||
public class EnemyMovement : MonoBehaviour
|
public class EnemyMovement : MonoBehaviour
|
||||||
{
|
{
|
||||||
public transform target;
|
public Transform target;
|
||||||
private NavMesh agent;
|
private NavMesh agent;
|
||||||
|
|
||||||
// Remember: Start runs **AT THE START OF THE GAME** and only once.
|
// Remember: Start runs **AT THE START OF THE GAME** and only once.
|
||||||
|
109
Tutorials/How to make a Finite State Machine (FSM).md
Normal file
109
Tutorials/How to make a Finite State Machine (FSM).md
Normal file
@ -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.
|
Loading…
Reference in New Issue
Block a user