reckfellENGINE

Интерфейс и сигналы

Счётчик на кнопке, подписки и отписки, повторный вход в дерево и клавиатурный фокус.

На этой странице

Сигнал — сообщение объекта о событии, например о нажатии кнопки. В C# вы подписываете метод на соответствующее событие. Не нужно каждый кадр спрашивать кнопку, нажата ли она.

1. Создайте интерфейс

Создайте отдельный документ с корнем Control, назовите его Counter и сохраните как Counter.rscene. Элементы Control предназначены для интерфейса: у них есть размеры, привязки и правила размещения.

Текст
Counter (Control)
├── CountLabel (Label)
└── AddButton (Button)

Выделите корень и выберите размещение Full Rect в инструментах Layout. Для детей оставьте привязки к верхнему левому углу. В инспекторе Layout задайте:

ОбъектPositionSizeText
CountLabel(32, 32)(200, 40)0
AddButton(32, 96)(200, 48)Добавить +1

Если инспектор показывает границы Offsets, эквивалент для кнопки: Left 32, Top 96, Right 232, Bottom 144. Камера и свет для этого документа не нужны.

2. Добавьте Counter.cs

Прикрепите скрипт Scripts/Counter.cs к корню Counter, а не к кнопке. Полный код:

C#
using Reckfell;

public partial class Counter : Control
{
    private int _count;
    private Label _label = null!;
    private Button _button = null!;

    public override void _EnterTree()
    {
        _label = GetEntity<Label>("CountLabel");
        _button = GetEntity<Button>("AddButton");
        _button.Pressed += AddOne;
        _label.Text = _count.ToString();
    }

    public override void _ExitTree()
    {
        if (ReckfellObject.IsInstanceValid(_button))
            _button.Pressed -= AddOne;
    }

    private void AddOne()
    {
        _count += 1;
        _label.Text = _count.ToString();
    }
}

Сохраните, соберите C# и запустите текущий документ через F6. Нажмите кнопку несколько раз: появятся 1, 2, 3 и так далее.

Как это связано

_count хранит целое число и начинается с нуля. _label и _button хранят ссылки на дочерние объекты. При входе в дерево _EnterTree() находит уже созданных детей и подключает обработчик. Для чтения данных, которые дети вычисляют в собственном _Ready(), используйте _Ready() родителя: в _EnterTree() дети ещё могут быть не готовы.

Pressed += AddOne означает «когда кнопка сообщит о нажатии, вызови метод AddOne». Здесь AddOne записывается без круглых скобок: мы передаём обработчик события, а не вызываем его сразу.

_count += 1 увеличивает счётчик. ToString() превращает число в текст для свойства Label.Text. private означает, что поле или метод предназначены для внутренней работы этого класса. Запись null! позволяет инициализировать ссылку позже; она не создаёт Label и не исправляет ошибку в имени CountLabel.

Почему подписка имеет пару

Pressed -= AddOne отключает тот же метод, который был подключён через +=. Он вызывается в _ExitTree(): удалённый из уровня интерфейс перестаёт получать события. Проверка IsInstanceValid() учитывает, что кнопку могли удалить отдельно.

Если вернуть тот же Counter через AddChild(), _EnterTree() подключит обработчик снова, а _count сохранит значение. Это отличается от удаления через QueueFree(): новый экземпляр начнёт с нуля. Пара _EnterTree() / _ExitTree() работает и при повторном добавлении, когда _Ready() сам не повторяется.

Не подключайте Pressed одновременно этим кодом и через редактор: одно нажатие может увеличить счётчик дважды. Не создавайте подписку каждый кадр в _Process(). Для возможности отписаться используйте именованный метод; новая лямбда при -= не равна ранее подключённой лямбде.

Проверка мышью и клавиатурой

  1. После запуска нажмите кнопку три раза: подпись должна показать 3.
  2. Переведите фокус на кнопку через Tab и нажмите действие ui_accept — по умолчанию Enter или Space. Счётчик должен увеличиться на один.
  3. Если проект изменяет встроенные действия ввода, проверьте назначение ui_accept в Input Map. Для кнопки нужен разрешённый режим фокуса.

Событие Pressed подходит для одного действия по активации. Для переключателя используйте Toggle Mode и событие Toggled: состояние не стоит восстанавливать по количеству нажатий.

СимптомПроверка
Ошибка GetEntity при стартеСкрипт прикреплён к Counter; дети называются ровно CountLabel и AddButton и имеют нужные типы
Одно нажатие добавляет дваСигнал подключён ещё и в редакторе либо другой код повторяет подписку
Кнопка видна, но не нажимаетсяПроверьте Disabled, перекрывающий Control и его Mouse Filter
Tab не выделяет кнопкуПроверьте режим фокуса, видимость и действие ui_focus_next
После удаления кнопки возникла ошибка доступаНе сохраняйте непроверенную native-ссылку для позднего вызова; отключайте подписки по времени жизни

Отдельный экран или HUD

Этот документ — отдельный экран. В игре с перемещающейся камерой интерфейс поверх мира обычно помещают в CanvasLayer, а внутрь — дерево Control. Так камера мира не уносит счётчик за экран.

Для адаптивного размещения используйте контейнеры VBoxContainer, HBoxContainer и привязки, а не масштабирование текста через Scale.

Счётчик сбрасывается при новом запуске: в примере нет сохранения на диск. Справочник: Control, Button, Label.

Документация Reckfell EngineНаверх ↑
БЫСТРЫЙ ПЕРЕХОДНачало работыEntity и иерархияC# & .NET 10Сцены и префабы
Руководства и полный API Reckfell K
reckfellENGINE
RECKFELL ACCOUNT

Вход в аккаунт

Войдите в аккаунт Reckfell.

Один аккаунт для всей платформы Reckfell.