You know, personally I like to create my own EventManager, that is a static (global) singleton, and then use it to "listen", "ignore" and "raise" string named events, with arbitrary (dynamically constructed) parameter objects (which can be null). It's not appropriate for things that're going to be happening many times per frame, but it's good for the vast majority of purposes.
The thing about C#'s events and GDScript's signals that falls down for me is that in order to connect up an event to a handler I have to have a reference to the object raising the event (or signalling the signal). And/or I have to declare the event delegate, et etc. I prefer to be able to simply listen for any string named event I want, anywhere in my whole code base, and raise that event anywhere else, without the listener (signaller) needing to know or care anything about the raiser (emitter), and vica versa.
I've done this in Python, PHP, JavaScript, C#, and now tonight I just did it again in GDScript. Here's my EventManager script:
extends Node
var listeners = {}
func _ready():
pass
# void listen(string event, funcref callback)
# adds a function reference to the list of listeners for the given named event
func listen(event, callback):
if not listeners.has(event):
listeners[event] = []
listeners[event].append(callback)
# void ignore(string event, funcref callback)
# removes a function reference from the list of listeners for the given named event
func ignore(event, callback):
if listeners.has(event):
if listeners[event].find(callback):
listeners[event].remove(callback)
# void raise(string event, object args)
# calls each callback in the list of callbacks in listeners for the given named event, passing args to each
func raise(event, args):
if listeners.has(event):
for callback in listeners[event]:
callback.call_func(args)
I have that set up in the "autoloads" part of the project settings, so it's globally accessible. Here is an example of listening for and raising events using this:
..
func updateDirectionOfFacing():
var x = Input.get_joy_axis(0, 0) # left joystick horizontal axis
var y = Input.get_joy_axis(0, 1) # left joystick vertical axis
var d = getDirection(x,y) # returns null if x and y are both 0, corrects for everything else
EventManager.raise("user_message", "x: %f, y: %f, d: %f" % [x, y, coalesce(d, 0.0)])
if (d != null):
dof = d
var rb = self.get_parent() # this script is on the mesh, which has a rigidbody as a parent
rb.set_rotation_deg(Vector3(0, dof, 0))
pass
..
extends Label
func _ready():
EventManager.listen("user_message", funcref(self, "on_user_message"))
func on_user_message(message):
self.set_text(message)