#Need help with coding custom signals

1 messages · Page 1 of 1 (latest)

charred pulsar
#

I've looked at the documentation and at tutorials, I don't feel like I've ever actually absorbed how signals work beyond the most basic implementation of using the Node tab to handle signals within the same scene to itself or a parent object.

Here's my setup:

SceneHandler.tscn is loaded as the root scene. It contains one node with a script on it. Onready it calls the TitleScene, and it plays an animation. When TitleScreen finishes its animation it should call a function in SceneHandler.tscn passing it a packed scene called MenuScreen.tscn, loads it, deletes the TitleScene, and then adds the loaded scene as a child.

It's my understanding I need signals to make this call from a node that has been added as a child like this during runtime, but isn't normally. Trouble is I'm not entirely sure where I need to declare and connect things. The documentation for this is incredibly sparse.

It just says you can "connect them as normal" but I'm trying to connect it to somewhere outside of the current scene, so how does that actually work? Don't I need to have a connect() function somewhere else?

lunar spruce
#

After loading your titlescreen like
var titlescreen = load("you know what goes here")
You can make it call connect like
titlescreen.connect("signal_name", self, "switch_scene")
Where self of course passes a reference of the object attached to the script, scenehandler. switch_scene is supposed to be a function in scenehandler. The object calling connect() needs to have the signal, if the signal is from a child you can have a variable in titlescreen that references the child and call connect like
titlescreen.child.connect(...)
Is this what you had problems with?

charred pulsar
#

Uh, it was mostly where to put the connect function. If I use that, then I don't need to do anything in the Node tab?

lunar spruce
#

Yeah, one connection is enough. They both do the same thing.

charred pulsar
#

So the layout is: SceneHandler loads TitleScreen. SceneHandler then connects TitleScreen with TitleScreen.connect("Requesting_Scene",self,"Scene_Changeover"), and as long as I declare Signal Requesting_Scene(target_scene) and a function called "Scene_Changeover, then I can have TitleScreen emit("Requesting_Scene") and the function Scene_Changeover will happen in SceneHandler?

lunar spruce
#

Yeah, although you left out the argument in some of these examples. But basically.

charred pulsar
#

Yeah it would need to include the packed scene in the call, but I think I'm okay on that

#

Except it's giving me an error on the connect.

#

Here's my code for that: ```func load_first_scene():
var first_scene = preload("res://Scenes/title_scene.tscn").instantiate()
add_child(first_scene)

current_scene = find_child("title_scene")
current_scene.connect("Requesting_Scene",self,"Scene_Changeover")```
#

The error is "Error at (25/46): Invalid argument for "connect()" function: argument 2 should be Callable but is res://scene_handler.gd"

#

I'm using GD4

#

if that changes anything

lunar spruce
#

It might. I'll think on it.

charred pulsar
#

Okay. I really appreciate the help thus far.

lunar spruce
#

I think I remember reading godot 4 uses self differently, yeah. I'll see what I can find.

charred pulsar
#

I need a minute to digest it, but I'll give it a try.

#

In that example I don't really understand where the "hit" property is coming from in "player.hit.connect(_on_player_hit.bind("sword", 100))"

#

or bind() for that matter.

#

Is bind() just a universal method now?

lunar spruce
#

I think those are methods in player. Lile scene.method.connect(signal) not sure, though

charred pulsar
#

Okay. So func _ready(): var button = Button.new() # `button_down` here is a Signal variant type, and we thus call the Signal.connect() method, not Object.connect(). # See discussion below for a more in-depth overview of the API. button.button_down.connect(_on_button_down) is using a property called button_down wihtout declaring it. Is that because it's a prebuilt signal in button? How does that work if I'm declaring the signal in the current code block, and the child I'm creating is supposed to signal back?

lunar spruce
#

Yeah, button down is a signal in button.

#

Oh, actually maybe I got it the wrong way round

#

scene.signal.connect(method)

charred pulsar
#

That'll work even though the scene doesn't actually have the signal inside it?

#

It's in the parent where the code is?

lunar spruce
#

Er. Hm. Probably scene is supposed to have signal, but I don't know where it finds function. Maybe there's a good youtube tutorial explaining how it works now?

charred pulsar
#

I did look, but it's hard to find gd4 stuff specifically

#

Everything that comes up is for gd3.x

lunar spruce
#

Hm, the documentation mostly seems quite clear to me. Just replace .connect(signal, callable, func) with .signal.connect(func)

charred pulsar
#

I get an error on runtume When I do htat

lunar spruce
#

And you don't even have to put the function as a string

#

What's the error?

charred pulsar
#

"Invalid get index 'Requesting_Scene' (on base: 'null instance')." where Requesting_Scene is the name of my signal

lunar spruce
#

Did you remember to write startscreen.signal.connect() ?

#

Or, er, current_scene

charred pulsar
#

This is my code: ```extends Node

This node will be an ongoing handler for juggling scene packages that the game can

be built into. It will create child scenes, have those scenes peform the bulk of the

game, and handle scene transitions when the child scene signals for it.

signal Requesting_Scene(recieved_scene)

@onready @export var current_scene :Node
@export var next_scene :PackedScene

func _ready():
load_first_scene()

func load_first_scene():
var first_scene = preload("res://Scenes/Title_scene.tscn").instantiate()
add_child(first_scene)

current_scene = find_child("Title_scene")
current_scene.Requesting_Scene.connect(Scene_Changeover)

func Scene_Changeover(target_scene) -> void:

print("Successfully Triggered a Scene Change Request")
next_scene = target_scene

var loaded_scene = load(target_scene).instantiate()
add_child(loaded_scene)
current_scene.queue_free()

current_scene = find_child(loaded_scene.name)
lunar spruce
#

Ah, you need to define the signal in the other scene.

charred pulsar
#

But it won't exist when I try to connect to it? I mean, The whole point is to not have to manage the scene transition from the children scenes directly. It gets pushed to here.

lunar spruce
#

Yeah, but the signal is doing the pushing. There is another way though, that I think you'll like more.

charred pulsar
#

Not all the signals are going to exist that I want to connect to, and I don't want to define a hundred different signals for each of my packaged scenes.

#

I'm all ears!

lunar spruce
#

Do you know about singletons?

charred pulsar
#

Yeah.

#

That way I can just reference it globally as a function I can call from anywhere?

lunar spruce
#

You could make your scenehandler one. Then all your scenes can call scene_changeover() directly.

#

Yeah.

#

And instead of adding and deleting children separately, you can use change_scene() (or however it might work in gd4)

charred pulsar
#

I didn't want to mess with that, since I do want some nodes to persist through scene changing and I wasn't sure on how to get it to only change some nodes and not others.

lunar spruce
#

Ah, I made the decision for myself to just have all persisting nodes as singletons. But it's up to you.

charred pulsar
#

I suppose that would simplify some things, but I feel like when I was first learning godot like two years ago I tried doing it that way, and kept on running into errors doing scene transitions, and never got them having a root node that spawns the game. I mostly have either made short one screen games or just given up on projects since then, lol. But it was burned in me that doing it that way can cause weird errors.

lunar spruce
#

Yeah, makes sense.

charred pulsar
#

This is my first attempt at actually trying to make a game with a bunch of rooms you transition between, so this was a giant looming albatross over my project, lol.

#

I am trying it with the singleton now, though.

#

So wait.. how do I create a reference to the sibling node in a Singleton? Can I stil use get_parent()?

#

It seems I cannot...

lunar spruce
#

If your node is called SceneManager.tscn, you'd just write SceneManager.function()

charred pulsar
#

Right, but the Singleton needs to spawn a new scene, and needs to know where to do that.

#

Wiat... is it an issue if I spawn it as a child of a Singleton? I don't think I've ever done that

lunar spruce
#

Oh, I think for that you use get_tree()

lunar spruce
charred pulsar
#

Well. It lets me add it as a child to the singleton....

#

Well. Everything I asked for help here is working. I'm just getting a type error when I call the function in the Singleton to change scenes, but it looks like it's actually calling it.

#

And after some quick debugging, Everything works!

lunar spruce
#

Yay!

charred pulsar
#

Thanks so much for putting up with my incompetence, lol

lunar spruce
#

Ah, it's no big deal. Good luck with Godot 4!