+1 vote

Hi there,

I was able to make code which switches scenes when a KinematicBody enters an Area node. But I also need a line of code that teleports the player when he steps into a different area and it changes the scene but teleports the player to a new spawnpoint.

So something like this:

Player Steps In Scene Changer 1 > Outcome 1 > Location X = 20, Y = 12, Z = 30
Player Steps In Scene Changer 2 > Outcome 2 > Location X = 40, Y= 12, Z = 5
etc.

I do think the outcomes need be scene connected or something like that but I am not sure on that.
for example:

Exits HouseScene1 > Outcome WorldScene2
Enters WorldScene4 > Outcome LevelScene1

this is the code that changes the scene when body has entered the area:

extends Area
var _is_player_in_Area = false
export (String) var player_node_name = "Player"
signal on_player_entered
var _start_new_scene = false
func _ready():
connect("body_entered",self,"_on_Scene_Load")
connect("on_player_entered",self,"_Print_Load");
func _process(delta):
if _is_player_in_Area == true:
emit_signal("on_player_entered")
_start_new_scene = true
get_tree().change_scene("res://Scenes/Scenes 3D/Title Screen/Title/MENU.tscn")
func _on_Scene_Load(other):
if other.name == player_node_name:
_is_player_in_Area = true
func _Print_Load():
print ("Load Scene!");

Thanks for the help :P

in Engine by (21 points)

1 Answer

+1 vote

If you use an autoload or persistent node to manage all your scene changes, it'll make this process easy. Something like:

World
  - Player
  - current_scene
      - house_2

The World node and the current_scene node will never change, they exist solely to carry the current scene the game is displaying, and to manage the scene transitions (done in World)

The way I'd do it is to have each door node have a unique name from every other door in your game, and have them all have a spawn point node as a child. Let's use an example of a town with three houses inside. Each of the doors that are in the town scene are called outerdoor1, outerdoor2, and outerdoor3. The door inside the first house is called innerdoor1, the one in the second house is called innerdoor2, and the third is innerdoor3. The player in currently in house_2, and walks up to the door to go to town. The house door sends a signal to the World node:

signal player_entered_door(scene, door_name)


#After the door has been triggered:
emit_signal("player_entered_door", name)

As long as World is connected to the signal, which you'll have to do on ready for each door, the door that's being triggered will tell the World node exactly which door the player is using to change the scene (by passing its own name).

World can take that name, and compare it to a dictionary of doors, to determine where to spawn the player. Here's a rough example:

var door_dict = {

    "inner_door_1" = {
        "destination" : #put the path to the town scene here ,
        "exit_door" : "outer_door_1"
       }

    "outer_door_1" = {
        "destination" : #put the path to the house_1 scene here ,
        "exit_door" : "inner_door_1"

    #Etc. Etc., fill in the rest of the door and town names here.

       }


func on_player_entered_door(doorname):

    #Transition the scene by first deloading the current_scene child

    $current_scene.get_child(0).queue_free()


    #Then loading your corresponding other scene. 

    var new_scene = doors_dict[doorname]["destination"]
    load_scene(new_scene)


    #And after the scene has loaded, move the player to the corresponding door spawn
    $Player.position = $current_scene.get_child(doors_dict[doorname]["exit_door"]).position

There are better ways to organize your doors_dict, like using sub-dictionaries corresponding to the individual scenes and passing those scene paths when changing scenes, but this demonstrates the basic idea.

by (436 points)

This looks amazing :P

I have a question or two tho ...
- Where do I need to place the code in (like in which of my nodes)?
because I am not really sure which nodes, like the doors, need the script atached.

  • How does my hierarchy need to look like?
    Because that might change the result doesn't it.

My Hierarchy for the Area trigger looks like this:

Spatial (the world) * Has script

  • Area node * Has script
  • -> CollisionShape (Is the Area which gets triggered to swap scenes)

  • KinematicBody (named Player)


    • > CollisionShape

    • > AnimatedSprite3D *Has script


      • > Spatial (For camera focuspoint)



        • > Camera

Thanks for helping out :P

Each door needs a script to detect player entry and then to emit a signal that contains its own name. You can use that same script on every door, or you can have unique scripts for each door that are all extended from the basic door script.

This can work as is if you use an autoload script to change scenes, or if you add another node that's the parent of everything else. Essentially you need to have some script that DOESN'T change when the scene changes. That script is going to be used for passing information from one scene to the next, as you deload and load them.

To give you an example, my game is set up like the following:

World
 - Player
 - current_level

Those nodes ALWAYS exist while the game is being played, no matter what. When the game starts, World has a script that loads the level as a child of current_level, so it looks like:

World
 - Player
 - current_level
     - Level
         - stuff_in_level
         - more_stuff_like_doors

Whenever I want to change the level, I just clear the child (it's only ever 1) of currentlevel from node. the currentlevel node only exists to act as a placeholder to make deloading and loading the game's level easier, all the scripting is located on World.

If you don't want to have a persistent node setup like that, then using an autoload is your best bet for the persisting script. There's more information on that here: https://docs.godotengine.org/en/latest/getting_started/step_by_step/singletons_autoload.html

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.