Опубликован: 15.05.2013 | Доступ: свободный | Студентов: 265 / 9 | Длительность: 24:25:00
Специальности: Системный архитектор
Лекция 10:

Устройства и печать

< Лекция 9 || Лекция 10: 123 || Лекция 11 >

API XInput и игровые контроллеры

API XInput API, часть DirectX, это API Win32, которое предназначено для работы с игровыми контроллероами и находится в списке API Win32/COM, доступ к которым можно получить из приложений для Магазина Windows. Видимо, наиболее часто используемая его функция, это XInputGetState, которая возвращает структуру XINPUT_STATE, которая описывает позицию джойстиков игрового манипулятора, силу нажатия на переключатели, состояния кнопок. Эти данные обычно считывают с каждым кадром анимации в чем-то вроде игрового приложения. API не вызывает события, когда меняется состояние игрового контроллера.

Пример "Рисование с использованием JavaScript и XInput" ( http://code.msdn.microsoft.com/windowsapps/XInput-and-JavaScript-c72fe535) в Windows SDK показывает именно это. Так как API XInput недоступно напрямую из JavaScript, необходимо создать для этих целей WinRT-компонент. Проще говоря, вы создаете компонент с общедоступным классом внутри пространства имен, которое совпадает с именем файла компонента и затем добавляете ссылку на этот компонент в проект JavaScript-приложения в VisualStudio. Это импортирует пространство имен и делает его доступным в JavaScript. Подробности об этом будут в Главе 5, но обычный код C++-компонента выглядит так, как показано ниже – сначала – в заголовочном (Controller.h) файле в проекте GameController:

     
namespace GameController
{
public value struct State
{
// [Опусщено – содержит те же значения, что и структура Win32 XINPUT_STATE
};
public ref class Controller sealed
{
~Controller();
uint32 m_index;
bool   m_isControllerConnected; // Подключен ли контроллер?
XINPUT_CAPABILITIES m_xinputCaps;     // Возможности контроллера
XINPUT_STATE  m_xinputState;     // Текущее состояние контроллера
uint64 m_lastEnumTime;    // Время, когда в последний раз было проверено
// подключение контроллера

public:
Controller(uint32 index);

void SetState(uint16 leftSpeed, uint16 rightSpeed);
State GetState();
};
}

Реализация GetState в Controller.cpp затем просто вызывает XInputGetState и 
копирует его свойства в экземпляр общедоступной структуры State:
State Controller::GetState()
{
// по умолчанию возвращает controllerState который показывает, что контроллер не подключен
State controllerState;
controllerState.connected = false;
// Приложению следует избегать вызова функции XInput в каждом кадре, если нет
// подключенных устройств, так как первичное перечисление устройств может ухудшить
// производительность приложения.
uint64 currentTime = ::GetTickCount64();
if (!m_isControllerConnected pgpg currentTime - m_lastEnumTime<EnumerateTimeout)
{
return controllerState;
}

m_lastEnumTime = currentTime;
auto stateResult = XInputGetState(m_index, pgm_xinputState);

if (stateResult == ERROR_SUCCESS)
{
m_isControllerConnected = true; controllerState.connected = true; controllerState.controllerId = m_index; 
controllerState.packetNumber = m_xinputState.dwPacketNumber;
controllerState.LeftTrigger = m_xinputState.Gamepad.bLeftTrigger;
controllerState.RightTrigger = m_xinputState.Gamepad.bRightTrigger;

// И так далее [копирование других свойств опущено.]
}
else
{
m_isControllerConnected = false;
}

return controllerState;
}
Конструктор для объекта Controller так же весьма прост
Controller::Controller(uint32 index)
{
m_index = index;
m_lastEnumTime = ::GetTickCount64() - EnumerateTimeout;
}

В приложении JavaScript, когда добавлена ссылка на компонент – пространство имен GameController будет содержать общедоступное API компонента и мы можем использовать его так же, как если бы оно было встроено в Windows. В примере, сначала создаётся экземпляр объекта Controller (с нулевым индексом) и затем начинают выводиться кадры анимации: (program.js):

  app.onactivated = function (eventObj) {
  if (eventObj.detail.kind ===
  Windows.ApplicationModel.Activation.ActivationKind.launch) {
  // [Другие настройки опущены]

  // Создаёт экземпляр объекта Controller из компонента WinRT
  controller = new GameController.Controller(0);

  // Начало цикла рендеринга
  requestAnimationFrame(renderLoop);
  };
  };

Затем функция renderLoop просто вызывает метод компонента getState и выполняет рисование в элементе canvas перед повторением цикла (так же в program.js, хотя много кода опущено):

  function renderLoop() {
  var state = controller.getState();

  if (state.connected) {
  controllerPresent.style.visibility = "hidden";

  // Код, добавленный в пример для расширения его функциональности
  if (state.leftTrigger) {
  context.clearRect(0, 0, sketchSurface.width, sketchSurface.height);
  requestAnimationFrame(renderLoop);
  return;
  }

  if (state.a) {
  context.strokeStyle = "green";
  } else if (state.b) {
  context.strokeStyle = "red";
  } else if (state.x) {
  context.strokeStyle = "blue";
  } else if (state.y) {
  context.strokeStyle = "orange";
  }

  // Обработка состояния и рисование в элементе canvas [код опущен]
  };

  // Повторить для следующего кадра
  requestAnimationFrame(renderLoop);
  };

Вывод данных этим примером показан на рис. 10.2, что отражает добавленную мной возможность, показанную в вышеприведенном коде, которая делает программу интересней для моего сына: изменение цветов с помощью кнопок A/B/X/Y и очистка экрана с помощью левого переключателя. Как вы можете видеть, то, что я рисую в этой программе не слишком отличается от того, что рисует он.

В итоге, хотя WinRT не содержит средств для работы с API наподобие XInput, приложение может делать это самостоятельно, благодаря реализации простого компонента. Обратите внимание на то, что различные аспекты интерфейса компонента, наподобие особенностей написания имени, изменятся, когда он будет спроецирован в JavaScript. В лекциях 13-14 мы рассмотрим это подробнее. Сейчас же это показывает нам, что доступ к подобным специализированным устройство – это не такая уж и сложная задача.

Пример "Рисование с использованием JavaScript и XInput" с некоторыми изменениями, которые позволяют менять цвет. Изменение ширины линии регулируется позицией правого переключателя

Рис. 10.2. Пример "Рисование с использованием JavaScript и XInput" с некоторыми изменениями, которые позволяют менять цвет. Изменение ширины линии регулируется позицией правого переключателя
< Лекция 9 || Лекция 10: 123 || Лекция 11 >