Instantiated nodes unable to access node reference, causing null errors

Godot Version

4.2.1

Question

Hello fellow Godoteers! I’m working on a 3D game where I have a vehicle that when it enters a specific Area3D the main_world.gd triggers a function to instantiate a “3 zombies and a road block” scene . However, I am encountering an issue with the instantiated nodes within the scene not having access to a vehicle reference, resulting in null errors for the zombie FSM (target_in_range) checks.

If I manually move a zombie into the scene everything works fine, which leads me to believe that the instantiated zombie’s do not “see” or have a reference for the vehicle even though it is setup in their script.

For context, I have main_world.gd script attached to the parent node of the scene. When the vehicle enters an Area3D, it triggers the _on_zombie_spawner_area_3d_vehicle_entered_zombie_spawner function. Inside this function, I instantiate zombie_road_block scenes using zombie_road_block_scene.instantiate().

I needed to use @onready var vehicle = $"../Vehicle/vehicle" for the zombie.gd because the zombie was referencing the vehicle node that contained the model, and I changed it so now it uses the model global position.

@onready var vehicle = $Vehicle is the scene node that can been seen in the structure screenshot below.

I have tried to set a global variable and “hard code” the vehicle variable but that breaks more things than it fixes so I need help rethinking about what solution I should use and how to set it up.

When func _on_zombie_spawner_area_3d_vehicle_entered_zombie_spawner(): is called the only print that makes it to output is _on_zombie_spawner_area_3d_vehicle_entered_zombie_spawner called. The later prints get interrupted by the null instance errors.

What additional information can I provide?

Thank you in advance for your help! Cheers!

zombie.gd
# zombie.gd
extends CharacterBody3D

@export_group("Zombie Stats")
@export var movement_speed: float = 4.0
@export var Health = 1

##Zombie was referencing the vehicle node that contained the model, changed so now it uses the model global position.
@onready var vehicle = $"../Vehicle/vehicle"
@onready var nav_agent: NavigationAgent3D = get_node("NavigationAgent3D")
@onready var sfx_zombie_run_over = $"../sfx_zombie_run_over"
@onready var zombies_killed_label = get_node("hud/Score/Zombies_Killed/zombies_killed_label")

@onready var idle_Label3D = $"idle_Label3D"
@onready var pursue_Label3D = $"pursue_Label3D"
@onready var attacking_Label3D = $"attacking_Label3D"

signal zombie_killed

enum State {IDLE, PURSUE, MELEE_ATTACK}

var current_state: int = State.IDLE

func _physics_process(delta):
	process_state(delta)

func process_state(delta):
	match current_state:
		State.IDLE:
			idle_Label3D.visible = true
			pursue_Label3D.visible = false
			attacking_Label3D.visible = false
			if is_target_in_range(10.0):
				current_state = State.PURSUE

		State.PURSUE:
			idle_Label3D.visible = false
			pursue_Label3D.visible = true
			attacking_Label3D.visible = false
			move_towards_target(delta)

			if is_target_in_attack_range():
				current_state = State.MELEE_ATTACK

		State.MELEE_ATTACK:
			idle_Label3D.visible = false
			pursue_Label3D.visible = false
			attacking_Label3D.visible = true
			if is_target_in_attack_range():
				melee_attack()
			else:
				current_state = State.PURSUE

func is_target_in_range(range: float) -> bool:
	var distance_to_target = global_transform.origin.distance_to(vehicle.global_transform.origin)
	return distance_to_target <= range

func is_target_in_attack_range() -> bool:
	var distance_to_target = global_transform.origin.distance_to(vehicle.global_transform.origin)
	return distance_to_target <= 3.0  # Adjust the attack range as needed

func move_towards_target(delta):
	var direction = vehicle.global_transform.origin - global_transform.origin
	direction = direction.normalized()
	velocity = lerp(velocity, direction * movement_speed, delta)
	move_and_slide()
main_world.gd
# main_world.gd

extends Node3D

@onready var vehicle = $Vehicle

var zombie_road_block_scene = preload("res://assets/zombie_road_block.tscn")

func hud_increase_zombie_killing_count_method():
	$hud._on_zombie_killed()
	
func _physics_process(delta):
	get_tree().call_group("Enemies", "update_target_location", vehicle.global_transform.origin)

func _on_zombie_spawner_area_3d_vehicle_entered_zombie_spawner():
	print("_on_zombie_spawner_area_3d_vehicle_entered_zombie_spawner called")
	# Spawn road blocks
	var progress_step = 1.0 / 10.0 # Divide the range of progress ratios into 10 equal parts
	var current_progress = 0.0 # Start at the beginning of the path

	for i in range(10): # Spawn 10 road blocks
		var zombie_road_block = zombie_road_block_scene.instantiate()
		print("Spawned road block at position: ", zombie_road_block.global_transform.origin)

		var road_block_spawn_location = get_node_or_null("ZombieSpawnPath/ZombieSpawnLocation")
		if road_block_spawn_location:
			print("Spawn location found: ", road_block_spawn_location.global_transform.origin)
		else:
			print("Spawn location not found!")

		# Assign a progress ratio from one of the 10 equal parts with some randomness
		road_block_spawn_location.progress_ratio = current_progress + randf() * progress_step * 0.5

		# Add a small random offset
		var offset_x = randf_range(-0.1, 0.1)
		var offset_z = randf_range(-0.1, 0.1)
		road_block_spawn_location.position.x += offset_x
		road_block_spawn_location.position.z += offset_z

		# Generate a random rotation angle in degrees, excluding 330-30, 60-120, 150-210, and 240-300 degrees
		var random_rotation_degrees
		while true:
			random_rotation_degrees = randi() % 360
			if (random_rotation_degrees >= 30 and random_rotation_degrees < 60) or \
				(random_rotation_degrees >= 120 and random_rotation_degrees < 150) or \
				(random_rotation_degrees >= 210 and random_rotation_degrees < 240) or \
				(random_rotation_degrees >= 300 and random_rotation_degrees < 330):
				break

		# Convert the rotation angle to radians
		var random_rotation = deg_to_rad(random_rotation_degrees)

		# Create a Transform3D with the random rotation
		var transform = Transform3D()
		transform = transform.rotated(Vector3.UP, random_rotation)
		transform.origin = road_block_spawn_location.global_transform.origin

		zombie_road_block.global_transform = transform

		add_child(zombie_road_block)

		# Move to the next part of the progress range for the next road block
		current_progress += progress_step




Well if the zombies are being instantiated as children of the road block scene, that puts them in a different place in the scene tree than the one you added manually, so all the relative paths are going to be different. This is why as general rule I try to avoid using $/get_node to locate nodes that are not part of the script’s scene (anything starting with “…” or “/root”). Even if you “fixed” the paths for where spawned zombies are showing up, they’d be broken for the one you manually added, and could also get broken if you do any reorganizing of your main scene.

Instead, I’d suggest moving the onready assignments for vehicle, sfx, & hud to main_world.gd (which should reliably know where those nodes are) and leave a simple var vehicle declaration (no onready or assignment) in the zombie script. Then right after you instantiate the road block scene, loop through the zombie nodes and set each one’s vehicle to the main world’s vehicle, and connect the zombie_killed signal to the sfx & hud nodes.

Thanks @soundgnome! That makes sense in concept but I am having trouble executing your suggestion. I performed the steps you outlined (thank you!) and am still getting null references to vehicle in the zombie.gd

Here is my code currently, what did I do wrong or am I not understanding?

main_world.gd
extends Node3D

@onready var vehicle = $Vehicle
@onready var hud = $hud
@onready var vehicle_vehicle = $"../Vehicle/vehicle"
@onready var sfx_zombie_run_over = $"../sfx_zombie_run_over"
@onready var zombies_killed_label = get_node("hud/Score/Zombies_Killed/zombies_killed_label")


var zombie_road_block_scene = preload("res://assets/zombie_road_block.tscn")

func hud_increase_zombie_killing_count_method():
	$hud._on_zombie_killed()

func on_vehicle_health_changed():
	$hud._on_fiesta_hit_points_update()

func _physics_process(delta):
	get_tree().call_group("Enemies", "update_target_location", vehicle.global_transform.origin)

func _on_zombie_spawner_area_3d_vehicle_entered_zombie_spawner():
	print("_on_zombie_spawner_area_3d_vehicle_entered_zombie_spawner called")
	# Spawn road blocks
	var progress_step = 1.0 / 10.0 # Divide the range of progress ratios into 10 equal parts
	var current_progress = 0.0 # Start at the beginning of the path

	for i in range(10): # Spawn 10 road blocks
		var zombie_road_block = zombie_road_block_scene.instantiate()
		#print("Spawned road block at position: ", zombie_road_block_scene.global_transform.origin)
		var road_block_spawn_location = get_node_or_null("ZombieSpawnPath/ZombieSpawnLocation")
		if road_block_spawn_location:
			print("Spawn location found: ", road_block_spawn_location.global_transform.origin)
		else:
			print("Spawn location not found!")
		# Set the vehicle reference for each zombie and connect signals
		for zombie in zombie_road_block.get_children():
			if zombie.is_in_group("Enemies"):
				zombie.vehicle = vehicle
				zombie.zombie_killed.connect(sfx_zombie_run_over.play)
				zombie.zombie_killed.connect(hud.hud_increase_zombie_killing_count_method)
		# Assign a progress ratio from one of the 10 equal parts with some randomness
		road_block_spawn_location.progress_ratio = current_progress + randf() * progress_step * 0.5

		# Add a small random offset
		var offset_x = randf_range(-0.1, 0.1)
		var offset_z = randf_range(-0.1, 0.1)
		road_block_spawn_location.position.x += offset_x
		road_block_spawn_location.position.z += offset_z

		# Generate a random rotation angle in degrees, excluding 330-30, 60-120, 150-210, and 240-300 degrees
		var random_rotation_degrees
		while true:
			random_rotation_degrees = randi() % 360
			if (random_rotation_degrees >= 30 and random_rotation_degrees < 60) or \
				(random_rotation_degrees >= 120 and random_rotation_degrees < 150) or \
				(random_rotation_degrees >= 210 and random_rotation_degrees < 240) or \
				(random_rotation_degrees >= 300 and random_rotation_degrees < 330):
				break

		# Convert the rotation angle to radians
		var random_rotation = deg_to_rad(random_rotation_degrees)

		# Create a Transform3D with the random rotation
		var transform = Transform3D()
		transform = transform.rotated(Vector3.UP, random_rotation)
		transform.origin = road_block_spawn_location.global_transform.origin

		zombie_road_block.global_transform = transform

		add_child(zombie_road_block)

		# Move to the next part of the progress range for the next road block
		current_progress += progress_step
zombie.gd

extends CharacterBody3D

@export_group("Zombie Stats")
@export var movement_speed: float = 4.0
@export var Health = 1

##Zombie was referencing the vehicle node that contained the model, changed so now it uses the model global position.
#@onready var vehicle = $"../Vehicle/vehicle"
#@onready var sfx_zombie_run_over = $"../sfx_zombie_run_over"
#@onready var zombies_killed_label = get_node("hud/Score/Zombies_Killed/zombies_killed_label")

@onready var nav_agent: NavigationAgent3D = get_node("NavigationAgent3D")

@onready var idle_Label3D = $"idle_Label3D"
@onready var pursue_Label3D = $"pursue_Label3D"
@onready var attacking_Label3D = $"attacking_Label3D"

var vehicle

signal zombie_killed

enum State {IDLE, PURSUE, MELEE_ATTACK}

var current_state: int = State.IDLE

func _physics_process(delta):
	process_state(delta)

func process_state(delta):
	match current_state:
		State.IDLE:
			idle_Label3D.visible = true
			pursue_Label3D.visible = false
			attacking_Label3D.visible = false
			if is_target_in_range(10.0):
				current_state = State.PURSUE

		State.PURSUE:
			idle_Label3D.visible = false
			pursue_Label3D.visible = true
			attacking_Label3D.visible = false
			move_towards_target(delta)

			if is_target_in_attack_range():
				current_state = State.MELEE_ATTACK

		State.MELEE_ATTACK:
			idle_Label3D.visible = false
			pursue_Label3D.visible = false
			attacking_Label3D.visible = true
			if is_target_in_attack_range():
				melee_attack()
			else:
				current_state = State.PURSUE

func is_target_in_range(range: float) -> bool:
	var distance_to_target = global_transform.origin.distance_to(vehicle.global_transform.origin)
	return distance_to_target <= range

func is_target_in_attack_range() -> bool:
	var distance_to_target = global_transform.origin.distance_to(vehicle.global_transform.origin)
	return distance_to_target <= 3.0  # Adjust the attack range as needed

func move_towards_target(delta):
	var direction = vehicle.global_transform.origin - global_transform.origin
	direction = direction.normalized()
	velocity = lerp(velocity, direction * movement_speed, delta)
	move_and_slide()

func melee_attack():
	emit_signal("deal_melee_damage")
	print("Melee attack on the vehicle!")

## Bullet damage logic
func Hit_Successful(Damage, _Direction: Vector3 = Vector3.ZERO, _Position: Vector3 = Vector3.ZERO):
	Health -= Damage
	if Health <= 0:
		zombie_killed.emit()
		queue_free()
		print("zombie shot")
		
## Collision damage logic
func _on_body_entered() -> void:
	zombie_killed.emit()
	$"../sfx_zombie_run_over".play()
	queue_free()
	print("zombie ran over")
HUD.gd

extends CanvasLayer

@onready var Debug_HUD = $debug_hud
@onready var CurrentWeaponLabel = $debug_hud/HBoxContainer/CurrentWeapon
@onready var CurrentAmmoLabel = $debug_hud/HBoxContainer2/CurrentAmmo
@onready var CurrentWeaponStack = $debug_hud/HBoxContainer3/WeaponStack
@onready var CurrentFOV = $"debug_hud/HBoxContainer4/FOV Label"
@onready var Hit_Sight = $Hit_Sight
@onready var Hit_Sight_Timer = $Hit_Sight/Hit_Sight_Timer
@onready var FOVSlider = $debug_hud/FOV
@onready var OverLay = $Overlay
@onready var CurrentFiestaHitPointsLabel = $"debug_hud/HBoxContainer5/Fiesta Hit Points"

func _input(event):
	if event.is_action_pressed("ui_cancel"):
		if FOVSlider:
			FOVSlider.release_focus()

func _on_weapons_manager_update_weapon_stack(WeaponStack):
	CurrentWeaponStack.text = ""
	for i in WeaponStack:
		CurrentWeaponStack.text += "\n"+i

func _on_weapons_manager_update_ammo(Ammo):
	CurrentAmmoLabel.set_text(str(Ammo[0])+" / "+str(Ammo[1]))

func _on_weapons_manager_weapon_changed(WeaponName):
	CurrentWeaponLabel.set_text(WeaponName)

func _on_hit_sight_timer_timeout():
	Hit_Sight.set_visible(false)

func _on_weapons_manager_add_signal_to_hud(_projectile):
	_projectile.connect("Hit_Successfull", Callable(self,"_on_weapons_manager_hit_successfull"))

func _on_weapons_manager_hit_successfull():
	Hit_Sight.set_visible(true)
	Hit_Sight_Timer.start()

func _on_weapons_models_update_fov(Fov, UpdateSlider: bool = false):
	CurrentFOV.set_text(str(Fov))
	if UpdateSlider:
		FOVSlider.set_value_no_signal(Fov)

func LoadOverLayTexture(Active:bool, txtr: Texture2D = null):
		OverLay.set_texture(txtr)
		OverLay.set_visible(Active)

func _on_weapons_manager_connect_weapon_to_hud(_weapon_resouce):
	_weapon_resouce.connect("UpdateOverlay", Callable(self, "LoadOverLayTexture"))

func _on_fiesta_hit_points_update(current_health):
	CurrentFiestaHitPointsLabel.text = str(current_health) + "/100"
	
func hud_increase_zombie_killing_count_method():
	# Update the zombie killing count label or perform any other necessary actions
	pass

Thanks again, cheers!

I think you need to update the node paths in the onready vars you moved to be relative to the world scene - for example, the “…/” probably shouldn’t be there for vehicle_vehicle & sfx_zombie_run_over. Maybe temporarily add a _ready function that just prints all those variables to make sure they’re getting assigned properly.

Thanks @soundgnome! I am still getting the same errors :sob:

I edited the @onready vars to remove the “…/” and I am still getting the same errors.

Any ideas? Thanks for your help.


As far as I can see the variable vehicle in zombie.gd is never assigned so it will be nil.
Since you are adding zombies dynamically, I recommend not using any kind of node searching to add the vehicle.
Set the vehicle variable from the same place you instantiate a zombie from (if possible).
I don’t see the code where you instantiate a zombie but likely it is part of main_world.gd and you already have access to the vehicle node there.
If this is the line that does it then:

for i in range(10): # Spawn 10 road blocks
    var zombie_road_block = zombie_road_block_scene.instantiate()   
    zombie_road_block.vehicle = vehicle

Note that all 10 road blocks are going to point to the same vehicle.

1 Like

Correct @sancho2 var vehicle is not assigned in zombie.gd because @soundgnome wanted to move that declaration into main_world.gd.

I tried your edit to the instantiation portion and still getting the same errors. Sorry if there is something I am missing…

current main_world.gd code
extends Node3D

@onready var vehicle = $Vehicle
@onready var hud = $hud
@onready var vehicle_vehicle = $"Vehicle/vehicle"
@onready var sfx_zombie_run_over = $"sfx_zombie_run_over"
@onready var zombies_killed_label = get_node("hud/Score/Zombies_Killed/zombies_killed_label")


var zombie_road_block_scene = preload("res://assets/zombie_road_block.tscn")

func hud_increase_zombie_killing_count_method():
	$hud._on_zombie_killed()

func on_vehicle_health_changed():
	$hud._on_fiesta_hit_points_update()

func _physics_process(delta):
	get_tree().call_group("Enemies", "update_target_location", vehicle.global_transform.origin)

func _on_zombie_spawner_area_3d_vehicle_entered_zombie_spawner():
	print("_on_zombie_spawner_area_3d_vehicle_entered_zombie_spawner called")
	# Spawn road blocks
	var progress_step = 1.0 / 10.0 # Divide the range of progress ratios into 10 equal parts
	var current_progress = 0.0 # Start at the beginning of the path

	for i in range(10): # Spawn 10 road blocks
		var zombie_road_block = zombie_road_block_scene.instantiate()   
		zombie_road_block.vehicle = vehicle
		var road_block_spawn_location = get_node_or_null("ZombieSpawnPath/ZombieSpawnLocation")
		if road_block_spawn_location:
			print("Spawn location found: ", road_block_spawn_location.global_transform.origin)
		else:
			print("Spawn location not found!")
		# Set the vehicle reference for each zombie and connect signals
		for zombie in zombie_road_block.get_children():
			if zombie.is_in_group("Enemies"):
				zombie.vehicle = vehicle
				zombie.zombie_killed.connect(sfx_zombie_run_over.play)
				zombie.zombie_killed.connect(hud.hud_increase_zombie_killing_count_method)
		# Assign a progress ratio from one of the 10 equal parts with some randomness
		road_block_spawn_location.progress_ratio = current_progress + randf() * progress_step * 0.5

		# Add a small random offset
		var offset_x = randf_range(-0.1, 0.1)
		var offset_z = randf_range(-0.1, 0.1)
		road_block_spawn_location.position.x += offset_x
		road_block_spawn_location.position.z += offset_z

		# Generate a random rotation angle in degrees, excluding 330-30, 60-120, 150-210, and 240-300 degrees
		var random_rotation_degrees
		while true:
			random_rotation_degrees = randi() % 360
			if (random_rotation_degrees >= 30 and random_rotation_degrees < 60) or \
				(random_rotation_degrees >= 120 and random_rotation_degrees < 150) or \
				(random_rotation_degrees >= 210 and random_rotation_degrees < 240) or \
				(random_rotation_degrees >= 300 and random_rotation_degrees < 330):
				break

		# Convert the rotation angle to radians
		var random_rotation = deg_to_rad(random_rotation_degrees)

		# Create a Transform3D with the random rotation
		var transform = Transform3D()
		transform = transform.rotated(Vector3.UP, random_rotation)
		transform.origin = road_block_spawn_location.global_transform.origin

		zombie_road_block.global_transform = transform

		add_child(zombie_road_block)

		# Move to the next part of the progress range for the next road block
		current_progress += progress_step

If so then this line is in error:

@onready var vehicle_vehicle = $"Vehicle/vehicle"

You can test this in the main_world.gd script :

func _ready(): 
    print(vehicle)

Theoretically that will print null because the address is wrong.
When using onready’s for scene nodes, the best way to create them is to click and drag them into the code window, press ctrl, and drop the node.
This will create the onready variable with the correct path.

Does the node Vehicle have a child called “vehicle”?
Looks to me like the path should be:

@onready var vehicle_vehicle = $Vehicle   

so I renamed ../Vehicle/vehicle to Vehicle_parent/Fiesta_vehicle just to make things more clear and I am getting Fiesta_vehicle:<RigidBody3D#54106523484> when print(vehicle) is executed on _ready.

So all good there but I am still getting the 3 errors in zombie.gd where it doesn’t recognize $"Vehicle_parent/Fiesta_vehicle" as vehicle

Is zombie_road_block.vehicle = vehicle after I instantiate zombie_road_block_scene not going to pass the vehicle var to the instantiated scene? Because that’s where the error is occuring.

Thanks so much for the help @sancho2 & @soundgnome, appreciate it! Any ideas on what I can do to fix this?

Just had a thought, the zombie.gd script is not attached to the parent node in the zombie_road_block.tscn packedscene. Could this be why zombie_road_block.vehicle = vehicle can’t find vehicle because it’s expecting vehicle to be defined in the parent node of zombie_road_block.tscn packedscene?

If so, what method and syntax do I need to reference zombie.gd which is a child of zombie_road_block_scene?

Thanks so much y’all for any help or tips. Cheers!

EDIT:

I attempted to get_node on each zombie (also named them “zombie_a” “zombie_b” “zombie_c” to make it more clear) and then set the vehicle var (which is undefined in the zombie.gd script attached) thinking this would set the var once the zombies are instantiated but doesn’t seem to make a difference, is this a good method and I just got a detail wrong, or is there another method I should use to make sure the vehicle var is set correctly in the children of the instantiated packedscene?

current zombie.gd
extends CharacterBody3D

@export_group("Zombie Stats")
@export var movement_speed: float = 4.0
@export var Health = 1

##Zombie was referencing the vehicle node that contained the model, changed so now it uses the model global position.
#@onready var vehicle = $"Vehicle_parent/Fiesta_vehicle"
#@onready var sfx_zombie_run_over = $"../sfx_zombie_run_over"
#@onready var zombies_killed_label = get_node("hud/Score/Zombies_Killed/zombies_killed_label")

@onready var nav_agent: NavigationAgent3D = get_node("NavigationAgent3D")

@onready var idle_Label3D = $"idle_Label3D"
@onready var pursue_Label3D = $"pursue_Label3D"
@onready var attacking_Label3D = $"attacking_Label3D"

var vehicle

signal zombie_killed

enum State {IDLE, PURSUE, MELEE_ATTACK}

var current_state: int = State.IDLE

func _physics_process(delta):
	process_state(delta)

func process_state(delta):
	match current_state:
		State.IDLE:
			idle_Label3D.visible = true
			pursue_Label3D.visible = false
			attacking_Label3D.visible = false
			if is_target_in_range(10.0):
				current_state = State.PURSUE

		State.PURSUE:
			idle_Label3D.visible = false
			pursue_Label3D.visible = true
			attacking_Label3D.visible = false
			move_towards_target(delta)

			if is_target_in_attack_range():
				current_state = State.MELEE_ATTACK

		State.MELEE_ATTACK:
			idle_Label3D.visible = false
			pursue_Label3D.visible = false
			attacking_Label3D.visible = true
			if is_target_in_attack_range():
				melee_attack()
			else:
				current_state = State.PURSUE

func is_target_in_range(range: float) -> bool:
	var distance_to_target = global_transform.origin.distance_to(vehicle.global_transform.origin)
	return distance_to_target <= range

func is_target_in_attack_range() -> bool:
	var distance_to_target = global_transform.origin.distance_to(vehicle.global_transform.origin)
	return distance_to_target <= 3.0  # Adjust the attack range as needed

func move_towards_target(delta):
	var direction = vehicle.global_transform.origin - global_transform.origin
	direction = direction.normalized()
	velocity = lerp(velocity, direction * movement_speed, delta)
	move_and_slide()

func melee_attack():
	emit_signal("deal_melee_damage")
	print("Melee attack on the vehicle!")

## Bullet damage logic
func Hit_Successful(Damage, _Direction: Vector3 = Vector3.ZERO, _Position: Vector3 = Vector3.ZERO):
	Health -= Damage
	if Health <= 0:
		zombie_killed.emit()
		queue_free()
		print("zombie shot")
		
## Collision damage logic
func _on_body_entered() -> void:
	zombie_killed.emit()
	$"../sfx_zombie_run_over".play()
	queue_free()
	print("zombie ran over")
current main_scene.gd
extends Node3D

#@onready var vehicle = $Vehicle
@onready var hud = $hud
#@onready var vehicle_vehicle = $"../Vehicle/vehicle"
@onready var sfx_zombie_run_over = $"sfx_zombie_run_over"
@onready var zombies_killed_label = get_node("hud/Score/Zombies_Killed/zombies_killed_label")
#@onready var vehicle = %vehicle
@onready var vehicle = $"Vehicle_parent/Fiesta_vehicle"

var zombie_road_block_scene = preload("res://assets/zombie_road_block.tscn").instantiate()

func _ready(): 
	print(vehicle)
	#print(vehicle_vehicle)

func hud_increase_zombie_killing_count_method():
	$hud._on_zombie_killed()

func on_vehicle_health_changed():
	$hud._on_fiesta_hit_points_update()

func _physics_process(delta):
	get_tree().call_group("Enemies", "update_target_location", vehicle.global_transform.origin)

func _on_zombie_spawner_area_3d_vehicle_entered_zombie_spawner():
	print("_on_zombie_spawner_area_3d_vehicle_entered_zombie_spawner called")
	# Spawn road blocks
	var progress_step = 1.0 / 10.0 # Divide the range of progress ratios into 10 equal parts
	var current_progress = 0.0 # Start at the beginning of the path

	for i in range(10): # Spawn 10 road blocks
		var zombie_road_block = zombie_road_block_scene.instantiate()   
		zombie_road_block.get_node("zombie_a").vehicle = vehicle
		zombie_road_block.get_node("zombie_b").vehicle = vehicle
		zombie_road_block.get_node("zombie_c").vehicle = vehicle
		var road_block_spawn_location = get_node_or_null("ZombieSpawnPath/ZombieSpawnLocation")
		if road_block_spawn_location:
			print("Spawn location found: ", road_block_spawn_location.global_transform.origin)
		else:
			print("Spawn location not found!")
		# Set the vehicle reference for each zombie and connect signals
		for zombie in zombie_road_block.get_children():
			if zombie.is_in_group("Enemies"):
				zombie.vehicle = vehicle
				zombie.zombie_killed.connect(sfx_zombie_run_over.play)
				zombie.zombie_killed.connect(hud.hud_increase_zombie_killing_count_method)
		# Assign a progress ratio from one of the 10 equal parts with some randomness
		road_block_spawn_location.progress_ratio = current_progress + randf() * progress_step * 0.5

		# Add a small random offset
		var offset_x = randf_range(-0.1, 0.1)
		var offset_z = randf_range(-0.1, 0.1)
		road_block_spawn_location.position.x += offset_x
		road_block_spawn_location.position.z += offset_z

		# Generate a random rotation angle in degrees, excluding 330-30, 60-120, 150-210, and 240-300 degrees
		var random_rotation_degrees
		while true:
			random_rotation_degrees = randi() % 360
			if (random_rotation_degrees >= 30 and random_rotation_degrees < 60) or \
				(random_rotation_degrees >= 120 and random_rotation_degrees < 150) or \
				(random_rotation_degrees >= 210 and random_rotation_degrees < 240) or \
				(random_rotation_degrees >= 300 and random_rotation_degrees < 330):
				break

		# Convert the rotation angle to radians
		var random_rotation = deg_to_rad(random_rotation_degrees)

		# Create a Transform3D with the random rotation
		var transform = Transform3D()
		transform = transform.rotated(Vector3.UP, random_rotation)
		transform.origin = road_block_spawn_location.global_transform.origin

		zombie_road_block.global_transform = transform

		var zombies = [
			zombie_road_block.get_node("zombie_a"),
			zombie_road_block.get_node("zombie_b"),
			zombie_road_block.get_node("zombie_c")
			]

		for zombie in zombies:
			zombie.scale = Vector3(0.13, 0.13, 0.13)
			
		var roadblock = zombie_road_block.get_node("roadblock")
		roadblock.scale = Vector3(1, 1, 2.635)
		
		add_child(zombie_road_block)

		# Move to the next part of the progress range for the next road block
		current_progress += progress_step

Can you post your code to a github repo or someplace where we can see the whole project? It looks to me now like the vehicle is being correctly assigned to the zombies twice (first in the zombie_road_block.get_node("zombie_a").vehicle = vehicle and then again in the for zombie in zombie_road_block.get_children() loop), so the problem may be elsewhere.

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