Керування системою введення з клавіатури


13

Примітка. Мені доводиться опитувати, а не робити зворотні дзвінки через обмеження API (SFML). Я також вибачаюся за відсутність "гідного" звання.

Я думаю, що у мене тут два питання; як зареєструвати вхід, який я отримую, і що з ним робити.

Обробка вводу

Я говорю про те, як ви зареєстрували, наприклад, що була натиснута клавіша "A", і як це зробити звідти.

Я бачив масив всієї клавіатури, приблизно:

bool keyboard[256]; //And each input loop check the state of every key on the keyboard

Але це здається неефективним. Ви не тільки зв'язуєте клавішу "А", наприклад, "гравець, що рухається ліворуч", але він перевіряє кожну клавішу, 30-60 разів на секунду.

Потім я спробував іншу систему, яка просто шукала ключі, які вона хотіла.

std::map< unsigned char, Key> keyMap; //Key stores the keycode, and whether it's been pressed. Then, I declare a load of const unsigned char called 'Quit' or 'PlayerLeft'.
input->BindKey(Keys::PlayerLeft, KeyCode::A); //so now you can check if PlayerLeft, rather than if A.

Однак проблема в тому, що зараз я не можу набрати ім'я, не маючи прив'язувати кожну клавішу.

Потім у мене є друга проблема, яку я не можу по-справжньому вважати хорошим рішенням:

Надсилання введення

Тепер я знаю, що була натиснута клавіша "A" або що "Гравець ліворуч" - це правда. Але як я можу поїхати звідси?

Я подумав про те, щоб просто перевірити, що if(input->IsKeyDown(Key::PlayerLeft) { player.MoveLeft(); }
це в значній мірі поєднує вклад в сутність, і я вважаю це досить безладним. Я вважаю за краще плеєр керувати власним рухом, коли він оновлюється. Я думав, якась система подій може працювати, але я не знаю, як з цим піти. (Я чув, що сигнали та прорізи були хорошими для такої роботи, але це, мабуть, дуже повільно, і я не можу побачити, як це підійде).

Спасибі.

Відповіді:


7

Що я б робив - це використовувати шаблон спостереження і мати клас введення, який підтримує список зворотних викликів або об'єктів обробки даних. Інші об'єкти можуть зареєструватися в системі введення, щоб отримувати сповіщення, коли відбуваються певні речі. Ви можете зареєструвати різні типи зворотних дзвінків, виходячи з типу вхідних подій, про які хотіли б повідомити спостерігачі. Це може бути настільки ж низький рівень, як "клавіша x вниз / вгору" або більш специфічна для гри, наприклад "трапилася подія стрибка / стрільби / руху".

Як правило, в ігрових об'єктах є компонент обробки вхідних даних, який відповідає за реєстрацію себе в класі введення та надання методів для обробки подій, які його цікавлять. Для руху у мене є компонент перемикача входу, який має метод переміщення (x, y). Він реєструється в системі введення та отримує сповіщення про події руху (де x і y буде -1 та 0, щоб означати переміщення ліворуч), компонент, що рухається, потім змінює свої координатні об'єкти батьківської гри на основі напрямку руху та швидкості об’єкта.

Я не знаю, чи це хороше рішення, але це працює для мене поки що. Зокрема, це дозволяє мені надати різні види системи введення, які відображають однакові логічні ігрові події, щоб кнопка геймпада x та клавіатурний простір генерували, наприклад, подію стрибка (це трохи складніше, ніж це, що дозволяє користувачеві перепризначити ключ відображення).


Це, безумовно, мене цікавить; Чи буде вхідний компонент реєструвати себе для певних подій (щось на зразок playerInput реєструє "ліворуч", "праворуч" тощо) чи кожен вхідний компонент, який зареєстрований, отримає всі повідомлення?
Качка комуніста

Це дійсно залежить від вашої вимоги та того, як ви хочете її виконати. У моєму випадку слухачі реєструються для конкретних подій та реалізують відповідний інтерфейс обробника вводу. Якщо кожен вхідний компонент отримує всі повідомлення, він повинен працювати, але формат повідомлення повинен бути більш загальним, ніж у мене.
Фірас Ассаад

6

Я думаю, що обговорення ОП збирає купу речей разом, і що проблему можна істотно спростити, трохи розірвавши її.

Моя пропозиція:

Зберігайте свій масив станів ключів. Чи немає дзвінка API, щоб одразу отримати весь стан клавіатури? (Більшість моїх робіт є на консолях, і навіть у Windows для підключеного контролера ви отримуєте одразу весь стан контролера.) Ваші ключові стани - це "жорстка" карта на клавішах клавіатури. Неперекладений найкраще, але однак це ви найпростіше отримати з API.

Потім збережіть кілька паралельних масивів, які вказують, чи піднявся ключ у цьому кадрі, інший вказує на те, що він знизився, а третій - просто вказує, що ключ "вниз". Можливо, киньте таймер, щоб ви могли відслідковувати, як довго ключ був у його поточному стані.

Далі створіть метод створення відображення ключів до дій. Вам захочеться зробити це кілька разів. Один раз для інтерфейсу користувача (і подбайте про те, щоб запитувати відображення Windows, оскільки ви не можете припустити код сканування, коли натискаєте "A", на комп'ютері користувача буде дано "A"). Ще для кожного ігрового «режиму». Це відображення ключових кодів дій. Це можна зробити двома способами, один - зберегти перерахунок, який використовується приймаючою системою, інший - покажчик функції, що вказує на функцію, яку потрібно викликати при зміні стану. Можливо, навіть гібрид із двох, залежно від ваших цілей та потреб. За допомогою цих "режимів" ви можете натиснути і перенести їх на стек режиму контролера, з прапорами, які дозволяють ігнорованому вводу продовжувати йти вниз по стеку або будь-якому іншому.

Нарешті, якось обробляйте ці ключові дії. Для руху, можливо, ви хочете зробити щось складне, перекладіть "W" вниз, щоб означати "рухатися вперед", але це не повинно бути бінарним рішенням; ви можете мати "W вниз" означає "збільшувати швидкість на X до максимуму Y", а "W - вгору", щоб "зменшити швидкість на Z, поки вона не досягне нуля". Взагалі кажучи - ви хочете, щоб ваш "інтерфейс управління контролером в ігрових системах" був досить вузьким; зробіть увесь переклад ключових слів в одному місці, а потім використовуйте результати цього в будь-якому іншому місці. Це на відміну від прямої перевірки, чи не натискається пробіл куди-небудь випадковим чином у коді, тому що якщо він знаходиться в якомусь випадковому місці, він, ймовірно, потрапить у якийсь випадковий час, коли ви цього не хочете, і ви просто не робите ' я не хочу з цим боротися ...

Мені дуже подобається розробляти шаблони, і я думаю, що компоненти приносять більше витрат на розробку, ніж користі, тому я не згадав жодного. Візерунки з’являться, якщо їм призначено, як і компоненти, але налаштування робити це з самого початку лише ускладнить ваше життя.


Ви не вважаєте, що брудно пов’язувати події з графічними кадрами? Я думаю, що це слід розділити.
Jo So

Я маю на увазі, я розумію, що майже у всіх випадках програвач буде повільніше вводити кнопки введення, ніж відеокарта випромінює кадри, але насправді вони повинні бути незалежними, а насправді вони стосуються інших типів подій, як зібраних, взятих з мережі .
Jo So

Дійсно; немає жодної причини, чому опитування клавіатури (або іншого пристрою введення) не може бути запущено зі швидкістю, відмінною від дисплея. Дійсно, якщо ви опитуєте входи на 100 ГГц, то ви можете забезпечити дійсно стійкий досвід управління користувачем незалежно від частоти оновлення відео апаратного забезпечення. Вам доведеться бути трохи більш розумним щодо того, як ви обробляєте свої дані (щодо фіксації тощо), але це полегшить послідовність таких способів, як жести.
dash-tom-bang

3

У SFML у вас є клавіші в тому порядку, в якому вони були натиснуті з типом події KeyPress. Ви обробляєте кожний ключ через деякий час (getNextEvent ()).

Отже, якщо натиснута клавіша знаходиться у вашій кнопці Key-> Action, виконайте відповідну дію, а якщо ні, перешліть її на будь-який віджет / речі, які можуть знадобитися.

Що стосується вашого другого питання, я рекомендую вам тримати його таким, оскільки це полегшує налаштування вашого геймплея. Якщо ви використовуєте сигнали чи подібні, вам доведеться зробити слот для "RunKeyDown" та ще один для "JumpKeySlot". Але що станеться, якщо у вашій грі виконується спеціальна дія, коли обидва натискаються?

Якщо ви хочете декоррегулювати вхідні дані та об'єкти, ви можете зробити свій вхід станом (RunKey = true, FireKey = false, ...) і надіслати його гравцеві, як ви надсилаєте будь-яку іншу подію до своїх AI.


Я не обробляю події клавіатури за допомогою sf :: Event, скоріше sf :: Input, оскільки це IIRC виявлення в реальному часі. Я намагався підтримувати це якомога більше API-агностику. : P (Питання, тобто)
Качка комуніста

1
Але я думаю, що справа в Calvin1602 полягає в тому, що ваше первісне твердження в питанні "Я повинен опитувати, а не робити зворотні виклики через обмеження API (SFML)" не відповідає дійсності; у вас є події, тому ви можете надіслати зворотній дзвінок під час обробки події.
Килотан

3

Правильне рішення часто є комбінацією двох методів, які ви обговорюєте:

Для функцій геймплея із заздалегідь заданим набором клавіш, опитування кожного кадру є цілком підходящим, і вам слід опитуватись лише для клавіш, які насправді пов'язані з чимось. Це насправді аналогічно тому, як ви б запитували введення контролера в консольній грі, це буде повністю опитування, особливо якщо мова йде про аналогові пристрої введення. Під час загального геймплею ви, мабуть, хочете ігнорувати події натискання клавіш і просто використовувати опитування.

Якщо мова йде про введення даних для таких речей, як імена, вам слід переключити гру в інший режим обробки даних. Наприклад, щойно з'являється запит "введіть своє ім'я", ви можете змінити те, що робить код введення. Він може або слухати ключові події натискання через якийсь інтерфейс зворотного дзвінка, або ви можете почати опитування кожної клавіші, якщо потрібно. Виявляється, зазвичай під час введення подій ви все одно не так сильно дбаєте про ефективність, тому опитування не буде таким поганим.

Отже, ви хочете використовувати селективне опитування для введення ігор та обробку подій для введення імен (або все опитування на клавіатурі, якщо обробка подій недоступна).


1

Мені дуже подобається відповідь dash-tom-bang, вона дійсно висвітлює деякі аспекти, про які слід пам’ятати, розробляючи систему введення.

Я хотів би додати невеликий підручник, на який я натрапив, і йде в тому ж напрямку (включаючи вхідні контексти, 3 шари, ...):

http://www.gamedev.net/blog/355/entry-2250186-designing-a-robust-input-handling-system-for-games/

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.