Search code examples
instancegodotgdscript

Instancing with export variables not working, so, not able to clone scenes by adding other scenes as a child of the Main


I am coding a star collect game in Godot, but while trying to add a scene as a child of the main (The scene which starts first, and the scene where I am doing the instancing), it's not working, rather the debug screen lags so much that it shows "Not Responding". I am coding in GDScript. Here's what I coded in the main scene to do the instancing:

extends Node2D

export (PackedScene) var Star

func _ready():
    pass

func _on_Timer_timeout():
    var star = Star.instance()
    add_child(star)

I've also inserted the desired scene I want to instance in the Script variables section (Sorry, as I'm new to Godot I'm not able to explain the terms well) : Script Variables section

And this is the code of the scene which I am instancing:

extends Area2D

export var done = 0
export var speed = 43
export var spinVal = 0
export var dir = 0

func _ready():
    done=0
    dir=5-(randf()*10)
    spinVal = 5-(randf()*10)
    position.x=randf()*10
    position.y=-20
    while done==0:
        position.y+=speed
        rotation_degrees=0+dir
        rotate(spinVal)
    print(position)


func _on_VisibilityNotifier2D_screen_exited():
    if (position.y<720):
            done=1
            queue_free()

Before, I had tried the simple way of instancing before I used PackedScene method, but I was facing the same problem. Now I'm trying it this way but no improvements...


Solution

  • Your instancing is fine. Your scene is wrong.

    As soon as you add the instanced scene with add_child, it's _ready will run. And this:

    func _ready():
        done=0
        dir=5-(randf()*10)
        spinVal = 5-(randf()*10)
        position.x=randf()*10
        position.y=-20
        while done==0:
            position.y+=speed
            rotation_degrees=0+dir
            rotate(spinVal)
    

    Well, that is is an infinite loop. The first line ensures done is 0. And nothing in there will set done to something else. The game is stuck there.


    I see you set done somewhere else:

    func _on_VisibilityNotifier2D_screen_exited():
        if (position.y<720):
                done=1
                queue_free()
    

    Yet, that code never had a chance to run.


    If you really, REALLY, want to write your motion in _ready. You can do this:

    func _ready():
        done=0
        dir=5-(randf()*10)
        spinVal = 5-(randf()*10)
        position.x=randf()*10
        position.y=-20
        while done==0:
            yield(get_tree(), "physics_frame") # <--
            position.y+=speed
            rotation_degrees=0+dir
            rotate(spinVal)
    

    When the code reaches yield, it will be suspended until the specified signal happens, then it continues. In this case the "physics_frame" signal of the SceneTree. I'm using "physics_frame" instead of "idle_frame" given that this is an Area2D.


    The more idiomatic way to write this is, of course:

    extends Area2D
    
    export var done = 0
    export var speed = 43
    export var spinVal = 0
    export var dir = 0
    
    func _ready():
        done=0
        dir=5-(randf()*10)
        spinVal = 5-(randf()*10)
        position.x=randf()*10
        position.y=-20
    
    func _physics_process(_delta):
        if done != 0:
            return
    
        position.y+=speed
        rotation_degrees=0+dir
        rotate(spinVal)
    
    func _on_VisibilityNotifier2D_screen_exited():
        if (position.y<720):
                done=1
                queue_free()
    

    In all honesty, I don't think you need done at all. However, given it is an exported variable, I didn't remove it.

    I'm not sure about your rotation either. But that is a separate issue.