События ввода и интерфейс
Выберите обработчик ввода, пропустите события через UI и остановите их распространение.
Где обрабатывать ввод
| Задача | Место |
|---|---|
| Непрерывное движение, сила нажатия стика | Input в _PhysicsProcess() |
| Игровое действие после интерфейса | _UnhandledInput(InputEvent) |
| Клавиатурные события после интерфейса | _UnhandledKeyInput(InputEvent) |
| Собственная кнопка или область UI | Control._GuiInput(InputEvent) |
| Перехват до интерфейса | _Input(InputEvent); используйте только при необходимости |
В пределах Viewport событие проходит _Input(), затем подходящие элементы UI. Если оно ещё не обработано, следуют _ShortcutInput(), _UnhandledKeyInput() для клавиш и _UnhandledInput(). Это упрощённый порядок: встроенные окна, вложенные Viewport и выбор физических объектов добавляют свои этапы. Отметка «обработано» останавливает последующие этапы этого события.
Действие после UI
Добавьте interact в Project Settings → Input Map и назначьте E. Прикрепите InteractReceiver.cs к обычной Entity игрового уровня:
using Reckfell;
public partial class InteractReceiver : Entity
{
public int Interactions { get; private set; }
public override void _UnhandledInput(InputEvent @event)
{
if (!@event.IsActionPressed("interact"))
return;
Interactions++;
ReckfellApi.Print("Interaction ", Interactions);
GetViewport().SetInputAsHandled();
}
}Соберите и запустите. Нажатие E увеличит счётчик один раз, если UI не забрал событие. У InputEvent.IsActionPressed() по умолчанию allowEcho = false: повторы удерживаемой клавиши не считаются новыми нажатиями. SetInputAsHandled() не даёт следующим получателям обработать это же событие.
Внутри Control._GuiInput() используйте AcceptEvent() для принятого UI-события. Для мыши важны размер элемента, его MouseFilter, порядок перекрытия и положение курсора; для клавиатуры — фокус. MouseFilter.Stop автоматически останавливает события указателя на Control даже без явного AcceptEvent(); у прокрутки есть отдельное правило передачи родителю.
Опрос Input не блокируется обработанным событием
Input.IsActionPressed() читает общее состояние устройства, а не список необработанных событий. Нажатие, принятое меню, всё ещё может учитываться игровым опросом. Отключайте игровое управление явно или приостанавливайте соответствующую ветку.
Input.ActionPress() меняет состояние действия для опроса, но не отправляет событие в _Input(). Для синтетического события используется Input.ParseInputEvent(); для изолированного Viewport — PushInput(). Не используйте синтетический ввод как замену проверки реального устройства.
Найдите причину
| Симптом | Что проверить |
|---|---|
| Одно нажатие даёт два действия | Один и тот же код в _Input() и _UnhandledInput(), два активных слушателя или повторная подписка. Оставьте одного владельца игрового действия; не вызывайте оба обработчика вручную. |
Клавиша не доходит до _UnhandledInput() | Привязку interact в Input Map и Control с клавиатурным фокусом: интерфейс мог уже поглотить событие. Для диагностики наблюдайте _Input(), но не переносите туда игровое действие в обход меню. |
| Кнопка под изображением не получает щелчок | Размеры и порядок перекрывающих Control. Для чисто декоративного слоя задайте MouseFilter.Ignore; интерактивному UI это значение без необходимости не назначайте. |
| Персонаж двигается через открытое меню | Игровой код опрашивает Input, который не учитывает поглощение события. При открытии меню явно отключайте игровое управление или приостанавливайте их ветвь. |
Не смешивайте дискретное событие и удержание: @event.IsActionPressed() подходит для одного действия, Input.IsActionPressed() — для состояния удержания.