Контроллеры, геймпады и джойстики

Godot поддерживает сотни моделей контроллеров "из коробки". Контроллеры поддерживаются на Windows, macOS, Linux, Android, iOS и в веб-версии.

Примечание

Начиная с версии Godot 4.5, движок использует SDL 3 для поддержки контроллеров в Windows, macOS и Linux. Это означает, что список поддерживаемых контроллеров и их поведение должны точно соответствовать тому, что доступно в других играх и движках, использующих SDL 3. Обратите внимание, что SDL используется только для ввода, а не для управления окнами или звука.

До Godot 4.5 движок использовал собственный код поддержки контроллеров. Это могло привести к некорректной работе некоторых контроллеров. Этот пользовательский код по-прежнему используется для поддержки контроллеров на Android, iOS и в веб-версии, поэтому проблемы могут возникать только на этих платформах.

Примечание: более специализированные устройства, такие как рули, педали и HOTAS, менее протестированы и могут работать не так, как ожидалось. Переопределение силовой обратной связи для этих устройств также еще не реализовано. Если у вас есть доступ к одному из этих устройств, не стесняйтесь сообщать об ошибках на GitHub.

В этом руководстве вы узнаете:

  • Как написать логику ввода для поддержки ввода как с клавиатуры, так и с контроллера.

  • Как поведение контроллеров может отличаться от поведения клавиатуры/мыши.

  • Устранение неполадок с контроллерами в Godot.

Поддержка универсального ввода

Благодаря системе действий ввода Godot, Godot позволяет поддерживать ввод как с клавиатуры, так и с контроллера, без необходимости писать отдельные пути кода. Вместо жесткого кодирования клавиш или кнопок контроллера в ваших сценариях вам следует создать действия ввода в настройках проекта, которые затем будут ссылаться на указанные входы клавиш и контроллера.

Действия ввода подробно описаны на странице Использование InputEvent.

Примечание

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

Какой singleton метод ввода я должен использовать?

Существует 3 способа получения аналогового ввода:

  • Если у вас есть две оси (например, джойстик или движение WASD) и вы хотите, чтобы обе оси вели себя как один вход, используйте Input.get_vector():

# `velocity` will be a Vector2 between `Vector2(-1.0, -1.0)` and `Vector2(1.0, 1.0)`.
# This handles deadzone in a correct way for most use cases.
# The resulting deadzone will have a circular shape as it generally should.
var velocity = Input.get_vector("move_left", "move_right", "move_forward", "move_back")

# The line below is similar to `get_vector()`, except that it handles
# the deadzone in a less optimal way. The resulting deadzone will have
# a square-ish shape when it should ideally have a circular shape.
var velocity = Vector2(
        Input.get_action_strength("move_right") - Input.get_action_strength("move_left"),
        Input.get_action_strength("move_back") - Input.get_action_strength("move_forward")
).limit_length(1.0)
  • Если у вас есть одна ось, которая может двигаться в обе стороны (например, дроссель на ручке управления полетом), или когда вы хотите обрабатывать отдельные оси индивидуально, используйте Input.get_axis():

# `walk` will be a floating-point number between `-1.0` and `1.0`.
var walk = Input.get_axis("move_left", "move_right")

# The line above is a shorter form of:
var walk = Input.get_action_strength("move_right") - Input.get_action_strength("move_left")
  • Для других типов аналогового ввода, таких как обработка триггера или обработка одного направления за раз, используйте Input.get_action_strength():

# `strength` will be a floating-point number between `0.0` and `1.0`.
var strength = Input.get_action_strength("accelerate")

Для неаналогового цифрового/логического ввода (только значения «нажато» или «не нажато»), например кнопок контроллера, кнопок мыши или клавиш клавиатуры, используйте Input.is_action_pressed():

# `jumping` will be a boolean with a value of `true` or `false`.
var jumping = Input.is_action_pressed("jump")

Примечание

Если вам нужно узнать, было ли действие ввода только что совершено в предыдущем кадре, используйте Input.is_action_just_pressed() вместо Input.is_action_pressed(). В отличие от Input.is_action_pressed(), который возвращает true, пока кнопка зажата, Input.is_action_just_pressed() вернёт true только в течение одного кадра после нажатия кнопки.

Vibration (Вибрация)

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

Используйте метод start_joy_vibration синглтона Input, чтобы запустить вибрацию геймпада. Используйте stop_joy_vibration, чтобы остановить вибрацию раньше (полезно, если при запуске не была указана длительность).

На мобильных устройствах вы также можете использовать vibrate_handheld, чтобы вибрировало само устройство (независимо от геймпада). На Android для этого требуется, чтобы разрешение VIBRATE было включено в пресете экспорта для Android перед экспортом проекта.

Примечание

Для некоторых игроков вибрация может вызывать дискомфорт. Обязательно предоставьте внутриигровой ползунок для отключения вибрации или уменьшения её интенсивности.

Различия между клавиатурой/мышью и вводом контроллера

Если вы привыкли обрабатывать ввод с клавиатуры и мыши, вы можете быть удивлены тем, как контроллеры справляются с конкретными ситуациями.

Мертвая зона

В отличие от клавиатур и мышей, контроллеры предлагают оси с аналоговыми входами. Преимущество аналоговых входов в том, что они обеспечивают дополнительную гибкость действий. В отличие от цифровых входов, которые могут обеспечить силу только 0.0 и 1.0, аналоговый вход может обеспечить любую силу между 0.0 и 1.0. Недостатком является то, что без системы мертвых зон сила аналоговой оси никогда не будет равна 0.0 из-за того, как физически построен контроллер. Вместо этого она будет задерживаться на низком значении, таком как 0.062. Это явление известно как дрейф и может быть более заметно на старых или неисправных контроллерах.

В качестве реального примера возьмем гоночную игру. Благодаря аналоговым входам мы можем медленно направлять автомобиль в ту или иную сторону. Однако без системы мертвых зон автомобиль будет медленно двигаться сам по себе, даже если игрок не прикасается к джойстику. Это происходит потому, что сила оси направления не будет равна 0.0, когда мы этого ожидаем. Поскольку мы не хотим, чтобы в этом случае автомобиль управлялся сам по себе, мы определяем значение "мертвой зоны" 0.2, которое будет игнорировать все входные данные, сила которых меньше 0.2. Идеальное значение мертвой зоны достаточно высоко, чтобы игнорировать ввод, вызванный дрейфом джойстика, но достаточно низко, чтобы не игнорировать фактический ввод от игрока.

В Godot есть встроенная система мертвых зон для решения этой проблемы. Значение по умолчанию — 0.5, но вы можете настроить его для каждого действия отдельно во вкладке Input Map (Список действий) в Project Settings. Для Input.get_vector() мертвая зона может быть указана как необязательный 5-й параметр. Если он не указан, будет вычислено среднее значение мертвой зоны из всех действий в векторе.

"Эхо" события

В отличие от ввода с клавиатуры, удержание кнопки контроллера, например направления крестовины, не будет генерировать повторяющиеся события ввода через фиксированные интервалы (также известные как события «эха»). Это связано с тем, что операционная система вообще никогда не отправляет «эхо»-события для ввода контроллера.

Если вы хотите, чтобы кнопки контроллера отправляли события echo, вам придётся генерировать объекты InputEvent в коде и анализировать их с помощью Input.parse_input_event() с регулярными интервалами. Это можно сделать с помощью узла Timer.

Фокус окна

В отличие от ввода с клавиатуры, ввод с контроллера виден всем окнам операционной системы, включая неактивные окна.

Хотя это полезно для стороннего функционала разделения экрана <https://nucleus-coop.github.io/>, это также может иметь негативные последствия. Игроки могут случайно отправить команды контроллера запущенному проекту, взаимодействуя с другим окном.

Если вы хотите игнорировать события, когда окно проекта не сфокусировано, вам нужно создать autoload с названием Focus со следующим скриптом и использовать его для проверки всех ваших входных данных:

# Focus.gd
extends Node

var focused := true

func _notification(what: int) -> void:
    match what:
        NOTIFICATION_APPLICATION_FOCUS_OUT:
            focused = false
        NOTIFICATION_APPLICATION_FOCUS_IN:
            focused = true


func input_is_action_pressed(action: StringName) -> bool:
    if focused:
        return Input.is_action_pressed(action)

    return false


func event_is_action_pressed(event: InputEvent, action: StringName) -> bool:
    if focused:
        return event.is_action_pressed(action)

    return false

Затем вместо Input.is_action_pressed(action) используйте Focus.input_is_action_pressed(action), где action — имя действия ввода. Также вместо event.is_action_pressed(action) используйте Focus.event_is_action_pressed(event, action), где event — ссылка на InputEvent, а action — имя действия ввода.

Профилактика энергосбережения

В отличие от ввода с клавиатуры и мыши, ввод с контроллера не блокирует спящий режим и меры энергосбережения (например, выключение экрана по истечении определенного времени).

Чтобы решить эту проблему, Godot по умолчанию включает режим энергосбережения при запуске проекта. Если вы заметили, что система отключает дисплей при игре с геймпадом, проверьте значение параметра Display > Window > Energy Saving > Keep Screen On в настройках проекта.

Устранение неполадок

См. также

Вы можете просмотреть список известных проблем с поддержкой контроллера на GitHub.

Мой контроллер не распознается Годо.

Сначала проверьте, распознаётся ли ваш контроллер другими приложениями. Вы можете воспользоваться сайтом Gamepad Tester, чтобы убедиться, что ваш контроллер распознаётся.

В Windows Godot поддерживает не более 4 контроллеров одновременно. Это связано с тем, что Godot использует API XInput, который поддерживает только 4 контроллера одновременно. Дополнительные контроллеры, превышающие это ограничение, Godot игнорирует.

У моего контроллера неправильно назначены кнопки или оси.

Во-первых, если ваш контроллер предоставляет утилиту обновления прошивки, обязательно запустите её, чтобы получить последние исправления от производителя. Например, прошивку контроллеров Xbox One и Xbox Series можно обновить с помощью приложения Xbox Accessories app. (Это приложение работает только в Windows, поэтому для обновления прошивки контроллера вам потребуется компьютер с Windows или виртуальная машина Windows с поддержкой USB.) После обновления прошивки контроллера отсоедините контроллер от ПК и снова подключите его, если вы используете контроллер в беспроводном режиме.

Если кнопки назначены неправильно, это может быть связано с ошибочным назначением в базе данных игровых контроллеров SDL, используемой Godot, или в базе данных игровых контроллеров Godot <https://github.com/godotengine/godot/blob/master/core/input/godotcontrollerdb.txt>. В этом случае вам потребуется создать пользовательское назначение для вашего контроллера.

Существует множество способов создания сопоставлений. Один из вариантов — использовать мастер сопоставлений из official Joypads demo. Получив работающее сопоставление для контроллера, вы можете протестировать его, определив переменную окружения SDL_GAMECONTROLLERCONFIG перед запуском Godot:

export SDL_GAMECONTROLLERCONFIG="your:mapping:here"
./path/to/godot.x86_64

Чтобы протестировать сопоставления на платформах, отличных от настольных компьютеров, или распространить свой проект с дополнительными сопоставлениями контроллеров, вы можете добавить их, вызвав Input.add_joy_mapping() как можно раньше в функции скрипта _ready().

Если вы удовлетворены пользовательским сопоставлением, вы можете внести его в следующую версию Godot, открыв запрос на извлечение в базу данных игровых контроллеров Godot.

Мой контроллер работает на данной платформе, но не работает на другой платформе.

Linux

Если вы используете бинарный файл движка, скомпилированный самостоятельно, убедитесь, что он скомпилирован с поддержкой udev. Эта поддержка включена по умолчанию, но её можно отключить, указав udev=no в командной строке SCons. Если вы используете бинарный файл движка, поставляемый дистрибутивом Linux, дважды проверьте, скомпилирован ли он с поддержкой udev.

Контроллеры по-прежнему могут работать без поддержки udev, но это менее надежно, поскольку необходимо использовать регулярный опрос для проверки подключения или отключения контроллеров во время игры (горячее подключение).

Android/iOS

Как описано в начале страницы, поддержка контроллеров на мобильных платформах основана на пользовательской реализации, а не на использовании SDL для ввода данных. Это означает, что поддержка контроллеров может быть менее надёжной, чем на настольных платформах.

Поддержка ввода контроллера на основе SDL на мобильных платформах запланирована в будущем выпуске.

Web

Поддержка Web-контроллеров зачастую менее надёжна по сравнению с "родными" платформами. Качество поддержки контроллеров, как правило, сильно различается в разных браузерах. В результате вам, возможно, придётся попросить игроков использовать другой браузер, если у них не получится запустить контроллер.

Как и для мобильных платформ, поддержка ввода контроллера на основе SDL на веб-платформе запланирована в будущем выпуске.