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

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 дозволяє підтримувати як введення з клавіатури, так і з контролера, без необхідності писати окремі шляхи коду. Замість жорсткого кодування клавіш, або кнопок контролера, у скриптах слід створити дії вводу в Параметрах проекту, які потім будуть посилатися на вказані вхідні дані клавіш та контролера.

Дії вводу детально пояснюються на сторінці Використання inputEvent.

Примітка

На відміну від введення з клавіатури, підтримка, як введення з мишки, так і з контролера, для дій (наприклад, озирнутися навколо в грі від першої особи) вимагатиме різних кодових шляхів, оскільки вони повинні оброблятися окремо.

Який метод singleton Input слід використовувати?

Існує 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 лише протягом одного кадру після натискання кнопки натиснутий.

Вібрація

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

Використовуйте метод Input singleton start_joy_vibration, щоб почати вібрувати геймпад. Використовуйте 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.get_vector() мертву зону можна вказати як необов’язковий 5-й параметр. Якщо не вказано, буде обчислено середнє значення мертвої зони з усіх дій у векторі.

Події "Відлуння"

На відміну від введення з клавіатури, утримування кнопку контролера, такої як напрямок D-pad, не буде генерувати повторювані події введення через фіксовані проміжки часу (також відомі як події "відлуння"). Це пов'язано з тим, що операційна система ніколи не надсилає події "відлуння" для введення з контролера.

Якщо ви хочете, щоб кнопки контролера надсилали події відлуння, вам доведеться генерувати об'єкти 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 активує запобігання енергозбереженню за замовчуванням під час виконання проекту. Якщо ви помітили, що система вимикає свій дисплей під час гри з геймпадом, перевірте значення Дисплей > Вікно > Енергозбереження > Залишати екран увімкненим у налаштуваннях проекту.

У Linux запобігання енергозбереженню вимагає, щоб механізм міг використовувати D-Bus. Перевірте, чи D-Bus встановлено та доступний, якщо проект виконується у Flatpak, оскільки обмеження ізольованого програмного середовища можуть зробити це неможливим за замовчуванням.

Вирішення проблем

Дивись також

Список відомих проблем з підтримкою контролерів ви можете переглянути на GitHub.

Godot не розпізнає мій контролер.

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

У Windows Godot підтримує лише до 4 контролерів одночасно. Це тому, що Godot використовує API XInput, який обмежено підтримкою 4 контролерів одночасно. Додаткові контролери вище цього ліміту ігноруються Godot.

На моєму контролері неправильно зіставлені кнопки, або осі.

По-перше, якщо ваш контролер підтримує якусь утиліту оновлення мікропрограми, обов’язково запустіть її, щоб отримати останні виправлення від виробника. Наприклад, мікропрограми контролерів Xbox One і Xbox Series можна оновити за допомогою програми «Аксесуари Xbox» <https://www.microsoft.com/en-us/p/xbox-accessories/9nblggh30xj3>`__. (Ця програма працює лише в Windows, тому для оновлення мікропрограми контролера потрібно використовувати машину Windows або віртуальну машину Windows із підтримкою USB.) Після оновлення мікропрограми контролера роз’єднайте контролер і знову з’єднайте його з комп’ютером, якщо ви за допомогою контролера в бездротовому режимі.

Якщо кнопки зіставлено неправильно, це може бути пов’язано з помилковим зіставленням із бази даних ігрового контролера SDL, яку використовує Godot, або бази даних ігрового контролера Godot. У цьому випадку вам потрібно буде створити настроюване відображення для вашого контролера.

Існує багато способів створення відображень. Одним із варіантів є використання майстра зіставлення в офіційній демонстрації Joypads. Коли у вас буде робоче відображення для вашого контролера, ви можете перевірити його, визначивши змінну середовища SDL_GAMECONTROLLERCONFIG перед запуском Godot:

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

Щоб перевірити зіставлення на платформах без настільних комп'ютерів, або розповсюдити проект з додатковими зіставленнями контролерів, ви можете додати їх викликавши Input.add_joy_mapping(), якомога раніше у функції скрипту _ready().

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

Мій контролер працює на даній платформі, але не на іншій платформі.

Linux

Якщо ви використовуєте самостійно скомпільований бінарний файл двигуна, переконайтеся, що він скомпільований із підтримкою udev. Це ввімкнено за замовчуванням, але можна вимкнути підтримку udev, вказавши udev=no у командному рядку SCons. Якщо ви використовуєте двійковий файл двигуна, що надається дистрибутивом Linux, ще раз перевірте, чи він був скомпільований з підтримкою udev.

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

Android/iOS

Як описано у верхній частині сторінки, підтримка контролерів на мобільних платформах базується на спеціальній реалізації, а не на використанні SDL для введення даних. Це означає, що підтримка контролерів може бути менш надійною, ніж на настільних платформах.

Підтримка вводу контролера на основі SDL на мобільних платформах планується у майбутньому випуску.

Інтернет

Підтримка веб-контролерів часто є менш надійною порівняно з «нативними» платформами. Якість підтримки контролерів може значно відрізнятися в різних браузерах. Як результат, вам може знадобитися порадити гравцям використовувати інший браузер, якщо їхній контролер не працює.

Як і для мобільних платформ, підтримка введення даних контролера на основі SDL на веб-платформі планується у майбутньому випуску.