Diagonal animation not working

Godot Version

Godot 4

Question

I set up animations with Godot and have the animations working in the four cardinal directions, but whenever I try to move upright for example the animation freezes in the first frame, any ideas? Thanks for reading!

extends CharacterBody2D

const speed = 100
var motion = speed

var currentDirection = “none”

func _physics_process(delta):
playermovement(delta)
move_and_slide()

func playermovement(delta):

if Input.is_action_pressed("left"):
	currentDirection = "left"
	playAnimation(1)
	velocity.x = -1
	velocity.y = 0
elif Input.is_action_pressed("right"):
	currentDirection = "right"
	playAnimation(1)
	velocity.x = 1
	velocity.y = 0
elif Input.is_action_pressed("up"):
	currentDirection = "up"
	playAnimation(1)
	velocity.x = 0
	velocity.y = -1
elif Input.is_action_pressed("down"):
	currentDirection = "down"
	playAnimation(1)
	velocity.x = 0
	velocity.y = 1

else:
	currentDirection = "nothing"
	playAnimation(0)
	velocity.x = 0
	velocity.y = 0

if Input.is_action_pressed("up") and Input.is_action_pressed("left"):
	currentDirection = "topleft"
	playAnimation(1)
	velocity.x = -1
	velocity.y = -1
if Input.is_action_pressed("up") and Input.is_action_pressed("right"):
	currentDirection = "upright"
	playAnimation(1)
	velocity.x = 1	
	velocity.y = -1

if Input.is_action_pressed("down") and Input.is_action_pressed("left"):
	currentDirection = "downleft"
	velocity.x = -1
	velocity.y = 1
if Input.is_action_pressed("down") and Input.is_action_pressed("right"):
	currentDirection = "downright"
	velocity.x = 1
	velocity.y = 1

if currentDirection != "nothing":
	velocity = velocity.normalized() * speed 
	print(velocity)

func playAnimation(movement):

   var dirCheck = currentDirection
var animation = $AnimatedSprite2D

if currentDirection == "upright":
	if velocity.x >= 1 and velocity.y <= 1:
		animation.play("upright")
	elif movement == 0:
		animation.play("idle")
		
if currentDirection == "left":
	animation.flip_h = true
	if movement == 1:
		animation.play("right")
	elif movement == 0:
		animation.play("idle") 

if currentDirection == "right":
	animation.flip_h = false
	if movement == 1:
		animation.play("right")
	elif movement == 0:
		animation.play("idle")
		
if currentDirection == "up":
	animation.flip_h= false
	if movement == 1:
		animation.play("up")
	elif movement == 0:
		animation.play("idle")

if currentDirection == "down":
	animation.flip_h = false
	if movement == 1:
		animation.play("down")
	elif movement == 0:
		animation.play("idle")

else:
	if currentDirection == "nothing":
		animation.play("idle")

try elif other than just if for each input or currentdirection

If up and left are held at the same time, the script will play the left animation and then the topleft animation every frame, which resets the animation.

I can think of two possible solutions for this problem; you can get an input vector and set the animation based on the angle, or you can choose an animation for every possible input combination.

Choosing the animation based on the direction of an input vector:

const ANIMATION_NAMES = [
    "right", "downright", "down", "downleft",
    "left", "upleft", "up", "upright"]

func playermovement(delta):
    var input_vector = Vector2(
        Input.get_axis("left", "right"),
        Input.get_axis("up", "down"))
    if input_vector != Vector2.ZERO:
        var angle = input_vector.angle()
        # angle is a value between -PI and PI.
        # For choosing an animation you need and int in range from 0 to 7
        angle *= 8.0 / TAU
        # Now the angle is between -4.0 and 4.0
        # The angles where the animation changes needs to be offset by a 16th of a full turn
        angle += TAU / 16.0
        # Then you can use floor() and posmod() to get an index for the direction.
        var animation_index = posmod(floor(angle), 8)
        # 0 is right, 1 is down and right, 2 is down and so on
        currentDirection = ANIMATION_NAMES[animation_index]
    else:
        currentDirection = "nothing"

Choosing the animation based on input flags:

const ANIMATION_NAMES = [
    "nothing",
    "left",
    "right",
    "nothing", # left & right
    "up",
    "upleft",
    "upright",
    "up", # up & left & right
    "down",
    "downleft",
    "downright",
    "down", # down & left & right
    "nothing", # up & down
    "left", # up & down & left
    "right", # up & down & right
    "nothing" # all at the same time
]

func playermovement(delta):
    var input_flags = 0
    # Store inputs as bits to an integer
    input_flags |= int(Input.is_action_pressed("left"))
    input_flags |= int(Input.is_action_pressed("right")) << 1
    input_flags |= int(Input.is_action_pressed("up")) << 2
    input_flags |= int(Input.is_action_pressed("down")) << 3
    # Choose the animation
    currentDirection = ANIMATION_NAMES[input_flags]
1 Like