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