Invalid assignment of property or key 'global_position' with value of type 'Nil' on a base object of type Node2D

Godot Version

Godot 4

Question

Hello, Im following a guide on how to make an invader style game on youtube and Ive been encountering this error: Invalid assignment of property or key ‘global_position’ with value of type ‘Nil’ on a base object of type ‘Node2D (ZombieShot)’ in invader_spawner.gd. I know that line of code is to randomize the projectile position and it is supposed to return a random array value but when I printed the array value it returns null. Why does it return null instead of returning anything?

invader_spawner.gd:

extends Node2D

class_name InvaderSpawner

const ROWS = 5
const COLUMNS = 11
const HORIZONTAL_SPACING = 32
const VERTICAL_SPACING = 32
const INVADER_HEIGHT = 24
const START_Y_POSITION = -50
const INVADERS_POSITION_X_INCREMENT = 10
const INVADERS_POSITION_Y_INCREENT = 20

var movement_direction = 1
var enemy_scene = preload("res://enemy.tscn")
var zombie_shot_scene = preload("res://invader_shot.tscn")

@onready var movement_timer = $Timer
@onready var zombie_shot = $Zombie_Shoot

func _ready():
	movement_timer.timeout.connect(move_invaders)
	zombie_shot.timeout.connect(on_invader_shot())
	
	var invader_1_res = preload("res://Resources/invader_1.tres")
	var invader_2_res = preload("res://Resources/invader_2.tres")
	var invader_3_res = preload("res://Resources/invader_3.tres")
	
	var invader_config
	
	for row in ROWS:
		if row == 0:
			invader_config = invader_1_res
		elif row == 1 || row == 2:
			invader_config = invader_2_res
		elif row == 3 || row == 4:
			invader_config = invader_3_res
	
		var row_width = (COLUMNS * invader_config.width * 3) + ((COLUMNS - 1) * HORIZONTAL_SPACING)
		var start_x  = (position.x - row_width) / 2
	
		for col in COLUMNS:
			var x = start_x + (col * invader_config.width * 3) + (col * HORIZONTAL_SPACING)
			var y = START_Y_POSITION + (row * INVADER_HEIGHT) + (row * VERTICAL_SPACING)
			var spawn_position = Vector2(x, y)
			
			spawn_invader(invader_config, spawn_position)
		
func spawn_invader(invader_config, spawn_position: Vector2):
	var invader = enemy_scene.instantiate() as Enemy
	invader.config = invader_config
	invader.global_position = spawn_position
	add_child(invader)

func move_invaders():
	position.x += INVADERS_POSITION_X_INCREMENT * movement_direction


func _on_left_wall_area_entered(area: Area2D) -> void:
	if (movement_direction == -1):
		position.y += INVADERS_POSITION_Y_INCREENT
		movement_direction *= -1


func _on_right_wall_area_entered(area: Area2D) -> void:
	if (movement_direction == 1):
		position.y += INVADERS_POSITION_Y_INCREENT
		movement_direction *= -1

func on_invader_shot():
	var random_child_position = get_children().filter(func (child): return child is Enemy).map(func (invader): return invader.global_position).pick_random()
	print(random_child_position)
	
	var zombie_shot = zombie_shot_scene.instantiate() as ZombieShot
	zombie_shot.global_position = random_child_position
	get_tree().root.add_child(zombie_shot)

enemy.gd:

extends Area2D

class_name Enemy

@onready var sprite_2d = $Graphics/Alive
@onready var animation_player = $AnimationPlayer

var dead = false
var config: Resource

func _ready() -> void:
	sprite_2d.texture = config.sprite
	animation_player.play(config.animation_name)

func _physics_process(delta):
	if dead:
		return

func kill():
	$DeathSound.play()
	$Graphics/Alive.hide()
	$Graphics/Dead.show()
	queue_free()


func _on_body_entered(body: Node2D) -> void:
	if "Bullet" in body.name:
		kill()


func _on_area_entered(area: Area2D) -> void:
	if "BulletArea" in area.name:
		kill()

invader_shot.gd:

extends Node2D

class_name ZombieShot

@export var speed = 200

func _process(delta):
	position.y += speed * delta

what does this method print? because apparently random_child_position is null.
This assignment looks very suspicious to me, are you sure it works correct?

1 Like

oh i printed that for testing. i just wanted to see if the random_child_position value is empty or not

And is it empty?

yea it returned null

And thats the problem. You have to make sure that the method stops with “return” when its null or assign a valid position to random_child_position

It’s most likely pick_random() returns null because it’s used on an empty array. Which means either get_children() returns an empty array, or non of the children are Enemy and they all get filtered out.
You could try printing what each of those return individually:

print(get_children()
print(get_children().filter(func (child): return child is Enemy))

Do you get the error immediately when you launch the game?

Nvm, i fixed it, apparently there was a typo when i called the timer’s timeout

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.