Search code examples
new-operatorgodotgdscript

godot changing scenes crash because of multiple enemy instances


when I change scenes in godot it crashes cause the enemies stay and the player is removed from the scene so they keep detecting a nil instance.

to be honest I can't find anything online similar to this.

here is my enemies code:

extends CharacterBody2D

@onready var player = get_tree().get_first_node_in_group("player")
@onready var death_time = get_tree().get_first_node_in_group("deathtime")

const SPEED = 300.0


func _physics_process(delta):
    rotation = player.global_position.angle_to_point(position)
    self.rotation_degrees += 180
    position += transform.x * SPEED * delta

my spawners code:

extends Node


@onready var player = %Player
@onready var timer = %spawntimer
@onready var death_time = %DeathTime

func _ready():
    print("start")
    timer.start()



func spawn():
    print("spawned")
    var enemy = preload("res://scenes/enemy.tscn").instantiate()
    add_sibling(enemy)
    enemy.global_position = Vector2(randi_range(-2647,4455),randi_range(2657,-3426))
    timer.start()




func _on_spawntimer_timeout():
    print("timeout")
    spawn()





func _on_death_time_timeout():
    get_tree().change_scene_to_file("res://scenes/menu.tscn")

here is my players code:

extends CharacterBody2D

@export var health = 30
const XSPEED = 400.0
const YSPEED = -400.0
@onready var death_time = %DeathTime

# Get the gravity from the project settings to be synced with RigidBody nodes.
var gravity = ProjectSettings.get_setting("physics/2d/default_gravity")


func _physics_process(_delta):
    var directiony = Input.get_axis("input_up", "input_down")
    if directiony:
            velocity.y = directiony * -YSPEED
    else:
        velocity.y = move_toward(velocity.y, 0, 13)

    var directionx = Input.get_axis("input_left", "input_right")
    if directionx:
        velocity.x = directionx * XSPEED
    else:
        velocity.x = move_toward(velocity.x, 0, 13)
        
    move_and_slide()
    for index in get_slide_collision_count():
        var collision = get_slide_collision(index)
        var body := collision.get_collider()
        print("Collided with: ", body.name)
        health -= 1
        if health <= 0:
            death_time.start()
            break #finish and exit so it does not start the timer again.d

the deathtimer was to attempt to fix it, I thought it was because the player was switching and the main scene had to switch or something.


Solution

  • I thought it was the reloading scene in godot doesn't remove enemy instances. but no, it's because I was adding the enemies as siblings of the root node. instead of children. heres the fixed spawner code:

    
    
    @onready var player = %Player
    @onready var timer = %spawntimer
    @onready var death_time = %DeathTime
    
    func _ready():
        print("start")
        timer.start()
    
    
    
    func spawn():
        print("spawned")
        var enemy = preload("res://scenes/enemy.tscn").instantiate()
        add_child(enemy)
        enemy.global_position = Vector2(randi_range(-2647,4455),randi_range(2657,-3426))
        timer.start()
    
    
    
    
    func _on_spawntimer_timeout():
        print("timeout")
        spawn()
    
    
    
    
    
    func _on_death_time_timeout():
        get_tree().change_scene_to_file("res://scenes/menu.tscn")