xRegnarokx I guess the difficulty is if I have nodes sending signals or doing callbacks but aren't in the same scene they just return errors. My understanding is you want the scenes to be able to exist without that. However, I can't connect a signal to something that doesn't yet exist.
I guess is it okay to make seperate scenes that are dependant on other scenes to work? All I've read says it is better that you don't, that is why I was making them all in one scene.
Ah, so that's what's confusing you. Here's how things should be set up, following the principle of object oriented encapsulation I mentioned earlier.
- Nothing inside the scene should call anything outside that scene
- Nothing outside the scene should call anything inside the scene.
- The scene has no business connecting itself to anything outside of it.
- Nothing outside the scene should connect to signals emitted by nodes inside the scene.
Instead:
- Everything must go through the interface script attached to the top node of the scene.
- The interface script can call only other scripts in nodes "below" it.
- The interface script should define custom signals relevant to the state of the scene, and emit them accordingly.
- Nodes below scene's top node should signal only up to that top node, and leave to it to decide what to do with those signals - either change the scene state and/or re-emit them as custom signals.
- The script that instantiates the scene should take care to connect to signals of interest emitted by the scene.
The intent is to make a self-contained (encapsulated) scene that has an interface which consists of methods that can be called from the outside and custom signals that anyone from the outside can connect to if they're interested in something that the scene could emit. In other words - you're making a "closed-box" component that can be controlled by its methods and reports its state changes by emitting signals. Or you can look at it this way: you made a complicated bunch of nodes behave and handle like a single node.
For example.
You work on a Frogger clone and have the main character Frog scene. This scene consists of an area node, a sprite node and several colliders. The area node, being the top node, has an interface script that defines following methods:
- jump_left()
- jump_right()
- jump_up()
- jump_down()
It also defines custom signals that are emitted when something of importance happens with Frog's state:
- signal jump_done
- signal fly_eaten
- signal home_reached(home_id)
- signal hit_by_car(car_id)
- signal drowned
- signal carried_away_on_log
- signal turtle_dive
- signal time_expired
Now at the start of a level the main Game script instantiates the Frog scene, connects itself to Frog's signals of interest and starts forwarding player input to the Frog, by calling its jump_*()
methods.
The beauty of this is that once you have one functional Frog, you can instantiate as many of them as you wish. They'll all work simultaneously, without any additional coding.
This also facilitates further improvements and additions. New in-scene functionality and new interface methods and signals can be added, without compromising existing communication with the "outside", as long as the interface stays "backward-compatible".