|
1 | 1 | --- |
2 | | -tags: animation, state_machine, input |
3 | | -title: Animation State Machine |
4 | | -brief: This example demonstrates how to create a character animation system using a Finite State Machine (FSM) with smooth transitions between different character states. |
| 2 | +title: Finite State Machines |
| 3 | +brief: Shows how to build a small Finite State Machine module and use it to control character and animation states. |
5 | 4 | author: The Defold Foundation |
6 | | -scripts: knight.script |
| 5 | +scripts: knight.script, control.gui_script, fsm.lua |
7 | 6 | thumbnail: thumbnail.png |
| 7 | +tags: animation, sprite, architecture, input |
8 | 8 | --- |
9 | 9 |
|
10 | | -# A simple Finite State Machine for animations. |
| 10 | +You can control the example in two ways: |
11 | 11 |
|
12 | | -This example shows how to create a responsive character animation system using a **Finite State Machine (FSM)**. The character can smoothly transition between different states like idle, running, jumping, attacking, and crouching based on player input. This is a fundamental technique used in most 2D platformers and action games. |
| 12 | +- Use the keyboard: <kbd>Left</kbd>/<kbd>Right</kbd> arrow keys, <kbd>Space</kbd>, <kbd>X</kbd>, and <kbd>C</kbd> |
| 13 | +- Click or touch the on-screen buttons: `idle`, `run`, `turn`, `jump`, `attack`, and `crouch` |
13 | 14 |
|
14 | | -## What You'll Learn? |
| 15 | +The keyboard `C` key is a held crouch input. The GUI `crouch` button toggles crouch on and off. |
15 | 16 |
|
16 | | -- How to implement a state machine for character animations |
17 | | -- How to handle complex input combinations and priorities## Key Concepts |
| 17 | +This example shows how to build a small **Finite State Machine** (FSM) Lua module and use it in more than one place: |
18 | 18 |
|
19 | | -**State Machine**: A design pattern where an object can be in only one state at a time, with clear rules for transitioning between states. |
| 19 | +- animation states in `knight.script` |
| 20 | +- locomotion states (`idle`, `run`) in `control.gui_script` |
| 21 | +- posture states (`standing`, `crouching`) in `control.gui_script` |
20 | 22 |
|
21 | | -**Input Priority**: A system that determines which actions take precedence when multiple keys are pressed simultaneously. |
| 23 | +## What You'll Learn |
22 | 24 |
|
23 | | -**Animation Transitions**: Smooth changes between different animations, often with intermediate "transition" animations. |
24 | | -- How to create smooth transitions between animation states |
25 | | -- How to make sprites flip direction based on movement |
26 | | -- How to add visual effects (like jump animations) |
27 | | -- How to communicate between game objects using messages |
| 25 | +- What Finite State Machines are |
| 26 | +- How to create generic FSM logic in a reusable Lua module |
| 27 | +- How to use multiple smaller FSMs for different control concerns |
| 28 | +- How to combine several control states into one animation target |
| 29 | +- How to insert intermediate animation states automatically |
| 30 | + |
| 31 | +### Finite State Machines |
| 32 | + |
| 33 | +A **Finite-State Machine** is a model with a finite set of possible states, one active state at a time, and explicit rules for moving from one state to another. FSMs are used in digital logic, software, and AI because they make behavior depend on clear state and transition rules. |
| 34 | + |
| 35 | +Check also: |
| 36 | +- [Simplest Lua Finite State Machine on lua-users.org](http://lua-users.org/wiki/FiniteStateMachine) |
| 37 | +- [Lua Finite State Machine by Kyle Conroy](https://github.com/kyleconroy/lua-state-machine) |
| 38 | +- [Lua FSM by unindented](https://github.com/unindented/lua-fsm) |
| 39 | +- [Lua FSM by recih](https://github.com/recih/lua-fsm) |
| 40 | +- ["Simple Lua FSM" video by Mahri2D](https://www.youtube.com/watch?v=aVFMDiaQ_Qc) |
| 41 | +- ["How I think of state machines, coded in Defold" video by kags](https://www.youtube.com/watch?v=Hb3GEcTgkrg) |
28 | 42 |
|
29 | 43 | ## Setup |
30 | 44 |
|
31 | | -The example consists of two main game objects: |
| 45 | +The collection contains two game objects: |
32 | 46 |
|
33 | | -knight |
34 | | -: The animated character. Contains: |
35 | | - - A *Sprite* component with the knight character image and animations. |
36 | | - - A *Script* component (`knight.script`) that implements the state machine logic, handles input, and manages animation transitions. |
| 47 | +<kbd>gui</kbd> |
| 48 | +: Contains `control.gui` and `control.gui_script`. This script owns input focus, handles keyboard and pointer input, and uses two FSMs: one for locomotion (`idle` / `run`) and one for posture (`standing` / `crouching`). |
37 | 49 |
|
38 | | -gui |
39 | | -: The user interface. Contains: |
40 | | - - A *GUI* component (`control.gui`) that has 6 nodes displaying states and text description for the example. |
41 | | - - A *GUI Script* component (`control.gui_script`) that receives messages from the knight and updates the visual state indicators. |
| 50 | +<kbd>knight</kbd> |
| 51 | +: Contains the sprite and `knight.script`. This script owns the animation FSM. It stores the current animation state, validates transitions with the reusable FSM module, plays flipbooks, and notifies the GUI whenever the active animation changes. |
42 | 52 |
|
43 | | -> **Note:** |
44 | | -> The GUI in this example is not required for understanding the state machine logic, it only visually shows the active animation state. You can view the GUI source in the project files on Github still though. |
45 | 53 |
|
46 | | - |
| 54 | + |
47 | 55 |
|
48 | | -## Animation Atlas |
| 56 | +## Input |
49 | 57 |
|
50 | | -The sprite component uses a flipbook animation that is set up in an atlas: |
| 58 | +The GUI stores raw input intent, then the locomotion and posture FSMs turn that intent into stable control states: |
51 | 59 |
|
52 | | -> For this example we used the Free Knight Character by Nauris 'aamatniekss' available here: https://aamatniekss.itch.io/fantasy-knight-free-pixelart-animated-character |
| 60 | +- locomotion FSM: `idle` or `run` |
| 61 | +- posture FSM: `standing` or `crouching` |
53 | 62 |
|
54 | | - |
| 63 | +For keyboard movement, the most recently pressed direction key wins. That lets the turn animation finish and continue into a run as long as one movement key is still held. |
| 64 | + |
| 65 | +The example uses these input bindings: |
| 66 | + |
| 67 | +Key Triggers: |
| 68 | + |
| 69 | +- <kbd>Space</kbd> - jump |
| 70 | +- <kbd>C</kbd> - crouch |
| 71 | +- <kbd>X</kbd> - attack |
| 72 | +- <kbd>Right</kbd> - right |
| 73 | +- <kbd>Left</kbd> - left |
55 | 74 |
|
56 | | -The atlas contains multiple animations for different character states: |
57 | | -- **idle**: Standing still animation |
58 | | -- **run**: Running animation (looped) |
59 | | -- **jump**: Jumping animation (plays once) |
60 | | -- **attack**: Attacking animation (plays once) |
61 | | -- **turn_around**: Turning animation (plays once) |
62 | | -- **crouch_idle**: Crouching idle anim **Note:** ation |
63 | | -- **crouch_walk**: Crouch walking animation |
64 | | -- **crouch_attack**: Crouch attacking animation |
65 | | -- **to_crouch**: Transition from standing to crouching |
66 | | -- **from_crouch**: Transition from crouching to standing |
67 | | - |
68 | | -## Input Bindings |
69 | | - |
70 | | -| Key | Action | |
71 | | -|-----------------|--------------------------------| |
72 | | -| **Left Arrow / Right Arrow** | Move left/right | |
73 | | -| **Space** | Jump | |
74 | | -| **X** | Attack | |
75 | | -| **C** | Crouch (hold to stay crouched) | |
| 75 | +Mouse Triggers: |
| 76 | + |
| 77 | +- <kbd>Button left</kbd> -touch (for left mouse clicks and touch input) |
76 | 78 |
|
77 | 79 |  |
78 | 80 |
|
| 81 | +## How It Works |
| 82 | + |
| 83 | +The example separates three different jobs: |
| 84 | + |
| 85 | +### Reusable FSM module |
| 86 | + |
| 87 | +`fsm.lua` contains the generic part: |
| 88 | + |
| 89 | +- create a machine with `new()` |
| 90 | +- read state with `get_state_name()` and `get_state()` |
| 91 | +- perform direct transitions with `set_state()` |
| 92 | +- find multi-step routes with `find_path()` |
| 93 | + |
| 94 | +This keeps the reusable code small and focused. |
| 95 | + |
| 96 | +### Animation FSM |
79 | 97 |
|
80 | | -## How It Works? |
| 98 | +The knight owns one animation FSM with states such as: |
81 | 99 |
|
82 | | -The character uses a **finite state machine** - a programming pattern where the character can only be in one "state" at a time. Each state can define certain things like: |
83 | | -- Which animation to play |
84 | | -- Whether the animation loops or plays once |
85 | | -- What happens when different keys are pressed |
86 | | -- What state to go to when the animation finishes |
| 100 | +- `standing_idle` |
| 101 | +- `standing_run` |
| 102 | +- `standing_jump` |
| 103 | +- `standing_turn` |
| 104 | +- `crouching_idle` |
| 105 | +- `crouching_run` |
| 106 | +- `to_crouch` |
| 107 | +- `to_standing` |
87 | 108 |
|
88 | | -The system processes input with **priorities**: Attack > Jump > Movement > Crouch/Stand > Turning. This ensures that important actions (like attacking) can interrupt less important ones (like walking). |
| 109 | +When the requested animation is not directly reachable, the knight asks `fsm.find_path()` for a legal route and automatically inserts intermediate animation states. This keeps the controller states simple while still allowing animated transitions such as standing up or crouching down. |
89 | 110 |
|
90 | | -## Key Concepts |
| 111 | +For example: |
91 | 112 |
|
92 | | -**State Machine**: A design pattern where an object can be in only one state at a time, with clear rules for transitioning between states. |
| 113 | +- `standing_idle` → `crouching_run` becomes `standing_idle` → `to_crouch` → `crouching_run` |
| 114 | +- `crouching_run` → `standing_idle` becomes `crouching_run` → `to_standing` → `standing_idle` |
93 | 115 |
|
94 | | -**Input Priority**: A system that determines which actions take precedence when multiple keys are pressed simultaneously. |
| 116 | +### Control FSMs |
95 | 117 |
|
96 | | -**Animation Transitions**: Smooth changes between different animations, often with intermediate "transition" animations. |
| 118 | +The GUI owns two simpler FSMs: |
| 119 | + |
| 120 | +- locomotion FSM: `idle` / `run` |
| 121 | +- posture FSM: `standing` / `crouching` |
| 122 | + |
| 123 | +These smaller machines are easier to understand than one larger controller state containing every combination directly. |
| 124 | + |
| 125 | +The GUI combines them into one animation target for the knight: |
| 126 | + |
| 127 | +- `standing` + `idle` -> `standing_idle` |
| 128 | +- `standing` + `run` -> `standing_run` |
| 129 | +- `crouching` + `idle` -> `crouching_idle` |
| 130 | +- `crouching` + `run` -> `crouching_run` |
| 131 | + |
| 132 | +The GUI sends stable looping targets with `set_target_state`. One-shot actions such as jump, attack, and turn are sent separately with `trigger_state`. |
| 133 | + |
| 134 | +## Why Split It Like This? |
| 135 | + |
| 136 | +Using several small FSMs keeps each machine focused on one question: |
| 137 | + |
| 138 | +- locomotion asks: "idle or run?" |
| 139 | +- posture asks: "standing or crouching?" |
| 140 | +- animation asks: "which exact animation state should play now?" |
| 141 | + |
| 142 | +That is often easier to read and maintain than one large state table that tries to represent every control and animation concern at once. |
| 143 | + |
| 144 | +## Animation Atlas |
| 145 | + |
| 146 | +The sprite component uses a flipbook atlas with the standing, crouching, attack, jump, and transition animations for the knight character. |
| 147 | + |
| 148 | +> This example uses the Free Knight Character by Nauris "aamatniekss": |
| 149 | +> https://aamatniekss.itch.io/fantasy-knight-free-pixelart-animated-character |
| 150 | +
|
| 151 | + |
0 commit comments