Godot: Player Animation

This post continues from the 1st one– Read Part 1 if you haven't. In this post, we'll add player animation

All the code is here, under Part 2

Player Animation

Till now, our player moves, but isn't really animated. Let's fix that.

Open Player.tscn, and add a new node for AnimatedSprite:

On the right, choose New Sprite  Frame:

And then click on the SpriteFrame you just created– this is slightly confusing, so I will show you what you need to click:

This will open a new animation window at the bottom:

Double click on the default animation and rename it to idle.

Then, drag across the idle image from the filesystem:

Create another animation for jump by clicking the New animation button:

Rename it to jump, and drag across the jump image.

So far, the animations only have one image, so they really aren't animations. Let's create a walking animation.

Create a new animation called walk as before.

And this time, drag the walk1 and walk2 image files:

Click the Playing button on the right, and you should see the player animate:

Good, so we have a simple animation setup. Let's use this in our code.

Using the AnimationPlayer with our Script

Using the  new animation is quite simple. Modify the code to add:

func _physics_process(_delta):
	if Input.is_action_pressed("right"):
		velocity.x = SPEED
		$AnimatedSprite.play("walk")  # ==> This is the new line
    elif Input.is_action_pressed("left"):
		velocity.x = -SPEED
		$AnimatedSprite.play("walk") # ==> This is the new line
    else:
		velocity.x = 0
		$AnimatedSprite.play("idle")  # ==> This is the new line

If the player presses left or right, we play the walk animation, otherwise we play idle.

Good, but the character always faces right, even when walking left. Let's fix that.

Godot has an inbuilt property to flip images. On the AnimatedSprite settings:

Flip H flips horizontally, while Flip V does it vertically. And even better, we can call these from the code:

	if Input.is_action_pressed("right"):
		velocity.x = SPEED
		$AnimatedSprite.play("walk")
		$AnimatedSprite.flip_h = false # ==> new code
	elif Input.is_action_pressed("left"):
		velocity.x = -SPEED
		$AnimatedSprite.play("walk")
		$AnimatedSprite.flip_h = true # ==> new code

We set $AnimatedSprite.flip_h = true when walking left, as our sprite is originally right facing. And we set it to false when walking right, as the sprite faces right to begin with. Let's test:

That's great.

Adding Jumping

If you remember, we added an animation for jumping, but there is no code for it. Let's fix that now.

Add this to the top of your script:

const JUMP_SPEED=100

And then in the function:

if Input.is_action_pressed("up"):
		$AnimatedSprite.play("jump")
		velocity.y -= JUMP_SPEED	

Let's try it:

2 problems:

  • The jump animation isn't working perfectly
  • Also, if you keep pressing up, you can fly into the air like superman (see the gif above)

Let's fix these.

First, the superman jump– we only want to enable jump if we are on the floor (or another ground). Luckily, godot has an inbuilt function for that

bool is_on_floor ( ) const
Returns true if the body collided with the floor on the last call of move_and_slide or move_and_slide_with_snap. Otherwise, returns false.

https://docs.godotengine.org/en/stable/classes/class_kinematicbody2d.html?highlight=is_on_floor#class-kinematicbody2d-method-is-on-floor

Let's use that.

if Input.is_action_pressed("up")  and is_on_floor() :
		velocity.y -= JUMP_SPEED	

So jump is only allowed if we are on the floor.

Now for the animation– it moved to jump but immediately went to idle. That's because it only shows jump when we press up, but we want it to show it all the time we are in the air. Let's use our is_on_floor() function again:

if not is_on_floor():
		$AnimatedSprite.play("jump")

There were 2 more things we had to do. First, I had to increase JUMP_SPEED to 500, as else the jump was too low.

Second, in order for  is_on_floor() to work, Godot needs to know which direction is up, so it can know if it is on the floor or ceiling. Our function move_and_slide() needs to be updated. From the docs:

up_direction is the up direction, used to determine what is a wall and what is a floor or a ceiling. If set to the default value of Vector2(0, 0), everything is considered a wall. This is useful for topdown games.

So let's update the function:

velocity = move_and_slide(velocity, Vector2.UP)		

I pass in the inbuilt Vector2.UP for up_direction.

Let's run the code:

Cool.

Update 13/12/12: I realised why when the player walks above, it looks like it has 4 hands– I had a extra standing image pasted behind the walking image, so it was displaying the standing and walking image at the same time. I fixed this in Part 4, as that's where I went to the trouble to find out what's happening.

To fix this, just look at the character animation, you will see 2 images. Delete one. If you are worried about deleting the wrong one, don't worry about making this change, as it's a minor glitch anyway.

For now, let's go to level design.