1
\$\begingroup\$

I'm porting an old BuidBox 2 game to the Godot game engine. I already added all assets and scenes to the Godot project. The game is a 2.5D (isometric) endless runner. What I want now is to add a mechanism to load the next scene offscreen, remove the player's character from the current scene, and add it to the next scene seamlessly, without breaking the game physics or causing the player character to go behind or in front of other game objects that it's not supposed to.

For instance if I have this scenes:

Scene1
|-bg
|-player
└-fg

Scene2
|-bg
|-player
└-fg

I would like to load Scene2, remove player from Scene1 and replace player from Scene2 with the player node I removed from Scene1, without the player node changing its velocity or position abruptly in the physics world or appearing behind the bg node in Scene2 or in front of the fg node in Scene1.

\$\endgroup\$
1
\$\begingroup\$

load the next scene offscreen

Usually we switch scenes with get_tree().change_scene("res://Main.tscn");. We are not going to do that. Instead we will load the new scene as a resource (PackedScene) and then switch.

You can load the scene in a single call of load on the resource_loader, but that could mean a noticeable hiccup.

Instead, you could use background loading as hinted by rawburt.

The abstract is that you load_interative instead of load. Calling load_interative returns a ResourceInteractiveLoader.

Then, on _process call poll on the ResourceInteractiveLoader. Do this until poll returns ERR_FILE_EOF, meaning it is done loading. Meanwhile, you can use get_stage and get_stage_count to know the load progress, for example to show a progress bar.

When loaded, the new scene will be available by calling get_resource of the ResourceInteractiveLoader.


Now, to switch to the new scene, we will mimic change_scene. Simply by instantiating the PackedScene resource, add it the scene tree and remove the old one.

Example:

var root = get_tree().get_root(); # Assuming you want to use the root

# Add the scene level
var next_scene = next_scene_resource.instance();
root.add_child(next_scene);

# Remove the old scene
var scene = root.get_node("Level"); # Node name may vary
root.remove_child(scene);
scene.queue_free();

Where to put that code? You can place it on the scene you will change itself. However, it will be handy to have this code in an AutoLoaded scene. See AutoLoad.


remove the player's character from the current scene, and add it to the next scene seamlessly

Alright, so you will first instantiate the new scene, then remove the avatar from the old scene and add it to the new one, finally you can remove the old scene.

The avatar, just as the scene, is another child in the tree. Remove it from the scene with remove_child. Usually we would then queue free, instead add it to the new scene.

Something like this:

var root = get_tree().get_root(); # Assuming you want to use the root

# Add the scene level
var next_scene = next_scene_resource.instance()
root.add_child(next_level)

# Get the old scene
var scene = root.get_node("Level"); # Node name may vary

# Get the avatar
var avatar = scene.get_node("Avatar"); # Node path may vary

# Remove the avatar from the old scene
scene.remove_child("Avatar"); # avatar.get_parent().remove_child("Avatar");

# Add it to the new one
next_scene.add_child(avatar);

# Remove the old scene
root.remove_child(scene);
scene.queue_free();

without breaking the game physics

Then you probably want to do this in _process_physics instead of _process.

or causing the player character to go behind or in front of other game objects that it's not supposed to

After adding the avatar, you can set its position in the new scene with move_child. Or you can add it directly in the position you want with add_child_below_node.


Be careful with what you put on the _ready of - any of the nodes of - the new scene. If the new scene needs to pre-load something, consider using AutoLoad or doing it lazily.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ That's more or less the approach I'm using at the moment, the only thing I haven't figured out yet is the player's avatar being occluded or occluding objects that it isn't supposed to. For that, I added a player placeholder node in each scene, that I assign the z-index of 0 to, and then assign the z-index for other nodes accordingly so that they are rendered in the right order. \$\endgroup\$ – rraallvv Oct 4 at 14:27
  • \$\begingroup\$ But now I have a similar issue with objects in the old scene occluding some objects in the new one, so I guess I'll have to change dynamically the z-index in the scenes at some point, since both scenes are visible for a while before the old one is completely off-screen. \$\endgroup\$ – rraallvv Oct 4 at 14:27
0
+50
\$\begingroup\$

This resource might help you begin to find a solution https://docs.godotengine.org/en/stable/tutorials/io/background_loading.html

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.