I need to get variables from another scene

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By javrocks

They are prob other ways to do this but basically i have two scenes one is called Enemy and the other is called Enemy split. I want it so that when the enemy dies it split into two identical but smaller enemies. So when the enemy dies i need to send across all the randomly generated variables the the enemy started with like its texture and it’s position.

#In Enemy script

signal destroyed

 if enemy_health <= 0:
	 var scene_insctance = Split_Scene.instance()
	 add_child(scene_insctance)
	 emit_signal("destroyed",(random_value),(global_position),(Random_Texture)) 
	 queue_free()

The signal doesn’t reach into the enemy split script unless the scene is instanced first so when the enemy dies i instanced the split scene then i sent the signal but it still tells me that my variables are null

#In Split_Enemy script

var Enemy_random_value 
var Enemy_pos 
var Enemy_Texture 

var Enemy

func _ready():
    Enemy = get_tree().get_root().find_node("Enemy", true, false)
    Enemy.connect("destroyed", self, "get_var")

    global_position = Enemy_pos
    $Sprite.texture = Enemy_Texture
    $Sprite.scale.x = Enemy_random_value/2   # to make it smaller
    $Sprite.scale.y = Enemy_random_value/2

func get_var(random_value,global_position,Random_Texture):

    Enemy_random_value = random_value
    Enemy_pos = global_position
    Enemy_Texture = Random_Texture
    print( Enemy_random_value, Enemy_pos, Enemy_Texture)
 if enemy_health <= 0:
   var scene_insctance = Split_Scene.instance()
   scene_insctance.get_var(random_value,global_position,Random_Texture)
   add_child(scene_insctance)
   //emit_signal("destroyed",(random_value),(global_position),(Random_Texture)) 
   queue_free()

ramazan | 2022-02-22 08:48

not sure if u wanted me to leave or remove the emit signal but i tried doing both and it says that the get_var() function is non-existent in base Node2D

javrocks | 2022-02-22 11:09

:bust_in_silhouette: Reply From: Zylann

I think you should not bother emitting a signal just to reach your split enemy. Signals don’t even work this way, they can’t be connected across separate scene files or inexistent instances. You could connect the signal after creating the instance, but since the enemy is destroyed just afterward it is unnecessary complexity. It is not the right tool for the job here.

The easiest thing to do is to instance your enemy split, then set the variables from the enemy script. No need for noodling around with signals.

 if enemy_health <= 0:
      var scene_instance = Split_Scene.instance()
      add_child(scene_insctance)

      scene_instance.some_var_you_want_to_set = var_from_enemy
      scene_instance.other_var_you_want_to_set = other_var_from_enemy
      # etc

      # Note, if you want those variables to be set 
      # before `_ready` is called in enemy split,
      # you could set those variables before calling `add_child`.

      queue_free()

If you prefer organize this copying code inside the enemy split scene instead, you can create a function to do this:

In enemy.gd:

 if enemy_health <= 0:
      var scene_instance = Split_Scene.instance()
      add_child(scene_insctance)

      scene_instance.copy_vars_from_enemy(self)

      queue_free()

In enemy_split.gd (or whatever script this is):

 func copy_vars_from_enemy(source_enemy):
      some_var_you_want_to_set = source_enemy.var_from_enemy
      other_var_you_want_to_set = source_enemy.other_var_from_enemy
      # etc

I tried both ways but it makes the game stick

if  enemy_health <= 0:
	var scene_instance = Split_Scene.instance()
	add_child(scene_instance) 
	scene_instance.get_var(self)
	queue_free()

And in Enemy_Split gd

#In Split_Enemy script

var Enemy_random_value 
var Enemy_pos 
var Enemy_Texture 

func _ready():

    global_position = Enemy_pos

    $Sprite.texture = Enemy_Texture

    $Sprite.scale.x = Enemy_random_value/2   # to make it smaller
    $Sprite.scale.y = Enemy_random_value/2

func get_var(source_enemy):

    Enemy_random_value = source_enemy.random_value
    Enemy_pos = source_enemy.global_position
    Enemy_Texture = source_enemy.Random_Texture

javrocks | 2022-02-22 20:22

Is source_enemy suppose to be something else idk

javrocks | 2022-02-22 20:23

source_enemy is the enemy that produces the split one when dying. It allows the split one to copy properties from it.

Zylann | 2022-02-22 20:47

so do i declare that

onready var source_enemy = get_tree().get_root().find_node("Enemy", true, false)

or do i just leave it cus it isn’t wrk

javrocks | 2022-02-22 21:16

You dont need to declare the variable like that, it is a function parameter. It is created just for the moment you pass it from the dying enemy to the new split one it creates.

Also, I realise you are destroying the split enemy you just created here:

if enemy_health <= 0:
    var scene_instance = Split_Scene.instance()
    add_child(scene_instance) # <--
    #...
    # This will ALSO destroy the instance you just added with `add_child` above,
    # because it will be child of this node.
    queue_free()

One solution is to add the scene instance as sibling of the enemy:

if enemy_health <= 0:
    var scene_instance = Split_Scene.instance()
    get_parent().add_child(scene_instance)

Zylann | 2022-02-22 21:21

It still sticks when health is zero

javrocks | 2022-02-22 21:31

I noticed you do the following in _ready of your split enemy:

$Sprite.texture = Enemy_Texture # <-- this is a variable you set in `get_var`

However when you create the split enemy, you chose to send over its variables after you added the split enemy to the tree. That means _ready will have been called already, so it’s too late:

add_child(scene_instance) # <-- `_ready` is called here
scene_instance.get_var(self)

So you should swap these two lines so that the variables will be set in time.

scene_instance.get_var(self)
add_child(scene_instance)

Zylann | 2022-02-22 21:47

yes i tried swapping them but it still sticks

javrocks | 2022-02-22 22:03

What do you mean by “it still sticks”?
At this point I don’t know what else needs to be fixed

Zylann | 2022-02-22 22:05

when i run the game everything is smooth but when i destroy the enemy the whole thing just freezes

javrocks | 2022-02-22 22:10

did i call/code the get_var() funtion properly?
or mabey like u said we can try it where u set the variable in the enemy gd. before _ready is called in enemy split,

javrocks | 2022-02-22 22:13

If it freezes it means there is some infinite loop or a function calling itself recursively without end. Unfortunately I can’t see where that is from the code posted so far.
I wonder if you can put a breakpoint somewhere in GDScript while the game is frozen, to see if it passes through there and see what it does (assuming Godot supports that, it might not work).

Zylann | 2022-02-22 22:14

If u could i wouldn’t know how to put a breakpoint

javrocks | 2022-02-22 22:20

is there another way to send variables across a scene

javrocks | 2022-02-22 22:27

You can try to press the pause button next to the play button instead, in the top-right corner of the editor, while the game is freezing. It will suspend the game and hopefully the script editor should point what GDScript was running at the time. Then you can step line by line using F10.

You can also place a breakpoint in a specific line by clicking in the empty aread on the left of line numbers.

And the way to send variables as described here is really the simplest. I think there is something else in your scripts that causes your game to freeze.

Zylann | 2022-02-22 22:30

I assigned the random variables instead of getting them and instanced the split scene and it works as intended.

So i don’t think some thing else is causing the freeze

javrocks | 2022-02-22 22:47

That was the first thing I suggested. I have no idea what happened with the function approach :shrug:

Zylann | 2022-02-22 23:53

This:

if enemy_health <= 0:
     var scene_instance = Split_Scene.instance()
     scene_instance.Enemy_random_value = random_value
	 scene_instance.Enemy_Texture = Random_Texture
	 scene_instance.Enemy_pos = global_position
     add_child(scene_instance) 

I also tried this. Could there be any changes

javrocks | 2022-02-23 00:10

I dont see anything in this snippet that would cause a freeze. Unless maybe the scene instance contains the enemy itself or something similar.
But either way if scene_instance is supposed to replace the one spawning it, it should not be added as child of it (see earlier comments)

Zylann | 2022-02-23 00:14

Should i send u the game
Mabey that would help

javrocks | 2022-02-23 00:35

That’s the wet-transfer link to the game

WeTransfer - Send Large Files & Share Photos Online - Up to 2GB Free

javrocks | 2022-02-23 20:09

Um…R U there?

javrocks | 2022-02-24 00:12