Player node not being detected not matter what I do

Godot Version

Godot 4.2.1 Stable

Question

How do I call my player node from somewhere else? I’ve been able to call the player node from the “Room” scene, but not from the “RoomPoint” scene, which is a child of the room scene. The room scene is on the same level as the player scene, as they both exist in the “world” scene. So I don’t know why it isn’t working. I’ve tired the following ways.

@onready var player = $Player 

As well as:

@onready var player = $"../Player"

Also:

@onready var player = get_node("Player") 

I’ve even tried setting the player node as a unique path and doing:

@onready var player = %Player 

and no matter what, it will always return null.

The heirachy is as follows:

World
->Player
->Room
–>RoomPoints (Default Node for organization)
—>RoomPoint (Actual Marker3D Calling the script)

Any help would be greatly appreciated. Thank you

$Player is getting a node called Player which is beside the current node. You need to use $../Player to get a node called Player which is beside the parent (which is ..).

Node path is using a relative path, .. means get the parent, Node1/Node2 means get the Node2, which is the child of Node1.

It’s a better solution to store the Player node in the World, and get the World with get_tree().current_scene.

Thanks for the information! I ended up using a get_parent() chain to get the node successfully.

Actually, get_parent().get_node("Player") will be the same as get_node("../Player")

1 Like

If my game is small and has one player or I’m prototyping, I tend to register a global reference.
I create a script called global.gd
Then create an Autoload

The laziest way (no setters, getters, nothing) is this code in the Global class

extends Node

var player

And then, on my player script register it as soon as it’s ready.

func _ready():
	Global.player = self

That’s it. Then I can access it from all over my game as Global.player. Problem solved.

I know, I know, “global variables bad”. But if your game is small, and you’re having trouble trying to reference the player through a complicated hierarchy of nodes and collision shapes, and area2ds… this might save you a few headaches. I mean, if you’re doing stuff like $“…/…/…/Player” it’s not pretty. A Global reference is cleaner, easier to refactor if for some reason in the future your project grows and you’ll never have to worry about complicated references. And if you want more “control” over that variable, you can use a setter and getter for validation and define the class name.

We could have a better “global variable”, we can use a static variable in the World’s script:

# This represents the World script
extends Node2D
class_name World // This makes a type for this script

static var player: Node // You might want it to be Node2D or Player if you have
# This represents the player's script
func _init() -> void:
    # We can use "World" because of the "class_name World" in the World script
    World.player = self

I’ve solved the issue thank you

Yep, that too. I tend to add it to Global because I tend to have a few more things there, and I don’t want to overload the World scene. Like the camera pointer, or another useful reference. Not too much, just 2 or 3 things enough so it’s comfortable to work with but without creating spaguetti code.

In fact, in other engines they do use global variables as a standard under the hood, if you’ve ever heard of Camera.main you know what I’m talking about.

1 Like

Yeah, and store it in public Camera mainCamera;

Hey, if you guys feel like still being helpful, can you check out my latest blog post? Thanks

Use @export, you can assign the player from the scene tree in the Inspector.

1 Like

I often use @export to reference nodes instead of node path, when the node’s hierarchy position is not quite consistent, which means I will often re-parent it to other nodes.