Создание движка Zavod3D
GameDev.ru / Страницы / Zavod3D engine / Статьи / Библиотека Gainput

Библиотека Gainput

Автор:


Заметки по использованию библиотеки gainput

Как-то разбирался с библиотекой обработки ввода Gainput  и делал записи. Не скажу, что разобрался досконально во всех деталях, но основные моменты понял. Решил выложить - может кому пригодится. Это не отменяет чтение официального мануала и некоторого копания в исходниках. Библиотека gainput служит для обработки ввода от клавиатуры, мыши, геймпада и других устройств.

Ссылка на библиотеку

Заметки по использованию библиотеки gainput

1. Особенности реализации классов и функций

Раздел 1 можно почитать, если есть желание изучить исходный код библиотеки и для общего ознакомления.

Идентификаторы кнопок

Идентификаторы кнопок описываются целыми числами. В качестве значений используются члены перечислимого типа Key и MouseButton.

InputState

Класс InputState содержит массив структур, где каждый элемент массива хранит состояние одной кнопки. Состояние может быть выражено булевым значением или числом с плавающей точкой. Этот внутренний массив создается конструктором и уничтожается деструктором класса. В связи с этим в конструктор класса должна быть передана ссылка на  аллокатор и число кнопок. Для получения состояний кнопок выделены методы GetBool, GetFloat класса. Для их использования нужно передать идентификатор кнопки в параметре. Метод Set кроме идентификатора кнопки требует задания булева значения или числа float во втором параметре. Идентификатор кнопки играет роль индекса во внутреннем массиве. Метод GetButtonCount() позволяет получить количество кнопок, состояния которых хранятся в объекте класса InputState. Класс InputState поддерживает операцию присваивания.

Перечислимый тип ButtonType содержит возможные типы кнопок: булево значение и число float.

InputDevice

Класс InputDevice служит базовым классом для классов всех устройств ввода. Это абстрактный класс.
Внутри класс содержит перечислимые типы  DeviceType, DeviceVariant и DeviceState. Тип DeviceType описывает возможные типы устройств ввода (клавиатура, мышь, геймпад и пр.). Назначение типа DeviceVariant мне пока не совсем ясно. Тип DeviceState отражает возможные состояния устройств ввода (нормальное, недоступное и низкий заряд источника питания).

Среди членов класса имеются пара указателей (state_ и previousState_)  типа InputState*  на текущее и предыдущее состояния кнопок этого устройства. Методы GetBool, GetBoolPrevious, GetFloat, GetFloatPrevious позволяют получить состояния кнопок по этим указателям, в сущности являясь простыми обертками над методами класса InputState. В качестве параметра в эти методы нужно передать идентификатор кнопки.
Также среди членов класса есть ссылка на менеджер ввода, идентификатор устройства и его индекс.

InputDeviceKeyboardImplWin

Класс InputDeviceKeyboardImplWin содержит хэш-словарь dialect_, который отображает коды виртуальных клавиш windows в идентификаторы кнопок.  Член nextState_ описывает состояния кнопок, которые были получены после обработки сообщений ввода WinAPI (WM_KEYDOW, WM_KEYUP и пр.).

InputDeviceKeyboard

Класс InputDeviceKeyboard является производным от класса InputDevice и описывает такое устройство ввода как клавиатура. Имеет в своем составе указатель impl_ на класс InputDeviceKeyboardImpl (класс InputDeviceKeyboardImplWin - производный от него). В конструкторе класса создаются объекты состояний, на которые указывают члены state_ и previousState_ базового класса. Объект класса InputDeviceKeyboardImplWin, на который указывает указатель impl_, также создается внутри тела конструктора класса InputDeviceKeyboard, при этом в конструктор класса InputDeviceKeyboardImplWin передается ссылка на менеджер, ссылка на объект этого устройства и только что созданные объекты состояний.

InputManager

Класс InputManager управляет созданием объектов устройств, обработкой сообщений и обновлением состояний устройств.  Он содержит хэш-словарь, отображающий идентификаторы устройств в указатели объектов устройств.

2. Использование библиотеки

Перед использованием библиотеки gainput должно быть создано окно вашего приложения. Первый шаг использования библиотеки gainput состоит в создании объекта класса InputManager – менеджера ввода.  Например, можно просто определить глобальную переменную  этого типа:

gainput::InputManager manager;

Нужно установить значения размеров окна при помощи метода SetDisplaySize, эти размеры используются при обработке перемещения мыши:

manager.SetDisplaySize(windowWidth, windowHeight);

После этого вы можете создавать объекты устройств, таких как клавиатура или мышь. Чтобы создать объект устройства, необходимо вызвать шаблонный метод CreateDevice, в качестве параметра шаблона которого нужно передать название класса устройства, производного от класса InputDevice. Метод CreateDevice создаст объект устройства, запишет его во внутренний хэш-словарь и вернет идентификатор созданного объекта устройства. Например:

// создание объекта мыши
gainput::DeviceId mouseId = manager.CreateDevice<gainput::InputDeviceMouse>();
// создание объекта клавиатуры
gainput::DeviceId keyboardId = manager.CreateDevice<gainput::InputDeviceKeyboard>();

Теперь рассмотрим работу методов HandleMessage и Update менеджера ввода. В методе HandleMessage происходит обработка сообщений Windows (структура MSG, переданная в параметре, описывает сообщение) и устанавливается состояние соответствующей кнопки. Все новые состояния кнопок сохраняются временно в объекте, описывающем новое состояние. В методе Update в самом простом случае идет перебор созданных устройств, текущее состояние их кнопок становится предыдущим, а новое – текущим.

Методы HandleMessage и Update менеджера ввода нужно вызывать в главном цикле приложения. Пример:

// Update Gainput
manager.Update();
MSG msg;
while (PeekMessage(&msg, hWnd,  0, 0, PM_REMOVE)) 
{
TranslateMessage(&msg);
DispatchMessage(&msg);
manager.HandleMessage(msg);
}

Теперь собственно о том, как можно проверять  состояния игровых кнопок. После создания (или определения) объекта менеджера ввода необходимо создать или определить объект карты типа InputMap, который отображает типы игровых кнопок в кнопки физического устройства ввода. Теперь вы можете определить игровые кнопки в виде перечислимого типа и вызвать методы MapBool, MapFloat, Unmap класса InputMap, чтобы задать или снять отображение игровой кнопки в одну или несколько кнопок устройства. Нужно отметить, что кнопками также считаются движения мыши – в этом случае это кнопки типа float. Пример:

map.MapFloat(MouseX, mouseId, gainput::MouseAxisX);
map.MapFloat(MouseY, mouseId, gainput::MouseAxisY);
map.MapBool(ButtonMoveForward, keyboardId, gainput::KeyW);

Для проверки состояния кнопки необходимо после обработки сообщений окна менеджером ввода вызвать методы GetBool, GetWasDown, GetBoolIsNew, GetBoolPrevious и соответствующие методы для float-кнопок класса карты отображения InputMap. Пример:

if (map.GetBoolIsNew(ButtonMoveForward))
{
  // move player character forward
}

Для кнопок-осей мыши метод GetFloat возвращает позицию курсора относительно левой верхней точки в долях от размеров окна. Чтобы получить смещение курсора от его положения на предыдущем кадре используйте метод GetFloatDelta карты.

Я не рассматривал здесь листенеры и модификаторы – мне пока хватает рассмотренного функционала.
Кратко резюмируя, самый простой способ использования библиотеки состоит в следующем:


1.  Создать менеджер ввода.
2.  Задать размеры окна в менеджере ввода.
3.  Создать объекты устройств ввода.
4.  Создать карту отображений игровых кнопок в кнопки устройств.
5.  Заполнить карту отображениями игровых кнопок в кнопки устройства.
6.  В главном цикле обновлять состояния кнопок, обрабатывать сообщения окна и проверять состояния игровых кнопок.

Пример:

// Задаем свои игровые кнопки 
enum Button
{
    MouseX,
    MouseY,
  ButtonMoveForward
};
// создаем окно размеров width, height
gainput::InputManager manager;
manager.SetDisplaySize(width, height);
gainput::DeviceId mouseId = manager.CreateDevice<gainput::InputDeviceMouse>();
gainput::DeviceId keyboardId = manager.CreateDevice<gainput::InputDeviceKeyboard>();
gainput::InputMap map(manager);
map.MapFloat(MouseX, mouseId, gainput::MouseAxisX);
map.MapFloat(MouseY, mouseId, gainput::MouseAxisY);
map.MapBool(ButtonMoveForward, keyboardId, gainput::KeyW);
while (!doExit)
{
manager.Update();
MSG msg;
while (PeekMessage(&msg, hWnd,  0, 0, PM_REMOVE)) 
{
TranslateMessage(&msg);
DispatchMessage(&msg);
manager.HandleMessage(msg);
}
        // Check button states
        
if (map.GetBoolIsNew(ButtonMoveForward))
{
    // move player character forward
}
        
   if (map.GetFloatDelta(MouseX) != 0.0f 
|| map.GetFloatDelta(MouseY) != 0.0f)
{
         // rotate camera   
}
}

Все перечисленные шаги можно посмотреть в примере basicsample. Смотрите пример basicsample_win.cpp во вкладке examples в документации на github библиотеки gainput.

18 июля 2016

#ввод, #движок, #клавиатура, #мышь

2001—2018 © GameDev.ru — Разработка игр