Pull to refresh

Работа с игровыми контроллерами

.NET

Приветствую, дорогие читатели!

В одном из проектов мне понадобилось работать с игровыми контроллерами, в частности с игровым рулем. Было необходимо получить состояние руля – угол поворота, нажатые кнопки. Создавалась не игра, это было обычное .net-приложение, не буду вдаваться в подробности проекта. Речь пойдет о том, как получить информацию о состоянии игровых контроллеров в .net.

Предметная область


Задача – получить данные от игрового руля. В первую очередь необходимо изучить предметную область. Где используются игровые рули? Очевидно, в играх. Множество игр разрабатывается с помощью технологии DirectX. Почитав википедию, можно узнать, что DirectX подразделяется на множество интерфейсов. Интерес для нас представляет интерфейс DirectInput.

DirectInput — интерфейс, используемый для обработки данных, поступающих с клавиатуры, мыши, джойстика и пр. игровых контроллеров. (с) Wikipedia.org

Используемые игровые контроллеры


Для реализации проекта в мое распоряжение был предоставлен игровой руль Defender Forsage GTR.
Также я не упустил возможности поэкспериментировать со своим игровым джойстиком Logitech Rumblepad 2.

Managed DirectX


Как Вы, наверное, догадались Managed DirectX — это поддержка DirectX из управляемого кода, т.е. из программ, написанных с использованием .net. MDX включен в состав DirectX SDK, начиная с девятой версии.
Если Вы заинтересовались MDX, то можете почитать книгу Тома Миллера «DirectX 9 с управляемым кодом. Программирование игр и графика». В сети есть масса информации по теме.

Необходимые инструменты


Логично, что в первую очередь необходимо инсталлировать драйвер производителя игрового контроллера, хотя, как выяснилось, это не является обязательным пунктом, т.к. в ходе моих экспериментов с джойстиком Logitech, никаких драйверов для него я не инсталлировал, и он стабильно отвечал на мои запросы (под управлением ОС Windows 7).
Мы используем DirectX, поэтому нам понадобится DirectX SDK, скачать его можно здесь. Все необходимое для работы с .net там уже есть. В качестве IDE я использовал Visual Studio 2010.

Начало работы


Итак, DirectX SDK установлен, запустим Visual Studio, создадим новый проект и подключим к нему Managed DirectX. Для этого идем в References -> Add Reference, идем во вкладку Browse, идем в папку \Windows\Microsoft.NET\DirectX for Managed Code\1.0.2902.0 и подключаем к проекту Microsoft.DirectX.dll и Microsoft.DirectX.DirectInput.dll, соответственно не забываем про:

using Microsoft.DirectX;
using Microsoft.DirectX.DirectInput;

Конечно, не обошлось без подводных камней. В своих проектах в основном я использую .net framework 4.0, а у MDX проблемы с этой версией фреймворка, и на этапе сборки проекта Visual Studio 2010 просто зависнет. Поэтому у нас есть два пути решения проблемы:

1) использовать более раннюю версию .net framework.
2) немного подправить конфиги проекта, что мы и сделаем.

Добавим к проекту новый файл app.config со следующим содержимым:

<?xml version="1.0"?>
<configuration>
  <startup useLegacyV2RuntimeActivationPolicy="true">
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0,Profile=Client"/>
  </startup>
</configuration>

Теперь все готово, можно начинать работать с игровыми контроллерами.

Получение состояния игрового руля


Очевидно, что первым делом необходимо узнать обо всех подключенных игровых контроллерах:

foreach (DeviceInstance instance in Manager.GetDevices(DeviceClass.GameControl, EnumDevicesFlags.AttachedOnly))
{
     // На этом этапе можно узнать информацию об игровом контроллере, например, название:
     instance.ProductName
}

Далее необходимо инициализировать игровое устройство. Для наглядности подразумеваю, что оно у меня одно:

Device device;

foreach (DeviceInstance instance in Manager.GetDevices(DeviceClass.GameControl, EnumDevicesFlags.AttachedOnly))
{
     device = new Device(instance.ProductGuid);
     // Background - флаг, говорит о том, что данные от руля будут поступать даже в неактивное окно
     // NonExclusive - говорит о том, что игровой контроллер могут использовать и другие приложения
     device.SetCooperativeLevel(null, CooperativeLevelFlags.Background | CooperativeLevelFlags.NonExclusive);

     // Зададим дополнительные параметры
     foreach (DeviceObjectInstance doi in device.Objects)
     {
          // Проверяем есть ли на устройстве что-нибудь поворачивающееся
          if ((doi.ObjectId & (int)DeviceObjectTypeFlags.Axis) != 0)
          {
               // Задаем минимальное и максимальное значение угла поворота
               device.Properties.SetRange(
                          ParameterHow.ById,
                          doi.ObjectId,
                          new InputRange(-90, 90));
           }
     }

     // Применяем настройки
     device.Acquire();
}

В характеристиках руля сказано, что угол поворота рулевого колеса составляет 180 градусов, поэтому в InputRange я указал значение угла отклонения влево и вправо в 90 градусов.

К сожалению, мы не сможем подписаться на какие-либо события от руля или джойстика вроде KeyDown\KeyUp, и состояние игрового контроллера придется опрашивать вручную:

// Создаем таймер
DispatcherTimer timer = new DispatcherTimer();

timer.Tick += new EventHandler(timer_Tick);
timer.Interval = new TimeSpan(0, 0, 0, 0, 10);
timer.Start();

private void  timer_Tick(object sender, EventArgs e)
{
     // Получим текущее состояние руля
     JoystickState j = device.CurrentJoystickState;

     string info = "";

     // Собираем информацию о кнопках
     byte[] buttons = j.GetButtons();
     for (int i = 0; i < buttons.Length; i++)
     {
          // Узнаем какие из кнопок нажаты на данный момент
          if (buttons[i] != 0)
          {
               info += "Button: " + i + " ";
          }
     }

     // j.X будет содержать информацию об угле поворота руля
     textBlock1.Text = j.ToString();
     textBlock2.Text = info;
}

Для наглядности можно вывести на экран структуру JoystickState и увидеть, какие поля меняются в зависимости от состояния игрового руля. Все это справедливо также и для джойстика.

Выводы


Оказывается, запрограммировать игровой контроллер под свои нужды не так уж и сложно, большинство всевозможных джойстиков\рулей и т.п. подчиняются интерфейсу DirectInput, теперь в свои проекты\игры вы с легкостью сможете добавить их поддержку. Что касается игр, то остается только реализовать функционал, дающий пользователю возможность самому «навешивать» на кнопки действия, предусмотренные логикой игры.

Ссылки


1. DirectX Software Development Kit June 2010 \ 572 Mb
2. Том Миллер — Managed DirectX 9 с управляемым кодом
3. Исходники демонстрационного проекта

Спасибо за внимание.
Tags:.netxnamanaged directxmdxdirectinputигровой рульsteering wheelgamepadджойстик
Hubs: .NET
Total votes 35: ↑29 and ↓6+23
Views19K

Popular right now