Как подружить Steam, Unity и контроллеры
Приветствую разработчики игр. ДНО снова выходит на связь. Речь пойдет о том, как подружить Unity и Steam в контексте устройств ввода. Сейчас у меня на руках есть такие контроллеры как: Steam Controller, XBox360, XBoxOne, PS4 и PS5. И задача стояла - запустить их все через Steam Input. Смотри как это сделать, даже без аккаунта разработчика.
Информация из документации Steam
«Система ввода Steam» (Steam Input) — это общий термин для всех устройств, программного обеспечения и настроек утилит, которые Steam использует для взаимодействия с играми.
Интерфейс настройки системы ввода Steam (Steam Input Configurator, SIC) встроен в клиент Steam и находится между игроком и игрой/приложением. Интерфейс ввода получает сигналы от устройства ввода и переводит эти данные должным образом — в зависимости от того, какие настройки установлены у игрока, прежде чем передать их игре.
API ввода Steam — программный интерфейс, который разработчики используют, чтобы напрямую общаться с интерфейсом ввода SIC в режиме встроенной поддержки. API контроллера не обязателен для работы режима совместимости.
Более полную информацию, вы можете найти здесь
К сожалению, для Unity нет встроенной поддержки, поэтому для связи нужно использовать сторонние решения. На данный момент есть два: Steamworks.NET и Facepunch.Steamworks.
Подготовка файла с внутриигровыми действиями (IGA)
Нужно подготовить конфигурацию действий, которые мы будем использовать в игре. По сути это инструкции событий для устройства ввода. А сам игрок сможет перенастроить эти действия в Steam.
Создадим файл вручную. Внутри папки Steam создаем папку "controller_config" (например, C:/Program Files (x86)/Steam/controller_config) и там создаем файл game_actions_480.vdf
Где 480 - идентификатор приложения (AppID). В данном случае 480 - идентификатор игры SpaceWar (приложение-образец с API Steamworks)
Если у вас уже есть страница игры, то вместо 480 используйте свой AppID.
Я специально убрал всё лишнее, оставив лишь одно действие.
GameControls - название группы действий, которое мы будем обрабатывать из кода. # Set_GameControls - ссылка для локализации настроек контроллера игрока.
Jump - название действия, которое мы будем обрабатывать из кода. Соответственно # Action_Jump ссылается на значение, которое будет видеть игрок, изменяя событие на другую кнопку.
Чтобы попробовать и понять как это работает, нам этого хватит. Более подробно о IGA
Facepunch.Steamworks
Начнем с более “дружелюбного” решения от Facepunch Studios (Rust и Garry's Mod). Установка простая: скачать и распаковать в директорию проекта.
Вызовы инициализации, обновления и завершения:
Steamworks.SteamClient.Init(480);
Steamworks.SteamClient.RunCallbacks();
Steamworks.SteamClient.Shutdown();
Запустив проект в Unity, после инициализации Facepunch.Steamworks подтянет файл с внутриигровыми действиями (IGA) game_actions_480.vdf. Запустится в Steam SpaceWar. И если у вас подключен контроллер, то вы сможете назначить действие Jump на одну из кнопок.
А теперь давай поймаем событие Jump.
Немного приколов и важных штук!
При подключении контроллера, после запуска SpaceWar, вы можете в Unity получать ошибку:
<RI.Hid> Failed to get preparsed data: Операция успешно завершена.
Если остановить игру, то вы увидите, что SpaceWar по прежнему запущен. Закрыв SpaceWar - у вас скорее всего закроется Unity. И нужно будет её повторно запускать. Эти проколы я не смог решил. Причем, после долгой работы, у меня даже зависал SpaceWar. И приходилось перезапускать Steam.
По началу, я не мог понять, почему у меня после получения RI.Hid отваливались контроллеры. Даже переставали идти вызовы UnityEngine.Input. Приходилось перезапускать и Steam и Unity.
Вызовы Steamworks для события Jump, то появлялись, то проходили мимо. Так я полез во второе решение Steamworks.NET. Но результат был только хуже. В итоге после целого дня ударов об стену, нашел следующую рекомендацию:
Launch your steam client with the following command line parameter: -forcecontrollerappid your_game's_AppID . This ensures that controllers are bound to the game window and nothing else, which could interfere with your debugging session. Example: D:\Programs\Steam\Steam.exe -forcecontrollerappid 480. In your code make sure that you activate an ActionSet before trying to receive input data from this set.
Запустив Steam с командой “-forcecontrollerappid 480” - ошибка RI.Hid по прежнему была, но теперь Steamworks не терял контроллеры.
Steamworks.NET
Более сложное решение, но пока что мне оно нравится больше. Возможно потому, что я в Facepunch.Steamworks не нашел как вибрировать контроллером. Но вероятно, я плохо искал.
Установить Steamworks.NET можно через unitypackage, Package Manager через ссылку git или распаковать вручную, скачав архив с github. Я пробовал 1 и 3 варианты.
После установки нужно добавить AppID в файл steam_appid.txt. Он будет лежать в корне проекта игры. Для работы с Steamworks, автор добавил скрипт SteamManager. В нем происходит инициализация, обновление и завершение.
Сначала вызовем SteamManager.Initialized. Затем "простимулируем" систему ввода SteamInput.Init();
Нужно собрать инструкции внутриигровых действий. В Facepunch.Steamworks этого не требовалось. Но так как у нас мало таких действий, вот пример того, как это можно собрать:
Это своего рода кеширование. Мы заранее соберем всю информацию обработчиков действий, контроллеров и прочее.
Нужна информация о контроллерах:
Когда будете экспериментировать, обращайте внимание на документацию ISteamInput. STEAM_INPUT_MAX_COUNT - максимальное количество контроллеров, которые могут использоваться одновременно в конфигураторе системы ввода Steam.
А теперь давай поймаем событие Jump. Просто для примера, без прохода по массиву, возьму нулевой элемент из контроллеров:
А если хотите повибрировать :)
Перед обработкой событий системы ввода, можно также сделать вызов SteamInput.RunFrame(). Он синхронизует состояние API с последними доступными элементами ввода контроллера. Это автоматически выполняет SteamManager с помощью SteamAPI.RunCallbacks(), но чтобы задержка была минимально возможной, вы можете вызвать функцию RunFrame() непосредственно перед чтением состояния контроллера.
Выводы
Зачем я это всё здесь написал, а ты возможно и прочитал… Время! Просто у меня это заняло больше времени, чем займет у тебя после прочитанного.
Если собираешься выходить в Steam, то лучше всего использовать Steam Input. Как минимум игрок будет ближе к твоей игре своими устройствами вибрации ;)
А что использовать, Facepunch.Steamworks или Steamworks.NET ? Ну, начни с Facepunch.Steamworks. Мы рассмотрели лишь одну сторону - систему ввода, а тебе ещё понадобится две другие - достижения и облачное хранение…
Следующее в моем плане изучение работы достижений и облачное хранение. И вот тогда точно, я окончательно приму решение - Facepunch.Steamworks или Steamworks.NET.
Спасибо за внимание.
ДНО (даю немного обучения)
[Отредактировано]
Спасибо вам за комментарии. После прочтения решил, что нужно сказать...
Не в коем случае я не настаиваю использовать steamworks ради Steam Input, тем более Steam Input вместо Input System Unity. Статья лишь демонстрирует, как завести устройства через Steam Input, ну и как воспользоваться частью Steam API.
Сам я недавно перешел на Input System в Unity и это отличная штука. Всем, кто начинает работать с Unity, начинайте с Input System. А те, кто работают давно, думаю и так этим пользуются.