Годо - Отсутствующие узлы

Это сложно объяснить набором текста ...

У меня есть сцена GameController (Node2D), которая содержит 3 сцены внутри:

  • Мышь (сцены / Mouse.tscn) - просто меняет курсор мыши на пользовательскую графику.
  • HeaderBar (сцены / HeaderBar.tscn) - это счет / метка, которая находится наверху
  • Сообщения (сцены / Messages.tscn) - это всплывающее окно сообщения, которое отображает текст для пользователя

В основной сцене (Level1.tscn) я использую сцену GameController, и она отлично работает. Там есть панель заголовка с оценкой / меткой, а также пользовательский курсор мыши и окно сообщения (но по умолчанию оно скрыто, но если я переключу его видимость на пульте дистанционного управления, оно появится).

Вот в чем мое замешательство ...

Если я попытаюсь в сценарии GameController манипулировать любыми из этих узлов в сцене GameController (мышь, заголовок, сообщения), они вернутся как null и выдадут ошибку. Например; если я попытаюсь обновить счет в $ HeaderBar / Control / score, я получаю следующее:

Invalid set index 'text' (on base: 'null instance') with value of type 'String'.

Завершение кода будет автоматически заполнять имена узлов по мере их ввода (чтобы он распознавал их в группе), но любая попытка ссылаться / использовать их в скрипте вызывает ошибки, аналогичные приведенным выше.

Я новичок в Годо, поэтому уверен, что у меня просто какое-то недоразумение относительно того, как работает этот тип вещей, но я в тупике! Любое понимание очень ценится!

ОБНОВЛЕНИЕ

Я постараюсь немного упростить свое объяснение (я внес некоторые изменения). Хорошо, вот сценарий объекта:

extends StaticBody2D

onready var main = load("res://scenes/MainGame.gd").new()

func _ready():
    pass

# mouse [left] clicked on object
func _on_trigger_input_event(viewport, event, shape_idx):
    if Input.is_action_just_pressed("left-click"):
        main.display_message("you [left] clicked on the object!")

вызов main.display_message () работает. Он действительно вызывает функцию, но вот эта функция в MainGame.gd

extends Node2D

onready var box = $Message/Control
onready var label = $Message/Control/Label


func _ready():
    # hide the mouse cursor (will use custom cursor)
    Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN)
    
func display_message(msg):
    label.text = msg
    box.visible = true

Это происходит из-за того, что метка (и поле) равны нулю. Если я вызываю display_message из функции _ready (в MainGame.gd), он работает как надо. Вызовите его извне (в Object.gd), и по какой-то причине узлы будут нулевыми.


person JeremyPage    schedule 04.06.2021    source источник
comment
Что приходит в голову: либо опечатка, либо что-то удаляет узел.   -  person Theraot    schedule 04.06.2021
comment
Я перепечатал примерно 200 раз: D Так что не думаю, что это опечатка. У меня тоже была мысль, что что-то удаляло узел, но будь я проклят, если узнаю, что именно! Еще одна информация, которую я только что понял, заключается в том, что если я выполняю оператор печати в функции _ready, он печатается 5 раз (он также ведет себя так же, если я выполняю оператор печати в функции _unhandled_input (для щелчка правой кнопкой мыши Например)   -  person JeremyPage    schedule 04.06.2021
comment
Похоже, у вас несколько экземпляров. Возможно, у некоторых из них есть эти узлы, а у других нет. Есть ли другое место, где вы их используете? Используете ли вы, например, автозагрузку для чего-либо из этого?   -  person Theraot    schedule 04.06.2021
comment
Вместо этого я переместил все функции из сценария GameController в сценарий Messages.gd. extends CanvasLayer onready var message_shell = $messageShell onready var message_label = $messageShell/messageBox/Label func _ready(): print(message_label.text) func display_message(msg): print("yes boy... yes!!") message_label.text = str(msg) # message_shell.visible = true инструкция _ready print работает. Когда я вызываю функцию display_message (из сценария игрового контроллера), она снова выдает ошибку (нулевой экземпляр). Не знаю, как это правильно отформатировать ...   -  person JeremyPage    schedule 04.06.2021
comment
Хорошо, если я соглашусь с идеей, что вы создаете экземпляры несколько раз ... Вероятно, вы вызываете display_message для экземпляра, который вы не добавляли в дерево сцены. Как выглядит код, из которого вы его вызываете? Также добавьте код вопроса, вы можете его редактировать.   -  person Theraot    schedule 04.06.2021


Ответы (1)


Это соответствует сценарию, как и ожидалось:

onready var main = load("res://scenes/MainGame.gd").new()

Однако этот код будет запущен, когда экземпляр сцены будет добавлен в дерево сцены:

onready var box = $Message/Control
onready var label = $Message/Control/Label


func _ready():
    # hide the mouse cursor (will use custom cursor)
    Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN)

Да, и onready переменные, и _ready будут работать, когда они будут добавлены в дерево сцены.

А когда вы добавляете main в дерево сцен? Я не вижу где.

Затем, когда вы это сделаете:

main.display_message("you [left] clicked on the object!")

И box, и label будут по-прежнему иметь значение NULL (значение по умолчанию).

Таким образом, добавьте его в дерево сцены, например:

func _ready():
    add_child(main)

Вот только это тоже не работает, не так ли? Посмотрите на код еще раз:

onready var main = load("res://scenes/MainGame.gd").new()

Вы создаете экземпляр сценария. сценарий. Не сцена. У него не будет дочерних узлов и так далее. Вы хотите создать экземпляр сцены, например:

onready var main = load("res://scenes/MainGame.tscn").instance()

Однако мне кажется странным, что вы делаете это в StaticBody2D. Я не думаю, что это имеет смысл, что MainGame принадлежит StaticBody2D.

Я подозреваю, что вы запускаете MainGame экземпляры в нескольких местах, ожидая, что это будет один и тот же экземпляр. Но это не тот же экземпляр, это новый экземпляр.

Здесь я предлагаю вам превратить MainGame в автозагрузку, чтобы получить единственный экземпляр, к которому вы можете получить доступ откуда угодно. Однако, возможно, это тоже неправильно. Возможно, вам стоит использовать сигнальную шину. См. Почему эта переменная продолжает возвращаться к исходному значению?, у которой была аналогичная проблема (они пытались открыть дверь, вы пытаетесь показать сообщение, но все же).

person Theraot    schedule 04.06.2021
comment
Большое спасибо за то, что нашли время помочь! Я думаю, совершенно очевидно, что более 25 лет веб-разработки не переводят один на один с разработкой игр! Две разные вещи! Мне нужно многому научиться! Я все-таки вставил его в автозагрузчик, и он работает, но он просто кажется ... Не знаю, не так уж элегантно, как мне кажется? Это действительно мой первый настоящий проект с Годо, поэтому я слишком беспокоюсь о том, чтобы сделать его идеальным (пока): D Еще раз спасибо за ваше время / помощь! - person JeremyPage; 05.06.2021