playground, back to the guide

open the guide in a new tab ↗

Build a desktop pet in Godot

step 5 of 6: Animate and drag

Animations

Currently it looks a little strange, it just slides left and right. We need to use those animations we made earlier!

To do this we need our code to speak to the AnimatedSprite2D node, create a variable that references it like this

GDScript
var window_size = Vector2(200, 200)

@onready var animated_sprite = $AnimatedSprite2D

Add this to _ready() to start the animation when the game starts

GDScript
func _ready():
	screen_size = Vector2(DisplayServer.screen_get_size())
	animated_sprite.play("Walk_Right")

And add this line to flip the sprite when it touches a wall so it’s walking in the correct direction.

GDScript
	if window_position.x <= 0 or window_position.x >= screen_size.x - window_size.x:
		direction.x *= -1
		animated_sprite.flip_h = !animated_sprite.flip_h

Let it take a break

Sometimes when the pet bumps into a wall, it should stop and chill for a moment. We need two new variables, one to say whether it's resting and one to count down how long for:

GDScript
var window_size = Vector2(200, 200)

var idle_timer = 0.0
var is_idling = false

Add a function that gives the pet a 30% chance of resting and picks a random resting animation

GDScript
func maybe_idle():
	if randf() < 0.3:
		is_idling = true
		idle_timer = randf_range(1.0, 3.0)
		var r = randi() % 3
		if r == 0:
			animated_sprite.play("Idle")
			speed = 0

randf_range(1.0, 3.0) means it rests for 1 to 3 seconds. randi() % 3 gives a random 0, 1 or 2, which we use to choose an animation.

Call maybe_idle() whenever the pet bounces. Update your bounce code from “Bounce off the edges” so it looks like this:

GDScript
	if window_position.x <= 0 or window_position.x >= screen_size.x - window_size.x:
		direction.x *= -1
		animated_sprite.flip_h = !animated_sprite.flip_h
		maybe_idle()
	if window_position.y <= 0 or window_position.y >= screen_size.y - window_size.y:
		direction.y *= -1
		maybe_idle()

While it's resting, the pet shouldn't move. Add this at the very top of _physics_process

GDScript
func _physics_process(delta: float) -> void:
	if is_idling:
		idle_timer -= delta
		if idle_timer <= 0:
			is_idling = false
			speed = 300
			animated_sprite.play("Walk_Right")
		return

Pick it up and drag it around

This is what the Area2D and CollisionShape2D are for: they detect when you click on the pet. Get a reference to the Area2D with a new @onready line

GDScript
@onready var animated_sprite = $AnimatedSprite2D
@onready var area = $Area2D

Add two variables for dragging

GDScript
var is_dragging = false
var drag_offset = Vector2()

drag_offset remembers where on the pet you grabbed it, so the pet doesn't jump so its corner snaps to your mouse.

Add a function that runs when you click on the Area2D:

GDScript
func _on_area_input(_viewport, event, _shape_idx):
	if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
		if event.pressed:
			is_dragging = true
			var mouse_pos = Vector2(DisplayServer.mouse_get_position())
			var win_pos = Vector2(DisplayServer.window_get_position())
			drag_offset = mouse_pos - win_pos
		else:
			is_dragging = false

When you press the left mouse button, dragging starts and we remember the offset. When you let go, dragging stops and the pet wanders off in a new direction.

Connect this function to the Area2D's input_event signal, so Godot calls it on a click. Add this to _ready():

GDScript
func _ready():
	screen_size = Vector2(DisplayServer.screen_get_size())
	animated_sprite.play("Walk_Right")
	area.input_event.connect(_on_area_input)

Finally, make the window follow the mouse while you're dragging. Add this at the very top of _physics_process()

GDScript
func _physics_process(delta: float) -> void:
	if is_dragging:
		var mouse_pos = Vector2(DisplayServer.mouse_get_position())
		var new_win_pos = mouse_pos - drag_offset
		DisplayServer.window_set_position(Vector2i(new_win_pos))
		return

	if is_idling:

This goes first because dragging should win over everything else. If you're holding the pet, it shouldn't be resting or walking.

Don't forget to commit!

shell
git add .
git commit -m "I did it!!!"
git push