• 2D
  • Help with player animation

Im trying to create the player's animation, but this happen:

And here the settings:

Why does not run correctly? P.s.: sry my english, it sucks.

I'm sure I'm missing something, but I'm not sure what the issue is.

Is the problem that the sprite moves when the animation plays? If so, then a few things could be causing it:

  • It might be that the script triggering the animation is moving the sprite, probably by altering the position.
    • I'd look at the code and see if translate, position and/or global_position is present. If it is, the try adding a comment on that line so the code does not execute and see if that fixes the issue.
  • Each frame of animation is not centered in the grid of the sprite-sheet/texture. This leads to the character appearing to move, as the character within the sprite-sheet/texture moves within the frame/cell of the animation.
    • Depending on how your animations are setup, this is relatively easy to fix. This just requires positioning all of the cells/frames of animation so that a central element (generally the feet) are at roughly the same relative position within each cell/frame.
  • If you are using and/or have a Camera2D node following the player, try adjusting the drag margin values.
    • It could be the slight delay is actually the camera's drag margin, which is why the character appears to move forward relative to the screen. Setting the drag margin property to a lower value should help fix the issue.

Though it could be other factors too, it is hard to say looking at the GIF file.

If the problem is the sprite moves when the animation plays, hopefully what I wrote above will be of some help! If it is not a sprite moving problem, can you describe what part isn't working?

@TwistedTwigleg said: I'm sure I'm missing something, but I'm not sure what the issue is.

Is the problem that the sprite moves when the animation plays? If so, then a few things could be causing it:

  • It might be that the script triggering the animation is moving the sprite, probably by altering the position.
    • I'd look at the code and see if translate, position and/or global_position is present. If it is, the try adding a comment on that line so the code does not execute and see if that fixes the issue.
  • Each frame of animation is not centered in the grid of the sprite-sheet/texture. This leads to the character appearing to move, as the character within the sprite-sheet/texture moves within the frame/cell of the animation.
    • Depending on how your animations are setup, this is relatively easy to fix. This just requires positioning all of the cells/frames of animation so that a central element (generally the feet) are at roughly the same relative position within each cell/frame.
  • If you are using and/or have a Camera2D node following the player, try adjusting the drag margin values.
    • It could be the slight delay is actually the camera's drag margin, which is why the character appears to move forward relative to the screen. Setting the drag margin property to a lower value should help fix the issue.

Though it could be other factors too, it is hard to say looking at the GIF file.

If the problem is the sprite moves when the animation plays, hopefully what I wrote above will be of some help! If it is not a sprite moving problem, can you describe what part isn't working?

Thats helped :+1:

I have another question now: First, I hold the directional keys and looks fine. After, when I pressed once the arrow keys, the animation doesnt run, just move staticly. Look:

How can I fix that?

@DarlesLSF said: Thats helped :+1:

Great! Glad it was of some help.

I have another question now: First, I hold the directional keys and looks fine. After, when I pressed once the arrow keys, the animation doesnt run, just move staticly. Look:

How can I fix that?

Without looking at the code that moves the character, it is hard to say for sure. If possible, can you post the code for the character?


The issue is most likely that the animation is being called whenever the arrow keys is pressed, without checking to see if the animation is already playing. This causes the first frame of the animation to be played repeatedly, giving the static look.

A simple solution is to check to see if the animation is playing already before changing to it. Something like the following should work:

# When the arrow key(s) are pressed, or whatever happens before
# the animation is changed.
if Input.is_action_pressed("ui_left"):
	# Check to see if the the animation playing is not the animation we want to change to
	# this way, the code will tell the animation to change to the animation we want, but if it is playing
	# the animation we want, then it will not change.
	#
	# (I am assuming that "andando_esquerda" is the animation you want to use when moving).
	if (animation_player_node.current_animation != "andando_esquerda"):
		# change the animation!
		animation_player_node.play("andando_esquerda")
	else:
		# the animation we want is playing, so don't do anything.
		pass
	# Add any other code you want to play when the character is moving here!

That is one way to check whether the animation needs to be changed or not. There are other ways to do it that depending on your project, may be better or worse. Hopefully what I wrote gives the general idea.


Another common case where this can happen is where the animation being played is based on the velocity of the character. When a key is tapped instead of held, this can rapidly change the velocity, causing only the first few frames of animation to be shown (causing the static look).

Finding a solution to this issue is largely dependent on how your game works, how often the velocity is going to change in the game, and other factors that make finding a generic solution to the issue difficult.

One solution is to interpolate the velocity when the player moves, smoothing the changes to velocity and giving the animation more time to play. The downside of this approach is that the player won't instantly start moving, but instead their movement in any direction will be interpolated. Depending on your game, this may or may not work.

The solution I often use is blending the animations together by passing a custom_blend argument to the play function in the AnimationPlayer node. By blending in the animations, it smooths the transitions from the idle animation to the moving animation. This works for 3D animation and bone-based 2D animation, as the key frames in the animation are just different positions, rotations, and/or scales. For frame based 2D animation, I have no idea how blending would work, nor if it would give desirable results.


Hopefully what I wrote above helps in finding a solution to the issue! :smile:

Here's the code:

var dir = Input.is_action_pressed("direita")
var esque = Input.is_action_pressed("esquerda")
var cima = Input.is_action_pressed("cima")
var baixo = Input.is_action_pressed("baixo")

if (dir):
	$Sarha.play("andando_direita")
elif (esque):
	$Sarha.play("andando_esquerda")
elif (cima):
	$Sarha.play("andando_cima")
elif (baixo):
	$Sarha.play("andando_baixo")
else:
	$Sarha.stop()
	$Sarha.frame = 1


movedir.x = -int(esque) + int(dir)
movedir.y = -int(cima) + int(baixo)

Thanks for sharing the code. I made some adjustments that should, hopefully, minimize the issue if not fix it completely. I included two versions, one that checks if the animation is different, and another that checks if the animation is different, but also uses a timer.

Version 1 (just checks if the animation is different):

var dir = Input.is_action_pressed("direita")
var esque = Input.is_action_pressed("esquerda")
var cima = Input.is_action_pressed("cima")
var baixo = Input.is_action_pressed("baixo")

if (dir):
	# Make sure the animation we want (andando_direita) is not
	# already playing. If it is not playing, then change to that animation
	if ($Sarha.current_animation != "andando_direita"):
		$Sarha.play("andando_direita")
elif (esque):
	if ($Sarha.current_animation != "andando_esquerda"):
		$Sarha.play("andando_esquerda")
elif (cima):
	if ($Sarha.current_animation != "andando_cima"):
		$Sarha.play("andando_cima")
elif (baixo):
	if ($Sarha.current_animation != "andando_baixo"):
		$Sarha.play("andando_baixo")
else:
	$Sarha.stop()
	$Sarha.frame = 1


movedir.x = -int(esque) + int(dir)
movedir.y = -int(cima) + int(baixo)

Version 2 (checks is the animation is different, and uses a small timer):

# A variable to use as a simple timer
var animation_change_timer = 0
# A constant to track how long of a delay there should be before
# allowing the animation to change
const ANIMATION_CHANGE_TIME = 0.1


# I have no idea where this code is. The timer code should work fine with
# _process or _physics_process. The timer just needs the delta variable
func _process(delta):
	var dir = Input.is_action_pressed("direita")
	var esque = Input.is_action_pressed("esquerda")
	var cima = Input.is_action_pressed("cima")
	var baixo = Input.is_action_pressed("baixo")
	
	if (dir):
		# Make sure the animation we want (andando_direita) is not
		# already playing. If it is not playing, then change to that animation
		if ($Sarha.current_animation != "andando_direita"):
			$Sarha.play("andando_direita")
			animation_change_timer = ANIMATION_CHANGE_TIME
	elif (esque):
		if ($Sarha.current_animation != "andando_esquerda"):
			$Sarha.play("andando_esquerda")
			animation_change_timer = ANIMATION_CHANGE_TIME
	elif (cima):
		if ($Sarha.current_animation != "andando_cima"):
			$Sarha.play("andando_cima")
			animation_change_timer = ANIMATION_CHANGE_TIME
	elif (baixo):
		if ($Sarha.current_animation != "andando_baixo"):
			$Sarha.play("andando_baixo")
			animation_change_timer = ANIMATION_CHANGE_TIME
	else:
		# Check if the timer is more than zero.
		# If it is, then wait ANIMATION_CHANGE_TIME seconds
		# before changing the animation to the idle animation
		if (animation_change_timer > 0):
			animation_change_timer -= delta
		# If the timer is zero or less, then change the animation
		else:
			$Sarha.stop()
			$Sarha.frame = 1

	movedir.x = -int(esque) + int(dir)
	movedir.y = -int(cima) + int(baixo)

Hopefully this helps!

First I tried use the AnimationPlayer, but now I'm using AnimatedSprite. So, how can I fix that in ur code? Because the "current_animation" doesnt work with AnimatedSprite :/

Edit: already solved haha

Great! I'm glad you were able to find a solution :smile: