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
var window_size = Vector2(200, 200)
@onready var animated_sprite = $AnimatedSprite2DAdd this to _ready() to start the animation when the game starts
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.
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_hLet 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:
var window_size = Vector2(200, 200)
var idle_timer = 0.0
var is_idling = falseAdd a function that gives the pet a 30% chance of resting and picks a random resting animation
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 = 0randf_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:
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
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")
returnPick 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
@onready var animated_sprite = $AnimatedSprite2D
@onready var area = $Area2DAdd two variables for dragging
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:
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 = falseWhen 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():
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()
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!
git add .
git commit -m "I did it!!!"
git push