Godot Version
4.5
Question
Hello, I am trying to animate a dog. I made a tiny state machine with two states: IDLE and SLEEP. The dog has a bunch of animations, here’s my animation tree:
Here are the infos for these animations:
- Idle2: 5s, looping
- LieStat: 1.5s, non-looping
- SleepStart: 0.4167s, non-looping
- Sleep: 0.8333s, looping
- SleepEnd: 0.625, non-looping
- LieEnd: 1.4583s, non-looping
Transitions:
- Start → Idle2 is Immidiate and Auto
- All other transitions: At End and Auto
- Idle2 → LieStart and Sleep → SleepEnd have `break_loop_at_end` set to `true`
Now if I just play press I get this: https://imgur.com/IAvZwAm (see debug info top left)
If I change the state to sleep after 5s i.e.:
get_tree().create_timer(5.0).timeout.connect(func(): $Corgi.set_state($Corgi.State.SLEEP))
I get this: https://imgur.com/GaRJWry
Here’s also my little state machine. This is attached to the dog.
extends Node3D
enum State {IDLE, SLEEP}
var current_state: State = State.IDLE
var last_state: State = State.IDLE
@onready var nav_agent: NavigationAgent3D = $NavigationAgent3D
@onready var anim_tree: AnimationTree = $AnimationTree
@onready var anim_player: AnimationPlayer = $AnimationPlayer
@onready var state_machine: AnimationNodeStateMachinePlayback = anim_tree["parameters/playback"]
@onready var last_state_label = $"../CanvasLayer/last_state_label"
@onready var current_state_label = $"../CanvasLayer/current_state_label"
@onready var current_node_label = $"../CanvasLayer/current_node_label"
var idle_states := ["Idle1", "Idle2", "Idle3", "Idle4"]
func _ready() -> void:
anim_tree.active = true
state_machine.start(idle_states[0])
func _physics_process(delta: float) -> void:
last_state_label.text = "Last State: " + State.keys()[last_state]
current_state_label.text = "Current State: " + State.keys()[current_state]
current_node_label.text = "Current Node: " + state_machine.get_current_node()
match current_state:
State.IDLE:
handle_idle(delta)
State.SLEEP:
handle_sleep(delta)
func handle_idle(delta: float) -> void:
if last_state != current_state:
print("ENTERING IDLE")
state_machine.travel("Idle2")
last_state = current_state
func handle_sleep(delta: float) -> void:
if last_state != current_state:
print("ENTERING SLEEP")
state_machine.travel("Sleep")
last_state = current_state
func set_state(new_state: State) -> void:
if new_state == last_state:
return
last_state = current_state
current_state = new_state
I don’t really know what’s going on. Here’s what I want:
I want high level states like IDLE or SLEEP that travel to a node in my AnimationTree. I want the animations to be fluid and nice, so they shouldn’t transition immediately. Now I can imagine that if I change the state too quickly, I get some weird behaviour but I don’t think I do that in my examples, I literally only have 1 state change.
E.g. I want to call `set_state(IDLE)` and it transitions to an idle state from whatever state it was in and just plays the animations and then loops the idle animation (without me looping it in code). Same for SLEEP state.
I hope this makes sense. Thanks in advance for any help.
