Допиливаем VirtualMouse в новой Input System, для геймпада в Unity

—

от автора

Пакет Input System в установщике

Пакет Input System в установщике

Привет, Хабр! Читаю Хабр с момента его появления, но всегда только читал и этой статьей решил изменить ситуацию. Меня зовут Вениамин Афанасьев и я cоло инди разработчик, работающий в Unity. Довольно часто сталкиваюсь с различными проблемами движка и способах их решения. Сегодня я расскажу вам как заставить VirtualMouse из нового Input System Unity работать.

В своей новой игре VICCP-2 Core, я решил добавить поддержку геймпада и для этого установил новый Input System. Ожидалось, что в новой системе всё будет работать из коробки и в документации была описана эта возможность. В пакете даже есть проект с примером (картинка выше).

Компонент Virtual Mouse

Компонент Virtual Mouse

У пакета есть 2 режима отображения курсора: Hardware и Software. И тут же возникла первая проблема, у мышки и у геймпада были разные курсоры. При включении Hardware курсора, нажатия с мышки переставали регистрироваться. В довесок при управлении с геймпада курсор выходил за пределы экрана. Зум колесика не синхронизировался. Ситуация сложилась, что вроде оно работает, но пользоваться этим невозможно.

Естественно я сразу полез в интернет искать решение. Нашел кучу форумов, роликов на ютубе где пытались решить это. Но к моему удивлению ничего не нашел, за исключением одного ролика, но данный подход меня не удовлетворил.

Далее заметил, что пакет ставит 1.3.0 версию, а документация есть уже на 1.5.1. По этому я отправился на официальный гитхаб от Unity и без труда нашел там новую версию нужного мне исходника. И там я увидел это:

TO DO 2023

TO DO 2023

Разницы у файла из 2019 и файла 2023 версии 1.5.1 нет. За 3 года, все эти «TODO» так и не были реализованы (Добро пожаловать в Unity, но сам движок отличный).

TO DO 2019

TO DO 2019

Ситуация стала безнадежной, так как изначально я хотел использовать именно оригинальный «инпут систем», чтобы избежать потом каких либо проблем. Затем, я полез на ассетстор, и нашел там отличный ассет Rewired. Тут я понял, что скорее всего его, обычно все и используют, или подобный ему. По этой причине, информации о том как заставить работать родной VirtualMouse от Unity нет. Специально описал, способы поиска решения, так как это тоже опыт и он может пригодится в других задачах. Особенно когда люди впадают в ступор и обычная ссылка на гитхаб Unity, может спасти положение, так как многие даже не подозревают о его существовании. Движок постоянно дописывается и часто уже есть готовое и исправленное. А ещё мне данная ситуация показалась забавной, ведь это официальный пакет.

Я не горел желанием покупать дорогой ассет и жаба меня так задавила, что в итоге я решил залезть в исходник и доделать эти «TODO» сам. Так же влезть в код Unity, уже своеобразный челлендж. Итак приступим:

  1. Вырезаем весь класс из пакета и создаем новый, так же меняем имя на «VirtualMouseV». Это нужно, чтобы мы никак не изменяли оригинальный пакет и у нас не было потом проблем, например после его обновления.

public class VirtualMouseV : MonoBehaviour
  1. Тут убираем строчку «InputSystem.DisableDevice(m_SystemMouse);». Данная строчка, как раз и отключала мышку (Зачем?):

private void TryEnableHardwareCursor()         {             var devices = InputSystem.devices;             for (var i = 0; i < devices.Count; ++i)             {                 var device = devices[i];                 if (device.native && device is Mouse mouse)                 {                     m_SystemMouse = mouse;                     break;                 }             }              if (m_SystemMouse == null)             {                 if (m_CursorGraphic != null)                     m_CursorGraphic.enabled = true;                 return;             }              // убрал чтобы мышка продолжала работать             // InputSystem.DisableDevice(m_SystemMouse);              // Sync position.             if (m_VirtualMouse != null)                 m_SystemMouse.WarpCursorPosition(m_VirtualMouse.position.ReadValue());              // Turn off mouse cursor image.             if (m_CursorGraphic != null)                 m_CursorGraphic.enabled = false;         }
  1. Убираем «TryFindCanvas()». Будем выставлять канвас вручную:

// поиск канваса скрыл         //private void TryFindCanvas()         //{         //    m_Canvas = m_CursorGraphic?.GetComponentInParent<Canvas>();         //}
  1. Делаем канвас публичным, чтобы выставить его в инспекторе (не забудьте потом это сделать). А так же добавляем переменную «isUseGamePad», она нам понадобится для синхронизации мышки и геймпада.

        public Canvas m_Canvas; // Canvas that gives the motion range for the software cursor.                  /// <summary>         /// Флаг использовался ли гейпад         /// </summary>         private bool isUseGamePad = false;
  1. Приводим «UpdateMotion()», вот в такой вид:

 private void UpdateMotion()         {             // включаем флаг что геймпад используется              isUseGamePad = true;              if (m_VirtualMouse == null)             {                 // флаг что геймпад не испольуется                  isUseGamePad = false;                 return;             }              // Read current stick value.             var stickAction = m_StickAction.action;             if (stickAction == null)             {                 // флаг что геймпад не используется                  isUseGamePad = false;                 return;             }             var stickValue = stickAction.ReadValue<Vector2>();             if (Mathf.Approximately(0, stickValue.x) && Mathf.Approximately(0, stickValue.y))             {                 // Motion has stopped.                 m_LastTime = default;                 m_LastStickValue = default;                  // флаг что геймпад не используется                  isUseGamePad = false;              }             else             {                 var currentTime = InputState.currentTime;                 if (Mathf.Approximately(0, m_LastStickValue.x) && Mathf.Approximately(0, m_LastStickValue.y))                 {                     // Motion has started.                     m_LastTime = currentTime;                 }                  // Compute delta.                 var deltaTime = (float)(currentTime - m_LastTime);                 var delta = new Vector2(m_CursorSpeed * stickValue.x * deltaTime, m_CursorSpeed * stickValue.y * deltaTime);                  // Update position.                 var currentPosition = m_VirtualMouse.position.ReadValue();                 var newPosition = currentPosition + delta;                   ////REVIEW: for the hardware cursor, clamp to something else?                 // Clamp to canvas.                 //if (m_Canvas != null)                 //{                     // Clamp to canvas.                     var pixelRect = m_Canvas.pixelRect;                     newPosition.x = Mathf.Clamp(newPosition.x, pixelRect.xMin, pixelRect.xMax);                     newPosition.y = Mathf.Clamp(newPosition.y, pixelRect.yMin, pixelRect.yMax);                 //}                  ////REVIEW: the fact we have no events on these means that actions won't have an event ID to go by; problem?                 InputState.Change(m_VirtualMouse.position, newPosition);                 InputState.Change(m_VirtualMouse.delta, delta);                  // обычная мышка                 InputState.Change(virtualMouse.position, newPosition);                 InputState.Change(virtualMouse.delta, delta);                  // Update software cursor transform, if any.                 if (m_CursorTransform != null &&                     (m_CursorMode == CursorMode.SoftwareCursor ||                      (m_CursorMode == CursorMode.HardwareCursorIfAvailable && m_SystemMouse == null)))                     m_CursorTransform.anchoredPosition = newPosition;                  m_LastStickValue = stickValue;                 m_LastTime = currentTime;                  // Update hardware cursor.                 m_SystemMouse?.WarpCursorPosition(newPosition);             }              // Update scroll wheel.             var scrollAction = m_ScrollWheelAction.action;             if (scrollAction != null)             {                                   var scrollValue = scrollAction.ReadValue<Vector2>();                 //Debug.Log(scrollValue.x + "   " + scrollValue.y);                 scrollValue.x *= m_ScrollSpeed;                 scrollValue.y *= m_ScrollSpeed;                   InputState.Change(m_VirtualMouse.scroll, scrollValue);                  // синхронизирум мышку с текущим зумом, если есть нажатия                 if (scrollValue.y != 0)                 {                     // обновляем скролл у мышки                      InputState.Change(Mouse.current.scroll, scrollValue);                 }             }                       }
  1. Дописываем «OnAfterInputUpdate()»:

        private void OnAfterInputUpdate()         {             UpdateMotion();                          // обновляем позицию курсора геймпада из позиции мышки, когда геймпад не зайдействован             if (isUseGamePad == false)             {                 InputState.Change(m_VirtualMouse.position, Mouse.current.position.ReadValue());             }         }

Всё, теперь у нас есть полностью рабочий VirtualMouse, в режиме hardware. Теперь используется один курсор и на мышку и на геймпад, и он не выходит за границу экрана. Так же отслеживается состояние колесика и синхронизируется с геймпадом, по этому Mouse.current.scroll.ReadValue().y будет работать и там и там одинаково. Теперь Unity воспринимает геймпад как полноценную мышь.

Так же не забудьте добавить девайсы в настройке пакета:

Настройки Input System Package

Настройки Input System Package

Пример, как нужно выставлять управление у геймпада для колесика. Вещь неочевидная и на это тоже потратил время:

VirtualMouseV

VirtualMouseV
VirtualMouseV

VirtualMouseV
VirtualMouseV

VirtualMouseV

Демонстрация работы допиленного компонента. Курсор в ролике двигает мышка и геймпад поочередно. При этом они работают одновременно.

Пользуясь случаем, даю ссылку на свою будущую игру VICCP 2 Core, которую я делаю в одиночку.

Надеюсь, данная статья поможет тем, кто столкнулся с этой проблемой.


ссылка на оригинал статьи https://habr.com/ru/articles/733634/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *