Godot Version
4.4
Question
Trying to make interactable animated objects and have been mimicking a few different methods from YouTube tutorials.
Currently trying https://www.youtube.com/watch?v=pQINWFKc9_k , as it seems like a nice way to jump start every interactable object.
The gist is that there is an interaction component scene that is a child node of the player character. It is a 2D node with an Area2D child and the following script:
extends Node2D
@onready var interact_label: Label = $interact_label
var current_interactions := []
var can_interact := true
func _input(event: InputEvent) -> void:
if event.is_action_pressed("e") and can_interact:
if current_interactions:
can_interact = false
interact_label.hide()
await current_interactions[0].interact.call()
can_interact = true
func _process(_delta: float) -> void:
if current_interactions and can_interact:
current_interactions.sort_custom(_sort_by_nearest)
if current_interactions[0].is_interactable:
interact_label.text = current_interactions[0].interact_name
interact_label.show()
else:
interact_label.hide()
func _sort_by_nearest(area1, area2):
var area1_dist = global_position.distance_to(area1.global_position)
var area2_dist = global_position.distance_to(area2.global_position)
return area1_dist < area2_dist
func _on_interact_range_area_entered(area: Area2D) -> void:
current_interactions.push_back(area)
func _on_interact_range_area_exited(area: Area2D) -> void:
current_interactions.erase(area)
The second component is an Area2D with a script that you attach to your interactable scenes.
extends Area2D
@export var interact_name: String = ""
@export var is_interactable: bool = true
var interact: Callable = func():
pass
So I make a StaticBody2D scene called tiny_stone, give it an animated sprite 2d, a collision shape, a couple of timers to trigger functions, a marker to instantiate a collectable item when it is destroyed, and the above Area2D component. And it works as expected so far with one exception.
Expected behavior: When the player character leaves the interaction Area2D before the tiny_stone is finished mining, it stops mining and resets the tiny_stone back to the default state.
Actual behavior: Once the player character initiates mining by pressing “e” in the correct area, no force on Earth will stop it from finishing.
Attempted solution: I’m trying to have the child Area2D signal tiny_stone (its parent) when the player character leaves. This solution worked in a previous iteration but not this one. The signal doesn’t seem to go through, as print() doesn’t log anything when I would expect it to.
The code for tiny_stone is currently as follows:
extends StaticBody2D
@onready var interact_object: Area2D = $interact_object
@onready var mining_time: Timer = $mining_time
@onready var destroyed_time: Timer = $destroyed_time
var state = "default"
var collectable = preload("res://Scenes/Objects/Collectable/tiny_stone_collectable.tscn")
var player_in_area = false
func _ready() -> void:
interact_object.interact = _on_interact
func _process(delta: float) -> void:
if state == "default":
$mining_time.stop()
$AnimatedSprite2D.play("default")
if !player_in_area:
state = "default"
func _on_interact():
if state == "default":
state = "mining"
$AnimatedSprite2D.play("mining")
$mining_time.start()
func _on_mining_time_timeout() -> void:
if state == "mining":
state = "destroyed"
$destroyed_time.start()
$AnimatedSprite2D.play("destroyed")
interact_object.is_interactable = false
var collectable_instance = collectable.instantiate()
collectable_instance.global_position = $collectable_spawner.global_position
get_parent().add_child(collectable_instance)
func _on_destroyed_time_timeout() -> void:
#function to delete this scene, but not the collectable it spawned
pass # Replace with function body.
func _on_interact_object_body_exited(body: Node2D) -> void:
if body.has_method("player"):
player_in_area = false
print("player left area")
func _on_interact_object_body_entered(body: Node2D) -> void:
if body.has_method("player"):
player_in_area = true
print("player now in area")
Sorry for the long post, it just seems missing a tiny detail means missing the cause of the problem. I’m assuming that the method I’m mimicking wasn’t made with animated sprites in mind, and I thought about trying to fix it in the player character’s code instead, but I couldn’t think of how. I appreciate any time you can spare, thank you.
EDIT: Got the enter and leave signals to trigger, was a problem with collision layers not being selected. Still haven’t managed to get the stone to change animations on exit, but it’s a hopeful step.