Invalid get index 'global_position'(on base:'null instance')

Godot Version

Gadot-4

Question

I am making a function that comes up with a random position along the outside of the screen for a spawning system in my 2D game and I am getting the error

Invalid get index ‘global_position’(on base:‘null instance’)

Here is the code

func get_random_position():

var vpr = get_viewport_rect().size * randf_range(1.1,1.4)#reusable script for off the screen
var top_left = Vector2(player.global_position.x - vpr.x/2, player.global_position.y - vpr.y/2)#var to teach the sides of the screen to computer
var top_right = Vector2(player.global_position.x + vpr.x/2, player.global_position.y - vpr.y/2)
var bottom_left = Vector2(player.global_position.x - vpr.x/2, player.global_position.y + vpr.y/2)
var bottom_right = Vector2(player.global_position.x + vpr.x/2, player.global_position.y - vpr.y/2)
var pos_side = ["up","down","left","right"].pick_random()#picks random side
var spawn_pos1 = Vector2.ZERO
var spawn_pos2 = Vector2.ZERO

# pikes a side and range of coordinates
match pos_side:
	"up":
		spawn_pos1 = top_left
		spawn_pos2 = top_right
	"down":
		spawn_pos1 = bottom_left
		spawn_pos2 = bottom_right
	"left":
		spawn_pos1 = top_left
		spawn_pos2 = bottom_left
	"right":
		spawn_pos1 = top_right
		spawn_pos2 = bottom_right
		
var x_spawn = randf_range(spawn_pos1.x, spawn_pos2.x)
var y_spawn = randf_range(spawn_pos1.y, spawn_pos2.y)
return Vector2(x_spawn, y_spawn)

Which line has the error?

Apparently, player isn’t defined.

2 Likes

On the second one

@onready var player = get_tree().get_first_node_in_group(“player”)

it is at the begining I don’t show the whole script

Here is the whole thing

extends Node2D

@export var spawns: Array[Spawn_info] =

@onready var player = get_tree().get_first_node_in_group(“player”)

var time = 0

func _on_timer_timeout():
print(“works”)
time += 1
var butterfly_spawns = spawns
for i in butterfly_spawns:
if time >= i.time_start and time <= i.time_end:

		if i.spawn_delay_counter < i.butterfly_spawn_delay:
			i.spawn_delay_counter += 1#add one to delay of next butterfly
			
		else:#if it is, than
			i.spawn_delay_counter = 0
			var new_butterfly = load(str(i.butterfly.resource_path))
			var counter = 0
			while counter < i.butterfly_number:
				var butterfly_spawn = new_butterfly.instantiate()
				butterfly_spawn.global_position = get_random_position()
				add_child(butterfly_spawn)
				counter += 1

func get_random_position():

var vpr = get_viewport_rect().size * randf_range(1.1,1.4)#
var top_left = Vector2(player.global_position.x - vpr.x/2, player.global_position.y - vpr.y/2)
var top_right = Vector2(player.global_position.x + vpr.x/2, player.global_position.y - vpr.y/2)
var bottom_left = Vector2(player.global_position.x - vpr.x/2, player.global_position.y + vpr.y/2)
var bottom_right = Vector2(player.global_position.x + vpr.x/2, player.global_position.y - vpr.y/2)
var pos_side = ["up","down","left","right"].pick_random()
var spawn_pos1 = Vector2.ZERO
var spawn_pos2 = Vector2.ZERO

# pikes a side and range of coordinates
match pos_side:
	"up":
		spawn_pos1 = top_left
		spawn_pos2 = top_right
	"down":
		spawn_pos1 = bottom_left
		spawn_pos2 = bottom_right
	"left":
		spawn_pos1 = top_left
		spawn_pos2 = bottom_left
	"right":
		spawn_pos1 = top_right
		spawn_pos2 = bottom_right
		
var x_spawn = randf_range(spawn_pos1.x, spawn_pos2.x)
var y_spawn = randf_range(spawn_pos1.y, spawn_pos2.y)
return Vector2(x_spawn, y_spawn)

The player may not be ready by the point this script is ready. Maybe an @export would work better, or waiting for a single frame

var player: Node2D

func _ready() -> void:
    await get_tree().process_frame # wait 1 frame after ready
    player = get_tree().get_first_node_in_group("player")

It’s giving me errors in variable and in the function. For the variable it sais [Unexpected " Indent" in class body] and in the function it sais[Expected end of file]. I also tried switching the Node2D for a CharacterBody2D because my player is a CharacterBody2D but it did not change anything. When I tried to change it to an export it said [Cannot call method ‘get_first_node_in_groupe’ on null value]

As said before, the player node is probably not ready at the point your script is. Did you check the hierarchy of your scene? _ready() is called on children first, then on their parent nodes. Not quite sure about the order between sibling nodes.

You could also get the player inside the function where you need it (assuming the function is called at some point after the whole scene has been initialized).

did you indent the variable? It sounds like white space problems, like you copied and pasted the code without properly indenting it.

gdscript cares about the whitespace at the start of a line. If it is indented you are saying that line belongs to a function or branch.

var player: Node2D # not indented, not part of any function, a global variable

func _ready() -> void: # not indented
    await get_tree().process_frame # indented, part of the _ready function above
    player = get_tree().get_first_node_in_group("player") # also indented, also part of the function

If you paste your script with proper formatting I can help more,

```
    type or paste code here
```

is displayed as:

    type or paste code here

I check my hierarchy is there anything in particular in should be looking for my player is before the spawner. I don’t get what you mean by get the player inside the function where I need it. Do you mean the variable?

What does indenting a variable mean. Could you explain I am really new.

Ah, sorry. What I meant is, instead of your

@onready var player = ...

at the beginning of the script, you can define the variable at the beginning of your function:

func get_random_position():
    var player = get_tree().get_first_node_in_group(“player”)

Here it is

extends Node2D


@export var spawns: Array[Spawn_info] = []#Array = many variables coupled
var time = 0
var player: Node2D

func _ready() -> void:
	await get_tree().process_frame
	player = get_tree().get_first_node_in_groupe("Player")
	
func _on_timer_timeout():
	print("works")
	time += 1
	var butterfly_spawns = spawns#referance to the array(spawn info)
	for i in butterfly_spawns:
		if time >= i.time_start and time <= i.time_end:#if timer is running
			
			if i.spawn_delay_counter < i.butterfly_spawn_delay:#if delay is bigger NOT than its supposed to
				i.spawn_delay_counter += 1#add one to delay of next butterfly
				
			else:#if it is, than
				i.spawn_delay_counter = 0#reset delay counter so restart cycle
				var new_butterfly = load(str(i.butterfly.resource_path))
				var counter = 0
				while counter < i.butterfly_number:#if missing a butterfly
					var butterfly_spawn = new_butterfly.instantiate()
					butterfly_spawn.global_position = get_random_position()#to make him spawn in random pos
					add_child(butterfly_spawn)#makes a clone(child)
					counter += 1#count the children
					
					
func get_random_position():
	
	var vpr = get_viewport_rect().size * randf_range(1.1,1.4)#reusable script for off the screen
	var top_left = Vector2(player.global_position.x - vpr.x/2, player.global_position.y - vpr.y/2)#var to teach the sides of the screen to computer
	var top_right = Vector2(player.global_position.x + vpr.x/2, player.global_position.y - vpr.y/2)
	var bottom_left = Vector2(player.global_position.x - vpr.x/2, player.global_position.y + vpr.y/2)
	var bottom_right = Vector2(player.global_position.x + vpr.x/2, player.global_position.y - vpr.y/2)
	var pos_side = ["up","down","left","right"].pick_random()#picks random side
	var spawn_pos1 = Vector2.ZERO
	var spawn_pos2 = Vector2.ZERO
	
	# pikes a side and range of coordinates
	match pos_side:
		"up":
			spawn_pos1 = top_left
			spawn_pos2 = top_right
		"down":
			spawn_pos1 = bottom_left
			spawn_pos2 = bottom_right
		"left":
			spawn_pos1 = top_left
			spawn_pos2 = bottom_left
		"right":
			spawn_pos1 = top_right
			spawn_pos2 = bottom_right
			
	var x_spawn = randf_range(spawn_pos1.x, spawn_pos2.x)
	var y_spawn = randf_range(spawn_pos1.y, spawn_pos2.y)
	return Vector2(x_spawn, y_spawn)

I thought this would work but it was still giving me the error. You think waiting a frame after calling the variable would change anything?

And in that case I don’t think white space is the issue.

At a glance, it looks good, so could you edit the code to include comments for where the errors occured?

Here it is

extends Node2D


@export var spawns: Array[Spawn_info] = []
var time = 0
var player: Node2D
# there were some errors in this ready function but i fixed them so there is only the main one left.
func _ready() -> void:
	await get_tree().process_frame
	player = get_tree().get_first_node_in_groupe("Player")
	
func _on_timer_timeout():
	print("works")
	time += 1
	var butterfly_spawns = spawns
	for i in butterfly_spawns:
		if time >= i.time_start and time <= i.time_end:
			
			if i.spawn_delay_counter < i.butterfly_spawn_delay:
				i.spawn_delay_counter += 1
				
			else:
				i.spawn_delay_counter = 0
				var new_butterfly = load(str(i.butterfly.resource_path))
				var counter = 0
				while counter < i.butterfly_number:
					var butterfly_spawn = new_butterfly.instantiate()
					butterfly_spawn.global_position = get_random_position()
					add_child(butterfly_spawn)
					counter += 1
					
					
func get_random_position():
	
	var vpr = get_viewport_rect().size * randf_range(1.1,1.4)
	var top_left = Vector2(player.global_position.x - vpr.x/2, player.global_position.y - vpr.y/2)#HERE IS THE ERROR im assuming it is in the next 3 lines as well because the are nearly identical
	var top_right = Vector2(player.global_position.x + vpr.x/2, player.global_position.y - vpr.y/2)
	var bottom_left = Vector2(player.global_position.x - vpr.x/2, player.global_position.y + vpr.y/2)
	var bottom_right = Vector2(player.global_position.x + vpr.x/2, player.global_position.y - vpr.y/2)
	var pos_side = ["up","down","left","right"].pick_random()
	var spawn_pos1 = Vector2.ZERO
	var spawn_pos2 = Vector2.ZERO

	match pos_side:
		"up":
			spawn_pos1 = top_left
			spawn_pos2 = top_right
		"down":
			spawn_pos1 = bottom_left
			spawn_pos2 = bottom_right
		"left":
			spawn_pos1 = top_left
			spawn_pos2 = bottom_left
		"right":
			spawn_pos1 = top_right
			spawn_pos2 = bottom_right
			
	var x_spawn = randf_range(spawn_pos1.x, spawn_pos2.x)
	var y_spawn = randf_range(spawn_pos1.y, spawn_pos2.y)
	return Vector2(x_spawn, y_spawn)
	
	
	
		

No e at the end
get_first_node_in_group