Чи є кращий спосіб налаштувати систему подій?


9

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

В даний час у мене є два методи:

  1. Найпростіше: всі об’єкти додаються у вектор, коли подія надсилається, всі об’єкти надсилаються події за допомогою методу handle_event ()

  2. Більш складний: у мене є карта з рядком, оскільки він є ключовим і int як його значення. Коли тип події додано, він додається до цієї карти, при цьому інт просто збільшується (повинен бути кращий спосіб),
    вектор векторів об'єктів потім відштовхує новий вектор для обробки такого типу події.
    Коли подія називається, вона просто викликає відповідний int у карті eventTypes до типу всередині векторів об'єктів і надсилає цю подію кожному об'єкту, що обробляє цей тип події.

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

Чи існує швидший (розумний час) шлях? Чи є більш швидкий спосіб шукати int з типу рядка? (Спочатку у мене був перелік, але він не дозволяв користувацьким типам, які необхідні через бажаний рівень динамізму.)


1
Це своєрідне те, для чого використовуються Hash Maps (або Hash Table), рядок обчислюється до хеш-числа, яке потім використовується для пошуку безпосередньо в масиві. en.wikipedia.org/wiki/Hash_table
Патрік Х'юз

Хороше запитання: чи це насправді вузьке місце продуктивності, чи ви просто переживаєте передчасно?
Jari Komppa

Це вже реалізовано, і існує вузьке місце, коли використовується багато об’єктів. Мій попередній коментар про відсутність вузького місця був не в самій програмі, а насправді різниця в швидкості між двома реалізаціями вище, де фактично оброблялася однакова кількість об'єктів. Я сподівався на інші методи створення подійних систем ... Однак деякі ідеї в цій темі збільшать швидкість, особливо при завантаженні системи подій (11-25 повних секунд часу завантаження 100000 об'єктами)
ultifinitus

100K об'єктів звучить жахливо високо для просто гри. Це сервер чи програма для кінцевих клієнтів?
Патрік Х'юз

Це мій двигун, тому я дійсно іду на гнучкість. Він буде використовуватися в серверних додатках та додатках для кінцевих користувачів (рідше перший, оптимізація)
ultifinitus

Відповіді:


5

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

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


Вузьке місце не велике (для 100 000 об'єктів він втрачає .0000076 мс / об’єкт), але я думаю, що ваша ідея - чудова ідея! Я думаю, що я дійсно буду одноразово шукати ідентифікатор і матиму eventID, що зберігається як int, а не вихідні рядкові дані. І я насправді не думав про пов'язані списки, гарна ідея.
ultifinitus

1
+1 Для попередньої обробки ідентифікаторів. Ви також можете це зробити ліниво, маючи тип EventType, який кожен модуль міг отримати через щось подібне EventType takeDamageEvent = EventSystem::CacheEventType("takeDamageEvent");. Зробіть це статичним членом класів, і у вас буде лише одна копія, що плаває навколо у кожному класі, який потребує цього.
michael.bartnett

2
Зауважте, що зберігання ідентифікаторів замість рядків зробить налагодження дещо складним. Завжди корисно мати можливість бачити текст, який визначає, звідки походить об’єкт. Ви можете піти на півдорозі, зберігаючи ідентифікатор, і рядок, які ви тримаєте навколо для налагодження (можливо, навіть видаляється у версії версій).
Нікол Болас

2

Що ж, давайте спочатку вийдемо з простих речей. Ви маєте це mapміж рядками (назва події, імовірно) та цілими числами (індекс зареєстрованих слухачів події).

Час пошуку в a mapґрунтується на двох речах: кількості елементів на карті та часу, необхідному для порівняння двох клавіш (ігнорування проблем із кешем). Якщо час пошуку - це проблема, один із способів вирішити це - змінити функцію порівняння, змінивши тип рядка.

Припустимо, ви використовуєте std::stringта operator<для порівняння. Це вкрай неефективно; це байтове порівняння. Вас не хвилює справжня струна менше порівняно; вам просто потрібне якесь порівняння, яке дає чітке слабке впорядкування (бо mapне працює інакше).

Тому вам слід використовувати 32-байтовий рядок фіксованої довжини замість std::string. Я використовую їх для ідентифікаторів. Порівняльні тести для цих фіксованих рядків не виконують байтових порівнянь; вони роблять 32-бітні (або 64-бітні) порівняння. Він приймає кожні 4 байти як непідписане ціле число і порівнює його з відповідними 4 байтами іншого рядка. Таким чином, порівняння бере лише максимум 8 порівнянь. Це забезпечує строго-слабке впорядкування, хоча впорядкування не має нічого спільного з даними як символами.

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

Тепер ви можете mapповністю вирватися та використовувати хеш-таблицю. Якщо у вас дійсно більше 100 000 різних типів подій, це може бути хорошою ідеєю. Але я не знаю гри, де це було б віддаленою справою.


Отже, слід використовувати 32-байтовий рядок фіксованої довжини замість std :: string. Фантастичний! Я не думав змінювати тип рядка.
ultifinitus

0

Щоб відповісти на загальне запитання:

Кращий спосіб налаштування системи подій

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

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

Найкращий спосіб - це вивчити різні види систем подій, і тоді у вас з’являться підказки, яку саме використовувати в тому випадку.

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

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