Hello, I'm learning how to program. When I tried running this script I wrote, I get an error saying the instance for the variable ArmorSlot and WeaponSlot are empty.

I'm using Godot 4.0's alpha 14.

This is the scene tree:

This is the Player script:

extends Node2D

var ArmorSlot = $ArmorSlot
var WeaponSlot = $WeaponSlot

func _process(_delta):
	if Input.is_action_just_pressed("ui_click"):
		pass
	if Input.is_action_just_pressed("ui_rightClick"):
		equipmentChanged("armorSlot")


func equipmentChanged(equipmentType):
	match equipmentType:
		"armorSlot":
			defense = ArmorSlot.defenseStat
		"weaponSlot":
			attack = WeaponSlot.attackStat
		_:
			print("No match found in equimpentChanged function, doing nothing")

Error:

E 0:00:00:0936   @implicit_new: Cannot get path of node as it is not in a scene tree.
E 0:00:00:0936   @implicit_new: Node not found: "ArmorSlot" (relative to "").

I also notice that if I don't create the variables var ArmorSlot and var WeaponSlot, and write the slots with the dollar signs in the equipmentChanged funtion, I don't get an error and it works!:

func equipmentChanged(equipmentType):
	match equipmentType:
		"armorSlot":
			defense = $ArmorSlot.defenseStat
		"weaponSlot":
			attack = $WeaponSlot.attackStat
		_:
			print("No match found in equimpentChanged function, doing nothing")

I'm definitely creating the variables for the children wrong, how should I do it correctly? Thank you for taking the time to help!

  • DaveTheCoder replied to this.
  • CrabIRL var ArmorSlot = $ArmorSlot
    var WeaponSlot = $WeaponSlot

    In Godot 3.x, that should be:

    onready var ArmorSlot = $ArmorSlot
    onready var WeaponSlot = $WeaponSlot

    In Godot 4, onready was changed to @onready, but I'm not sure if that needs to be on a separate line.

    The reason you need that is because $ArmorSlot and $WeaponSlot reference nodes in the scene tree, and until those nodes are "ready", they may not be in the scene tree. Using "onready" is equivalent to initializing the variables in the _ready() method.

    Your equipmentChanged() method is evidently called later, after _ready(), which is why it works.

    CrabIRL changed the title to "Cannot get path of node as it is not in a scene tree." .

    CrabIRL var ArmorSlot = $ArmorSlot
    var WeaponSlot = $WeaponSlot

    In Godot 3.x, that should be:

    onready var ArmorSlot = $ArmorSlot
    onready var WeaponSlot = $WeaponSlot

    In Godot 4, onready was changed to @onready, but I'm not sure if that needs to be on a separate line.

    The reason you need that is because $ArmorSlot and $WeaponSlot reference nodes in the scene tree, and until those nodes are "ready", they may not be in the scene tree. Using "onready" is equivalent to initializing the variables in the _ready() method.

    Your equipmentChanged() method is evidently called later, after _ready(), which is why it works.

      DaveTheCoder Thank you very much. That makes sense and works!

      If I can ask an additional question then, why does writing the variables in the _ready() method cause the equipmentChanged function to throw an error saying the variable hasn't been initialized yet? If I did want to declare the variable in the _ready() method, it wouldn't let me?

      func _ready():
      	var WeaponSlot = $WeaponSlot
      	var ArmorSlot = $ArmorSlot
      ...
      
      func equipmentChanged(equipmentType):
      	match equipmentType:
      		"armorSlot":
      			defense = ArmorSlot.defenseStat
      		"weaponSlot":
      			attack = WeaponSlot.attackStat
      		_:
      			print("No match found in equimpentChanged function, doing nothing")

      error:

      Parse Error: Identifier "ArmorSlot" not declared in the current scope.
      Parse Error: Identifier "WeaponSlot" not declared in the current scope.

      Thank you for helping!

      func _ready():
          var WeaponSlot = $WeaponSlot
          var ArmorSlot = $ArmorSlot

      That makes the variables local to _ready(). They're not visible outside that function.

      This would work:

      var WeaponSlot
      var ArmorSlot
      
      func _ready():
          WeaponSlot = $WeaponSlot
          ArmorSlot = $ArmorSlot