Trying to make the player when the retry button is pressed

Godot Version

4.2.1

Question

Hello. I am trying call the respawn_player() function in the BaseScene script that is attached to the level scene, when pressing the retry button in the GameOver screen, but when I type that in the code I get this error messege


I can’t figure out what it is that I am doing wrong or if I am messing something what do I need to do?

BaseScene Script:

class_name BaseScene extends Node

@onready var player: Player = $Player
@onready var camera = $FollowCam
@onready var entrance_markers: Node2D = $EntranceMarkers
@export var startingPos: Marker2D


# This input event is for testing.
func _input(event):
   if Input.is_action_just_pressed("retry"):
   	respawn_player()

# Called when the node enters the scene tree for the first time.
func _ready():
   if scene_manager.player:
   	if player:
   		player.queue_free()
   		
   	player = scene_manager.player
   	add_child(player)
   	camera.follow_node = player
   	
   position_player()


func position_player() -> void:
   var last_scene = scene_manager.last_scene_name
   if last_scene.is_empty():
   	last_scene = "any"
   
   for entrance in entrance_markers.get_children():
   	if entrance is Marker2D and entrance.name == "any" or entrance.name == last_scene:
   		player.global_position = entrance.global_position


func respawn_player() -> void:
   player.global_position = startingPos.global_position

GameOver screen script:

extends Control

signal opened
signal closed

var isOpen: bool = false


func open():
	visible = true
	isOpen = true
	opened.emit()


func close():
	visible = false
	isOpen = false
	closed.emit()


func _on_retry_button_pressed():
	close() # Closes the GameOver screen UI.
	PlayerHealth.set_health_to_max()
	BaseScene.respawn_player() # This line here, is highlighted in red.


func _on_quit_button_pressed():
	get_tree().quit()

To call function respawn_player you need to have an instance of BaseScene class in your GameOver script. These are called static functions. In this case BaseClass is considered not as variable of type BaseClass, but as class type, so Godot tries to call respawn_player function as static.

Add the BaseScene script in autoloads and remove the class_name

Hey jayd1os,

The issue here is that you are trying to call respawn_player() from the BaseScene class itself, not an instance of it. You will have to create a reference to the instance of BaseScene inside the GameOver script and then you will be able to call the function. To do that, you can use @export or the get_node() function, for example.

Isn’t that going to break the script if I do that?

This is still very vague. What do I need type in the code with get_node()??

Could you share your project structure and autoloads section?

Yes, here are the autoloads

Is the BaseScene a node in tree? If so, could it be made an autoload? If yes, then the answer from @KingGD would be right (but as said, you have to remove class_name section to avoid conflicts between autoload node and class name).

I have a scene called ‘world’ that is where the BaseScene script is attached, all the levels are inherited from world scene
Skærmbillede 2024-05-30 200925

Okay I see World node does have references to its children, so is it possible to add reference to the BaseScene node via @export annotation in GameOver script?

Like this?

@export var baseScene: BaseScene 
1 Like

I tried using the exported variable, but then when I press the retry button I get this error messege and the game crashes

func _on_retry_button_pressed():
	close() # Closes the GameOver screen UI.
	PlayerHealth.set_health_to_max()
	baseScene.respawn_player()

Skærmbillede 2024-05-30 204321

Did you assign World in the inspector? Where is your GameOver script attached?

I can’t assign World in the inspecter, when I click on assign it only points to all the children that are in the GameOver screen control node, I can’t drag over the world node either

Then as a quick (I’m not sure if it’s the proper way of doing things) solution I see creating another Mediator autoload, so World and GameOverScreen could communicate with each other without coupling. It has got more of design problem…

Sorry to bother you, but I am out of words, I really don’t know what to do… I am still new to Godot

Here is solution (checked by myself):

BaseScene script:

class_name BaseScene
extends Node2D

# your properties

func _ready():
	Mediator.base_scene = self

	# your code of _ready function

# your functions

func respawn_player() -> void:
	player.global_position = startingPos.global_position

GameOverScreen script:

extends Control

# your code

func _on_retry_button_pressed():
	close() # Closes the GameOver screen UI.
	PlayerHealth.set_health_to_max()
	Mediator.retry()

mediator.gd (must be an autoload with name Mediator):

extends Node

var base_scene: BaseScene

func retry():
	base_scene.respawn_player()

Here GameOverScreen notifies Mediator that event occured and Mediator delegates work to World node (BaseScene instance). If you have further questions feel free to ask!

1 Like

you could use the root if this “World” is your main scene.

get_node("/root/World").respawn_player()
# or
get_tree().root.get_node("World").respawn_player()

It’s kind of like how autoloads work under the hood, without automatically being instantiated forever.

I just tried out the solution, it seems to have solved issue atleast for now.

Thanks for the help :+1: