Godot Version
Godot_v4.3-stable_win64
Question
I’m trying to write something like intaraction system. I have one class called “Interactor” and one class called “InteractiveObject”. Both of them require an Area2D node.
First one, an Interactor, monitors areas by connecting to its Area2D signals area_entered
and area_exited
. Simplified class is here:
extends Node2D
class_name Interactor
#region public
@export var active : bool = true:
set(_new_active):
if _new_active == active:
return
active = _new_active
_update_signals_connections()
#endregion public
#region private
@export var _interactive_area : Area2D
var _is_signal_connected : bool = false
var _object_list : Array[InteractiveObject]
func _ready() -> void:
assert(_interactive_area, "Interactive Area must be set!")
_update_signals_connections()
func _destructor():
active = false
func _process(_delta: float) -> void:
pass
func _update_signals_connections():
if active and not _is_signal_connected:
_interactive_area.area_entered.connect(_handle_area_entered)
_interactive_area.area_exited.connect(_handle_area_exited)
_is_signal_connected = true
return
if not active and _is_signal_connected:
_interactive_area.area_entered.disconnect(_handle_area_entered)
_interactive_area.area_exited.disconnect(_handle_area_exited)
_is_signal_connected = false
return
func _handle_area_entered(_other_area : Area2D):
var _owner = _other_area.owner
var _interactive_object : InteractiveObject = Utils.find_first_node_of_type(_owner, InteractiveObject)
if not _interactive_object:
return
_object_list.push_back(_interactive_object)
_interactive_object.enter_interactor_area(self)
func _handle_area_exited(_other_area : Area2D):
var _owner = _other_area.owner
var _interactive_object : InteractiveObject = Utils.find_first_node_of_type(_owner, InteractiveObject)
if not _interactive_object:
return
_object_list.erase(_interactive_object)
_interactive_object.exit_interactor_area(self)
func _notification(what):
match what:
NOTIFICATION_PREDELETE:
_destructor()
#endregion private
Utils.find_first_node_of_type
- returns the first child of given node of given type, without recursion.
And the Interactive Object class:
extends Node2D
class_name InteractiveObject
#region public
func enter_interactor_area(_interactor : Interactor):
print('Enters!')
func exit_interactor_area(_interactor : Interactor):
print('Exits!')
#endregion public
Later there will be abilities, that Interactive Object will give to Interactor.
For example. Player’s Interactor’s area catched sword’s Interactive Object’s area - sword gives the player an ability to take it (and then ability system will turn on inputs etc…). Player went away from swords area - sword removes abilities.
Imagine, that player got an ability to take sword and takes it. An ability adds sword to player’s inventory and removes sword scene by calling queue_free
. We can simulate it by adding queue_free
call to Interactor’s _handle_area_entered
method:
func _handle_area_entered(_other_area : Area2D):
var _owner = _other_area.owner
var _interactive_object : InteractiveObject = Utils.find_first_node_of_type(_owner, InteractiveObject)
if not _interactive_object:
return
_object_list.push_back(_interactive_object)
_interactive_object.enter_interactor_area(self)
# Removing sword
_owner.queue_free()
After that, when sword is removing, Interactor will catch exit_area
signal, that is called by sword. But at this moment sword’s area’s owner is null! And I can’t find appropriate Interactive Object
of this area.
Can anybody tell me, how to workaround this? Maybe somehow catch object’s destroying before area_exited
signal. Thank you in advance!