Skip to content

Commit 1e027d7

Browse files
authored
Updated Finite State Machine for animations example. (#172)
1 parent 2454963 commit 1e027d7

13 files changed

Lines changed: 887 additions & 394 deletions
-75.5 KB
Binary file not shown.

animation/animation_states/assets/example.input_binding

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,7 @@ key_trigger {
1818
input: KEY_LEFT
1919
action: "left"
2020
}
21+
mouse_trigger {
22+
input: MOUSE_BUTTON_LEFT
23+
action: "touch"
24+
}
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
font: "/assets/SourceSansPro-Semibold.ttf"
2-
material: "/builtins/fonts/font.material"
3-
size: 32
2+
material: "/builtins/fonts/font-df.material"
3+
size: 28
4+
output_format: TYPE_DISTANCE_FIELD
45
characters: " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
Lines changed: 118 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,96 +1,151 @@
11
---
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.
54
author: The Defold Foundation
6-
scripts: knight.script
5+
scripts: knight.script, control.gui_script, fsm.lua
76
thumbnail: thumbnail.png
7+
tags: animation, sprite, architecture, input
88
---
99

10-
# A simple Finite State Machine for animations.
10+
You can control the example in two ways:
1111

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`
1314

14-
## What You'll Learn?
15+
The keyboard `C` key is a held crouch input. The GUI `crouch` button toggles crouch on and off.
1516

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:
1818

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`
2022

21-
**Input Priority**: A system that determines which actions take precedence when multiple keys are pressed simultaneously.
23+
## What You'll Learn
2224

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)
2842

2943
## Setup
3044

31-
The example consists of two main game objects:
45+
The collection contains two game objects:
3246

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`).
3749

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.
4252

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.
4553

46-
![animation_states_collection](animation_states_collection.png)
54+
![animation_states_collection](setup.png)
4755

48-
## Animation Atlas
56+
## Input
4957

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:
5159

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`
5362

54-
![atlas](atlas.png)
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
5574

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)
7678

7779
![input_bindings](input_bindings.png)
7880

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
7997

80-
## How It Works?
98+
The knight owns one animation FSM with states such as:
8199

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`
87108

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.
89110

90-
## Key Concepts
111+
For example:
91112

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`
93115

94-
**Input Priority**: A system that determines which actions take precedence when multiple keys are pressed simultaneously.
116+
### Control FSMs
95117

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+
![atlas](atlas.png)

animation/animation_states/example/animation_states.collection

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ embedded_instances {
2020
""
2121
position {
2222
x: 360.0
23-
y: 600.0
23+
y: 580.0
2424
}
2525
scale3 {
2626
x: 5.0

animation/animation_states/example/control.gui

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
script: "/example/control.gui_script"
22
fonts {
33
name: "text48"
4-
font: "/assets/text32.font"
4+
font: "/assets/text28.font"
55
}
66
nodes {
77
position {
88
x: 500.0
9-
y: 150.0
9+
y: 170.0
1010
}
1111
size {
1212
x: 120.0
@@ -39,7 +39,7 @@ nodes {
3939
nodes {
4040
position {
4141
x: 200.0
42-
y: 150.0
42+
y: 170.0
4343
}
4444
size {
4545
x: 120.0
@@ -72,7 +72,7 @@ nodes {
7272
nodes {
7373
position {
7474
x: 350.0
75-
y: 150.0
75+
y: 170.0
7676
}
7777
size {
7878
x: 120.0
@@ -105,7 +105,7 @@ nodes {
105105
nodes {
106106
position {
107107
x: 500.0
108-
y: 250.0
108+
y: 270.0
109109
}
110110
size {
111111
x: 120.0
@@ -123,9 +123,6 @@ nodes {
123123
size_mode: SIZE_MODE_AUTO
124124
}
125125
nodes {
126-
position {
127-
y: 3.0
128-
}
129126
size {
130127
x: 120.0
131128
y: 70.0
@@ -143,7 +140,7 @@ nodes {
143140
nodes {
144141
position {
145142
x: 200.0
146-
y: 250.0
143+
y: 270.0
147144
}
148145
size {
149146
x: 120.0
@@ -178,7 +175,7 @@ nodes {
178175
nodes {
179176
position {
180177
x: 350.0
181-
y: 250.0
178+
y: 270.0
182179
}
183180
size {
184181
x: 120.0
@@ -213,19 +210,15 @@ nodes {
213210
nodes {
214211
position {
215212
x: 350.0
216-
y: 50.0
213+
y: 70.0
217214
}
218215
size {
219-
x: 120.0
216+
x: 550.0
220217
y: 70.0
221218
}
222-
color {
223-
x: 0.2
224-
y: 0.302
225-
z: 0.702
226-
}
227219
type: TYPE_TEXT
228-
text: "Use arrow keys, space, X and C."
220+
text: "Use keys left, right, space, X and C\n"
221+
"or click/touch buttons to change state."
229222
font: "text48"
230223
id: "description"
231224
layer: "text"

0 commit comments

Comments
 (0)