Godot 3.0 Zelda-like Tutorial [2] Walk and Push Animations

Sprite Direction loop

Now we need to adjust the player script. First we are going to create a new variable under our movedir variable called spritedir. This is going to represent which direction the player is facing.

extends KinematicBody2D

const SPEED = 70

var movedir = Vector2(0,0)
var spritedir = "down"

We need a new function called spritedir_loop(). This is going to have a match statement for our movedir and change the spritedir anytime the player is not moving diagonally. If you are not familiar with Godot’s match statement, they work the same as a switch statement in other languages. It takes one expression and does something different for each outcome you set, which is much cleaner than using a lot of if statements. We are going to set the spritedir to the equivalent movedir.

func spritedir_loop():
	match movedir:
		Vector2(-1,0):
			spritedir = "left"
		Vector2(1,0):
			spritedir = "right"
		Vector2(0,-1):
			spritedir = "up"
		Vector2(0,1):
			spritedir = "down"

We just need to stick this function into the physics process. Underneath, just add “print(spritedir)” so we can see the current sprite direction in the output.

func _physics_process(delta):
	controls_loop()
	movement_loop()
	spritedir_loop()
	print(spritedir)

Run the game and try moving around. In the output log at the bottom of the editor you should see the direction changed every time you press a different arrow key.

Playing the animations

We know what direction the player is facing as a string, we can combine that string with a desired action and have anim play it as an animation. Create a new function called anim_switch(animation). Inside, create a new variable called newanim and set it to “str(animation, spritedir)”. str() turns all of its arguments into one combined string. Let’s say we run this function with “walk” and our current spritedir is “down”. It will combine “walk” with “down” and give us “walkdown”, one of the animations we created earlier.

Now we just need to play the animation. Our if statement is going to see if anim‘s current_animation is NOT newanim. If this is true, anim will play newanim. This prevents the AnimationPlayer from attempting to play the animation every frame, which resets the position of the player to 0 every time resulting in no movement.

func anim_switch(animation):
	var newanim = str(animation,spritedir)
	if $anim.current_animation != newanim:
		$anim.play(newanim)

To finish the walk and idle animations off we just need to tell the physics process which one to play. Go up to our physics process. We are going to have an if statement that checks if movedir is NOT Vector2(0,0), or the player is standing still. If true, we will use anim_switch with “walk”. After that, an else statement that will use anim_switch with “idle”.

When we run the game we can see the player’s sprite update when moving around and it stops animating when we stop moving. We just need to add the push animations now. This will just take a few more if statements. This could be shortened into one with a long line and a lot of parentheses, but I like to split it up. For each of our sprite directions we are going to check if the player is moving up against a wall using test_move. This function simulates if the body moved to a certain location, and if the body would have collided with something, it returns true. This block of code is going to be above our “if movedir != Vector2(0,0):” block, which we are going to change into an elif statement.

func _physics_process(delta):
	controls_loop()
	movement_loop()
	spritedir_loop()
	
	if is_on_wall():
		if spritedir == "left" and test_move(transform, Vector2(-1,0)):
			anim_switch("push")
		if spritedir == "right" and test_move(transform, Vector2(1,0)):
			anim_switch("push")
		if spritedir == "up" and test_move(transform, Vector2(0,-1)):
			anim_switch("push")
		if spritedir == "down" and test_move(transform, Vector2(0,1)):
			anim_switch("push")
	if movedir != Vector2(0,0):
		anim_switch("walk")
	else:
		anim_switch("idle")

Conclusion

That is everything for this video. If you have any questions, join my Discord. If you want to support me, pledge on Patreon. All of my links can be found on the sidebar. See you for the next one!