Godot Version
4.2
Question
Ok, here’s the scenario. I recently wrote a temperature system for my game. I got it working to a certain extent, but I wanted the system to be easier to use, for things in my game to be able to be both temperature sources and receivers, and for temperature objects to not need to be created at the time the scene tree was opened and so on. I decided to create a temperature singleton that would receive data about temperature reactants and then, upon request, pass them along to temperature reactants.
Currently my temperature reactants are only partially connecting to the singleton. I’m not sure why, but some of my signals are failing to connect.
my exact two errors are:
temperature.gd:50 @ _connect_to_global(): In Object of type 'Node3D': Attempt to connect nonexistent signal 'provide_data' to callable 'Node3D(temperature.gd)::global_recieved
and
temperature.gd:51 @ _connect_to_global(): Error calling from signal 'register+heat' to callable: 'Node3d(Globals.gd)::register_heat': Cannot convert argument 1 from Object to Callable
The second one makes even sense to me, because at no point have a passed the type Callable into the signal constructor.
By using print() as proof of execution of some of my functions, I have confirmed that the call to the group “Unregistered Heat” works fine.
the code for Globals.gd (the singleton for temperature)
extends Node3D
var request_timer = null
var heat_objects = []
var heat_recievers = []
var heat_sources = []
signal provide_data(target, heat_recievers, heat_sources)
func _ready() -> void:
request_timer = Timer.new()
add_child(request_timer)
request_timer.set_wait_time(.5 + (randf() * .1))
request_timer.timeout.connect(search_for_heat.bind())
request_timer.start()
func information_requested(target : Callable, heat_recievers_requested : bool, heat_sources_requested: bool):
if heat_recievers_requested and heat_sources_requested:
provide_data.emit(target, heat_recievers, heat_sources)
elif heat_recievers_requested:
provide_data.emit(target, heat_recievers, null)
elif heat_sources_requested:
provide_data.emit(target, null, heat_sources)
func register_heat(heat : Callable, is_heat_reciever : bool, is_heat_source : bool):
heat_objects.append(heat)
if is_heat_reciever:
heat_recievers.append(heat)
if is_heat_source:
heat_sources.append(heat)
func deregister_heat(heat : Callable):
heat_objects.erase(heat)
heat_recievers.erase(heat)
heat_sources.erase(heat)
func search_for_heat():
print("Searching started")
request_timer.set_wait_time(.5 + (randf() * .1))
for i in get_tree().get_nodes_in_group("Unconnected_Heat"):
i.connect("register_heat", register_heat)
get_tree().call_group("Unconnected_Heat", "_connect_to_global")
print("Searching finished")
and the code for the temperature reactants is here
extends Node3D
@export_group("Tempurature Reactivity")
@export_subgroup("Temperature Source Settings")
@export var Source := true
@export var heat_radius = 1.0
@export var decay_per_meter = 1.1
@export var heat_strength = 1.0
@export_subgroup("Temperature Reciever Settings")
@export var Reciever := true
@export var freezable := false
@export var burnable := false
@export var heat_tolerance := -100.0
@export var cold_tolerance := 100.0
#Connection to the singleton
signal register_heat(broadcaster, is_heat_reciever, is_heat_source)
signal deregister_heat(broadcater)
var origin = Vector3(0,0,0)
signal modify_heat(heat_modifier, target)
@onready var heat_recievers := []
var heat_sources := []
var heat_modifier = 0.0
var timer = null
var connection_timer = null
var size := Vector3(0,0,0)
var coldness = 0
var connected_to_global = false
enum reported {COLD, HEAT, DEFAULT}
signal temperature_tolerance(exceeded_value)
signal temperature_report(coldness)
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
add_to_group("Unconnected_Heat")
origin = get_parent().get_position()
size = get_parent().get_scale()
if Source:
initialize_source()
if Reciever:
initialize_reciever()
#global connections
func _connect_to_global():
remove_from_group("Unconnected_Heat")
print(get_parent(), " connected to global")
$".".connect("provide_data", global_recieved)
register_heat.emit(get_parent(), Reciever, Source)
func global_recieved(target, recievers, sources):
if target == self.get_parent():
heat_recievers = recievers
heat_sources = sources
#Initialization functions
func initialize_source():
get_parent().add_to_group("Heat Sources")
$Area3D/outer_layer.shape.set_radius(heat_radius)
$center.position = origin
$center.scale = size
timer = Timer.new()
add_child(timer)
timer.set_wait_time(1.0 + (randf() * .01))
timer.timeout.connect(distribute_heat.bind())
timer.start()
func initialize_reciever():
get_parent().add_to_group("Heat Reciever")
for i in get_tree().get_nodes_in_group("Heat Sources"):
i.find_child("Temperature Reactivity").connect("modify_heat", modify_own_heat)
set_scale(size)
set_position(origin)
#Modifier functions
func _on_area_3d_area_entered(area: Area3D) -> void:
if area.get_parent().is_in_group("Heat Reciever"):
heat_recievers.append(area.get_parent_node_3d())
func _on_area_3d_area_exited(area: Area3D) -> void:
if area.get_parent().is_in_group("Heat Reciever"):
heat_recievers.remove_at(heat_recievers.find(area.get_parent_node_3d()))
func distribute_heat():
if heat_recievers.size()>0:
for i in heat_recievers:
heat_modifier = heat_strength / abs(i.get_position().distance_to($center.get_position()) * decay_per_meter)
modify_heat.emit(heat_modifier, i)
#Reciever functions
func modify_own_heat(heat_modifier: Variant, target: Variant) -> void:
if target == get_parent():
coldness -= heat_modifier
temperature_report.emit(coldness)
evaluate_heat()
func evaluate_heat():
if (coldness <= cold_tolerance and freezable):
temperature_tolerance.emit(0)
elif (coldness>= heat_tolerance and burnable):
temperature_tolerance.emit(1)
else:
temperature_tolerance.emit(2)
#getters and setters
func set_reciever(new_status: bool):
Reciever = new_status
func set_source(new_status: bool):
Source = new_status
func set_heat_tolerance(new_heat: float):
heat_tolerance = new_heat
func set_cold_tolerance(new_cold: float):
cold_tolerance = new_cold
func get_heat_recievers():
return heat_recievers
func get_cold_tolerance() -> float:
return cold_tolerance
func get_heat_tolerance() -> float:
return heat_tolerance
func _on_tree_exiting() -> void:
deregister_heat.emit(get_parent())
connected_to_global = false
Any help would be much appreciated . I’ve tried to make my code pretty readable; however, if you need me to elaborate, just let me know. btw, I should mention that I have already double-checked that the singleton is autoloaded.