Character select screen

Godot Version

3.6

Question

I have Character select scene with 3 buttons for each character. One button currently loads level1 on button pressed signal. In level1 I have instanced my 3 characters (they are all kinematicbody2d).

How do I best set up my character select scene script so it loads level1 with just one of the selected characters. Do you make a variable or an identifier for the selected character (global script?) and have the level1 script check what character is selected or can you spawn the selected character directly from the character select scene into the level1 scene? Do you use visibilty or the queue_free() ?

How do you write the code?

Thanks in advance

If only one is visible at all the time it would be straight forward to use one node with 3 meshes and unhinde desired one while two others are hide .

If you have singletons with saving loading logic and multiple looks of meshes it can be expressed there with load only specific nodes in scene .

Currently im controlling all 3 characters at the same time. And I want to only control 1 selected character from my character select screen.

Got these ai-answers:

1. Using a Global Singleton (Autoload)

This is the most common approach for scene-to-scene persistence.

  • Create a Global Script (GameManager.gd): Add it to Project Settings → Autoload.

  • Store Player Selection: In the script, hold a variable: var selected_player = "res://player1.tscn".

  • Load Player: In your game level’s _ready() function, instantiate the saved path:

var player_scene = load(GameManager.selected_player).instantiate()
add_child(player_scene)
player_scene.global_position = $SpawnPoint.global_position

2. Instantiating in the Scene
If you prefer not using autoloads, you can pass the player scene path directly when switching scenes.

var next_scene = load(“res://level.tscn”).instantiate()
var player = load(“res://player1.tscn”).instantiate()
next_scene.add_child(player)
get_tree().root.add_child(next_scene)
get_tree().current_scene = next_scene

3. Placing Player at Specific Points
To ensure the player spawns correctly:

Use Node2D/Node3D Markers: Place a node named SpawnPoint in your scene where the player should appear.
Set Position: In the player’s _ready() function, set their position to that marker’s position.

If I understand it correctly all three exist in scene and you want to limit control to one at the time but keep other exist in scene ?

Maybe simplistiest be make Boolean for each player input and just make it true while other two be false ,

2 Likes

Just want to control one character at a time. Maybe be able to switch between characters in the scene. And maybe when a characters dies be taken back to the character select screen to be able to select from the remaining characters.

So I would be just making singleton for this purpose and get those three booleans there and make it switchable .

if player_one_input == true :
character_one = true
character_two = false
character_three = false

Rest should be in each of your input script defined to allow control if character_one,two,three is true then your control logic is executed else pass

.

1 Like

Ok how Do I write the code for the Global script, level1 and code for the button press on character select scen?

Found this thread:

Maybe it will work?

Depends what mechanics you plan to use ,and what is your existing code doing and where it’s attached .
Singleton will create you access from player and level script , button is quite simple can call for you your made function for player1,2,3 and in player script you can update singleton value or singleton from button .

Ok I have:

character_select.tscn

character_select.gd

Code with connected signals:

(cant seem to add intendentions here)

func _on_Character1Button_pressed():
get_tree().change_scene(“res://level_1.tscn”)

func _on_Character2Button_pressed():

pass

func _on_Character3Button_pressed():


pass

Character1.tscn

Character1.gd

Character2.tscn

Character2.gd

Character3.tscn

Character3.gd

level_1.tscn

level_1.gd

Global.gd

Agreeing with iOSxcOder.

You dont really need to have all three characters loaded in at the start. Its like when you cook for example. You dont start with a table filled with all ingredients and then return the ones you dont need to the fridge. Just spawn in what you need.

Simple solution:

Create a singleton script. If you dont know how, google it. It is easy.

In the singleton, create an array or dictionary in which you store the various character scenes, as packedscenes. Also add an empty variable "selected_character” or something like that.

In the character select screen code, pick a character from the array and assign it to “selected_character” when you press the corresponding button. You can access the singleton and variables from the character select screen by writing the name of the autoload plus a . and then the variable name. Example singleton.selected_character = singleton.character_array[0]

In the level root node or anywhere else, in the ready function, access the variable in the same way, instantiate it and add it to the scene tree. Position it at some spawn point node.

Haha :grinning_face_with_smiling_eyes: makes sense.

I have my Global.gd which autoloads.

How do I create an array or dictionary for character scenes as as packedscenes?

How do i add “selected_character” as an empty variable? “var = selected_character”?

Yes correct!

Var selected_character is enough

Then, to get the packed scenes pull them from the file registry into the scrip. They will become variables.

Then var character_array = [ the variable names you got from pulling the character scenes into the script, separated by comma]

Now you have an array with all the packedscenes. To access them, just write character_array[0] to get the first entry, 1 to get the second entry etc. Arrays start at 0 not 1.

So from the root just write var character = Global.selected_character

Var instance = character.instantiate()

Instance.position = just drop a regular node where you want and use that node’s position as a spawn point by writing $node.position or whatever name the node has.

Get_tree().add_child(instance)

@baba

So this is what I got so far:

In my Global.gd:

var selected_character

var character_array = [“res://Character1.tscn”, “res://Character2.tscn”, “res://Character3.tscn”]

In my level_1.gd:

func _ready():

var character = Global.selected_character

var instance = character.instantiate()
instance.position = $CharacterSpawnArea.position

get_tree().add_child(instance)

In my character_select.gd:

func _on_Character1Button_pressed():

Global.character_array[0]

get_tree().change_scene("res://level_1.tscn")

I get this error when I try to run the game:

“Invalid call. Nonexistent function ‘instantiate’ in base ‘Nil’.”

You need to pass value to selected_character because it’s empty so there is nothing to instantiate.


Global.selected_character = load(Global.character_array[0]

This should fix it

1 Like

Yes as iOSxcOder says you have only created the selected_chsracter variable. You also need to assign a character to it when you press the select button.

The line you have in your button script doesnt do anything right now. It just looks what is inside the first index in the array but doesnt do anything with it.

Global.character_array[0]

You need to do something like what iOSxcOder suggested above.

1 Like

I changed my character_select.gd to:

func _on_Character1Button_pressed():

Global.selected_character = load(Global.character_array[0])

get_tree().change_scene(“res://level_1.tscn”)

But now I get:

Invalid call. Nonexistent function “instantiate” in base “PackedScene”.

you’re working in Godot 3.6, correct?
The function is called instance()here, not instantiate. See: PackedScene — Godot Engine (3.6) documentation in English

You can avoid these problems easier if you use static typing. With this, Godot can suggest you which kind of properties / methods are available and show you errors before you run the game

Yes im working in godot 3.6

Would this work?

var character = Global.selected_character

var instance = character.instance()
instance.position = $CharacterSpawnArea.position

get_tree().add_child(instance)

Update:

Did not work.

Invalid call. Nonexistent function “add child” in base “SceneTree”