I'm trying to animate a 2D character using a blendspace2D in an animation tree. I've built a basic state machine where, when the charge
input is detected while the directional movement is not (0, 0)
, the state changes to the DASH
state and remains there until the charge
button is released, with the animation state changing to the Dash
animation blendspace2D. However, while in the DASH
state, the animation doesn't update if I change directions, e.g., if I dash left and then move right while dashing, the animation doesn't change so the character goes backwards. While not in the DASH
state, I have a similar blendspace2D for normal movement, which updates the animations correctly. My code to manage the player character, including the state machine and blendspaces is below.
extends CharacterBody2D
class_name Player
@export var ACCELERATION = 17
@export var MAX_SPEED = 100
@export var FRICTION = 100
@export var DASH_SPEED = MAX_SPEED * 1.5
var direction = Vector2.ZERO
enum{
MOVE,
DASH,
CHARGE,
ATTACK
}
var state = MOVE
@onready var animation_player = $AnimationPlayer
@onready var animation_tree = $AnimationTree
@onready var animation_state = animation_tree.get("parameters/playback")
@onready var sprite_2d = $Sprite2D
#@onready var animation_state = animation_tree.get("parameters/playback")
#var direction_changed = false
var anim_dir = Vector2.ZERO
func _ready():
animation_tree.active = true
func _process(_delta):
direction = Vector2.ZERO
anim_dir.x = Input.get_axis("move_left", "move_right")
anim_dir.y = Input.get_axis("move_up", "move_down")
direction = anim_dir.normalized()
func _physics_process(delta):
match state:
MOVE:
move_state(delta)
DASH:
dash_state(delta)
CHARGE:
charge_state(delta)
ATTACK:
attack_state(delta)
func move_state(delta):
if direction.length()!= 0:
if anim_dir.x !=0:
set_animation_parameters()
velocity = velocity.move_toward(direction * MAX_SPEED, ACCELERATION)
move_and_slide()
animation_state.travel("Move")
if Input.is_action_just_pressed("charge"):
state = DASH
else:
velocity = velocity.move_toward(Vector2.ZERO, FRICTION)
if Input.is_action_just_pressed("charge"):
state = CHARGE
animation_state.travel("Idle")
func set_animation_parameters():
animation_tree.set("parameters/Idle/blend_position", anim_dir)
animation_tree.set("parameters/Move/blend_position", anim_dir)
animation_tree.set("parameters/Dash/blend_position", anim_dir)
func dash_state(delta):
if direction.length()>0:
if anim_dir.x != 0:
set_animation_parameters()
velocity = velocity.move_toward(direction * DASH_SPEED, ACCELERATION)
move_and_slide()
animation_state.travel("Dash")
if Input.is_action_just_released("charge"):
state=MOVE
func attack_state(delta):
pass
func charge_state(delta):
print("charging...")
if Input.is_action_just_released("charge"):
state = MOVE
As you can see, I set the animation parameters for each state while both moving and dashing and have the animation_state
travel to Dash
and Move
in the same way, yet the latter works and the former doesn't. As far as I can tell it's not because the Move
animation state gets interrupted by the Idle
animation state, as I can change directions by holding the input vertically without resetting to the Idle
animation and it still works.
Here's my animation tree setup:
Here's the Move
state's blendspace2D where every point on the left is the left moving animation and every point on the right is the right moving animation
And here's the Dash
state with the same setup as the Move
state
I've tried everything I can think of and have come up empty. Any help would be appreciated.
Solution: Blend parameter was set incorrectly to be continuous in the Dash state. I set it to be discrete, just as in the Move state's Blend parameter and it worked.