Global Variable changing the root of my node

For some reason, whenever I try to make my player’s speed a global variable, it change the root of my head and camera nodes.

I don’t think i’ve EVER seen anyone else with this problem so how in the world do I fix this? Thanks.

extends CharacterBody3D


@export var speed = 7.0
@export var sprint_speed = 14.0
const JUMP_VELOCITY = 4.5
@onready var head: Node3D = $head
@onready var camera_3d: Camera3D = $head/Camera3D




func _ready() -> void:
	Input.mouse_mode = Input.MOUSE_MODE_CAPTURED


	


# First person
func _input(event: InputEvent) -> void:
	if event is InputEventMouseMotion:
		rotate_y(deg_to_rad(-event.relative.x * 0.5))
		head.rotate_x(deg_to_rad(-event.relative.y * 0.5))
		head.rotation.x = clamp(head.rotation.x, deg_to_rad(-90), deg_to_rad(45))
		

	
	



	
	

	


func _physics_process(delta: float) -> void:
	# Add the gravity
	if Input.is_action_pressed("Crouch"):
		head.position.y = lerp(0.0, delta * -2.0, 3)
		print("crouch")
	else:
		head.position.y = 0.0

	
	


	

	if not is_on_floor():
		velocity += get_gravity() * delta
	
	if Input.is_action_pressed("Space") && is_on_floor():
		velocity.y += 4
	if Input.is_action_pressed("Shift"):
		speed = sprint_speed
	else:
		speed = 4
	
	

	# Get the input direction and handle the movement/deceleration.
	# As good practice, you should replace UI actions with custom gameplay actions.
	var input_dir := Input.get_vector("A", "D", "W", "S")
	var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
	if direction:
	
		velocity.x = direction.x * speed
		velocity.z = direction.z * speed 
	else:
		
		velocity.x = move_toward(velocity.x, 0, speed)
		velocity.z = move_toward(velocity.z, 0, speed)
		
	move_and_slide()
	

	
	
	
const BOB_FREQ = 1.5
const BOB_AMP = 0.04
var t_bob = 0.0
 
func _process(delta):
	t_bob += delta * velocity.length() * float(is_on_floor())
	camera_3d.transform.origin = headbob(t_bob)
  
func headbob(time) -> Vector3:
	var pos = Vector3.ZERO
	pos.y = sin(time * BOB_FREQ) * BOB_AMP
	pos.x = cos(time * BOB_FREQ / 2) * BOB_AMP
	return pos

Don’t make it global.

but I NEED to, I want it to display on my UI

You don’t really. There are other ways to achieve what you need.

Note that you don’t have full understanding of what happens when you make a script “global”. Look at the docs section on autoloads.

When you set a script up as an autoload, you shouldn’t run the same script regularly in the scene because then you’ll end up with two instance of the script running at the same time and the instance that’s set up as an autoload will not have the expected scene structure underneath it. It will just be a single node attached to root, trying to run the script.

Just make a separate script global with all the data you want to display, or get access to the data some other way. No reason to make everything global. Not sure why it glitches out though but even if it did not glitch out, i wouldn’t recommend making an entire script global just to get access to one of the properties.

It glitches because the script is trying to access children nodes that are not there.

Ah yes of course.

Alright thanks.

What “other” ways do you have in mind?

As @baba already mentioned, make a dedicated autoloaded script that only holds a reference to the player node. This reference would then be globally available to anyone who needs it.

well now this happens.

Is this a script that’s set up as autoload? If yes, let the player script store a reference to self into it from its _ready().
Not sure why you used rich text label though.

The error persists, i’m using the text label in order to display my player’s speed variable to the screen with UI.

Yeah but that shouldn’t be an autoload. Extend plain Node class for an autoload.

$"." means “this node” which would refer to the rich text label in both lines 2 and 3, and since 3 is expecting a CharacterBody3D it fails.

Don’t always rely on dragging and dropping into the script editor, it’s wrong often enough to cause issues.


If you want a always present player variable, have the var as part of the global script, don’t assign it, let the player script assign it to themselves

# global script
extends Node

var player: Player

# player script
extends CharacterBody3D
class_name Player

func _ready() -> void:
    GlobalNode.player = self

Ok nevermind, I just found a way simpler solution. I just converted the speed variable into a string, and added it to the player script, apologizes for the wasted time.

image

For next time, make sure to explain your root problem. We need to know what you expected to happen versus what really happens, and the big picture of what you are trying to do.

This is a great example of an XY problem.

Additional suggestions, if you are interested.

If you are casting and updating the value of the text prop within any _process methods, then notice that it will happen many frames a second, even when the speed doesn’t change.From what I see in your code, you have two speeds. You can add a signal within your player node which emits whenever the speed changes. Then from within your text label node connect that signal and invoke a text update function. That will make sure the update is done only when needed.

Other thing, the velocity and speed are decoupled. Meaning the speed displayed will be different from your velocity. If you want to be more precise, then you should show the velocity.