Чи бувають випадки, коли глобуси / одинаки корисні при розробці ігор? [зачинено]


11

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

Так бувають випадки, коли глобальні змінні чи одинаки насправді корисні при розробці гри?

Відповіді:


30

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


Дуже близько до моєї мантри.
flafur Waage

15

Очевидно, що список не є вичерпним, але тут йдеться:

Мінуси

  • Довічне управління . Синглтони та глобали можуть хотіти запускатися до ініціалізації ключових систем (наприклад, купи), залежно від способу їх налаштування. Якщо ви коли-небудь хочете їх збити (корисно, наприклад, якщо ви займаєтесь відстеженням витоків), вам слід бути обережними щодо порядку замовлення та починати вступати в такі речі, як фенікс синглтон . (Див . Фіаско для замовлення статичної ініціалізації .)
  • Контроль доступу . Чи повинен мати візуалізація лише const доступ до ігрових даних, тоді як оновлення не має const? Це може бути важче застосувати з одиночними та глобальними.
  • Держава . Як зазначав Кей, важче функціонально розкласти і перетворити сингли, щоб вони взагалі працювали в архітектурі, що не має спільної пам'яті. Він також має потенційні наслідки для продуктивності інших типів систем NUMA (доступ до пам'яті, яка не є локальною). Однотонні зазвичай представляють централізований стан, і, таким чином, є антитезою перетворень, які полегшуються чистотою.

Або про, або проти

  • Паралельність . У одночасному середовищі одиночні кнопки можуть бути болем (ви повинні врахувати проблеми перегонів / перенастроювання даних) або благо (це легше централізувати та міркувати про блокування та управління ресурсами). Розумне використання таких речей, як локальне зберігання потоків, може дещо пом’якшити потенційні проблеми, але це, як правило, не проста проблема.
  • Кодеген (залежно від компілятора, архітектури тощо). Для наївного створення однотонних реалізацій, створених під час використання, ви можете оцінювати додаткову умовну гілку для кожного доступу. (Це може доповнити.) Кілька глобальних точок, які використовуються у функції, можуть роздути пул буквальних даних . Підхід "структура всіх глобалів" може заощадити простір у прямому пулі: лише один запис у базу структури, а потім зміщення, закодоване в інструкціях щодо завантаження. Нарешті, якщо ви уникаєте глобалів та синглів, будь-якою ціною, вам, як правило, потрібно використовувати хоча б трохи додаткової пам’яті (регістри, стеки чи купи) для передачі покажчиків, посилань чи навіть копій навколо.

Плюси

  • Простота . Якщо ви знаєте, що перелічені вище мінуси не впливають на вас так сильно (наприклад, ви працюєте в однопотоковому середовищі для однієї процесорної портативної платформи), ви уникаєте деякої архітектури (наприклад, вищезгаданого проходження аргументів). Однотонних та глобальних може бути легше зрозуміти для менш досвідчених кодерів (хоча може бути простіше використовувати їх неправильно).
  • Довічне управління (знову). Якщо ви використовуєте "структуру глобалів" чи якийсь механізм, відмінний від створення за першим запитом, ви можете мати легкий для читання та тонкий контроль над порядком ініціалізації та знищення. Ви певною мірою автоматизуєте це або керуєте ним вручну (необхідність керування ним може бути профі чи кон, залежно від кількості глобальних / синглтонних та їх взаємозалежностей).

Ми багато використовуємо "структуру глобальних синглтонів" у своїх ручних заголовках. Назви ПК та консолей, як правило, менше покладаються на них; ми перейдемо більше до архітектури, керованої подіями та повідомленнями. Зважаючи на це, заголовки ПК / консолей все ще часто використовують центральний TextureManager; оскільки зазвичай він містить один спільний ресурс (пам'ять текстури), це має для нас сенс.

Якщо ви зберігаєте API досить чистим, це може бути не надто важко для рефактора з (або в!) Однотонного шаблону, коли вам потрібно ...


Чудовий список. Особисто я знаходжу лише негативне значення в одиночних і глобальних з-за проблем, які виникають із спільного (ймовірно, змінного) стану. Я не вважаю, що проблема «кодегена» є проблемою; вам або потрібно пройти покажчики через регістри, або вам потрібно виконати певну послідовність операцій, щоб його отримати, я думаю, що це змінить код у порівнянні з розміром даних оглядно, але сума буде приблизно однаковою.
Даш-Том-Банг

Так, повторно кодеген, єдине, що ми насправді бачили, що суттєво змінилося, - це переходити від окремих глобальних до глобальних: це зменшило буквальний пул, а отже, і розмір розділу .text, на кілька відсотків. Що в маленьких системах дуже приємна річ. =) Переваги від продуктивності від того, щоб не так сильно вдаритись у дікаш, були просто приємною (хоча і крихітною у більшості випадків) побічною перевагою. Ще однією перевагою переходу до глобальної таблиці стала можливість по-справжньому легко перемістити її до розділу, який проживав у більш швидкій пам’яті ...
linder

4

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


2

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

Я часто використовую глобальні змінні для речей, до яких потрібен доступ через двигун. Мій інструмент продуктивності - це один хороший приклад, який я використовую у всіх двигунах для дзвінків. Дзвінки прості; ProbeRegister (), ProbeHit () та ProbeScoped (). Їх реальний доступ трохи складніше і використовує глобальні змінні для деяких своїх речей.


2

Основна проблема глобальних та погано реалізованих синглів - незрозумілі помилки в будівництві та деконструкції.

Тож якщо ви працюєте з примітивами, у яких цих проблем немає, або дуже добре в курсі проблеми з вказівником. Тоді їх можна безпечно використовувати.

Глобали мають своє місце, як готи, і їх не слід випускати з рук, а використовувати їх обережно.

У цьому посібнику зі стилів Google C ++ є гарне пояснення


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

@Joe ключове слово - "залежності". Функція, яка отримує доступ до глобальних точок (або одиночних або будь-яких інших спільних станів), має неявні залежності від усіх цих речей. Набагато простіше міркувати про трохи коду, якщо всі його залежності явні, це те, що ви отримуєте, коли повний перелік залежностей задокументований у списку аргументів.
Даш-Том-Банг

1

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

Однотонні корисні для заподіяння проблем собі та оточуючим. Чим більше глобального стану ви запровадите, тим більше проблем у вас буде з правильністю коду, технічним обслуговуванням, розширенням, одночасністю тощо. Просто не робіть цього.


1

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


Для тих із вас, хто не знає, DI - це "введення залежності", а IoC - "інверсія управління". Посилання: martinfowler.com/articles/injection.html (я раніше про це читав, але ніколи не бачив абревіатури, тому знадобилося мені трохи пошуку.) +1 для згадки про цю чудову трансформацію.
лизинг

0

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

http://en.wikipedia.org/wiki/Flyweight_pattern

Що стосується питань, пов’язаних із багатопотоком, зазначених вище, то слід досить просто з деяким передбаченням реалізувати механізм блокування ресурсів, які можуть бути розподілені між потоками. http://en.wikipedia.org/wiki/Read/write_lock_pattern


0

Синглтони - це прекрасний спосіб зберігання загального стану в ранньому прототипі.

Вони не є срібною кулею і мають певні проблеми, але вони є дуже корисною схемою для певних статей інтерфейсу / логіки.

Наприклад, в iOS ви використовуєте одиночні кнопки для отримання [UIApplication sharedApplication], в cocos2d ви можете використовувати його для отримання посилань на певні об'єкти, такі як [CCNotifications sharedManager], і я особисто починаю з синглтона [Game sharedGame], де я можу стан зберігання, який поділяється між великою кількістю різних компонентів.


0

Нічого собі, це мені цікаво, оскільки я ніколи особисто не мав проблем з однотонним малюнком. Мій поточний проект - це ігровий двигун C ++ для Nintendo DS, і я реалізую безліч утиліт апаратного доступу (наприклад, VRAM Banks, Wifi, два графічні двигуни) як одиночні екземпляри, тому що вони призначені для завершення глобального C функції в базовій бібліотеці.


Моє запитання було б тоді, навіщо взагалі використовувати одиночні? Я бачу, що люди люблять обертати API з одинаковими класами або класами, які складаються лише зі статичних функцій, але навіщо взагалі турбуватися з класом? Мені здається, навіть простіше мати лише виклики функцій (загорнуті за вашим бажанням), але потім внутрішні для них отримують доступ до "глобального" стану. Напр. Журнал :: GetInstance () -> LogError (...) так само може бути LogError (...), який внутрішньо отримує доступ до будь-якого глобального стану, не вимагаючи про це клієнтського коду.
Даш-Том-Банг

0

Тільки коли у вас є елемент, у якого є лише один контролер, але обробляється декількома модулями.

Такий, як, наприклад, інтерфейс миші. Або інтерфейс джойстика. Або музичний плеєр. Або звуковий плеєр. Або екран. Або менеджер збереження файлів.


-1

Глобали набагато швидше! Так воно ідеально підходило б для інтенсивного застосування, як гра.

Сінглтони є кращим глобальним, ІМО, і, отже, правильним інструментом.

Використовуйте це економно!


Набагато швидше, ніж що ? Глобали знаходяться на якійсь випадковій сторінці пам'яті, якщо вони вказівник, і на якійсь фіксованій, але, ймовірно, на віддаленій сторінці пам'яті, якщо вони є значенням. Компілятор не може використовувати будь-які корисні оптимізації для цього виду. За будь-якої міри, про яку я можу придумати, глобальні сповільнення є повільними .

Швидше, ніж геттери та сетери та передачі довідок навколо. Але не на багато. Це допомагає зменшити розміри, тому це допоможе в деяких системах. Я, мабуть, перебільшував, коли сказав "багато", але я дуже скептично ставився до того, хто сказав, що ти не повинен щось використовувати. Вам просто потрібно використовувати свій здоровий глузд. Зрештою, одиночні - це не що інше, як член статичного класу, і це глобали.
jacmoe

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