Наприклад, базовий клас GameObject з глибокою ієрархією успадкування може бути корисним для обслуговування ...
Насправді глибокі ієрархії, як правило, гірші для ремонту, ніж дрібні, а сучасний архітектурний стиль для ігрових об'єктів має тенденцію до мілководних підходів, заснованих на агрегації .
Однак я думаю, що такий підхід може створити проблеми з ефективністю. З іншого боку, дані та функції всіх ігрових об'єктів можуть бути глобальними. Це може бути головним болем, але може бути ближчим до оптимально працюючого циклу гри.
Цикл, який ви показали, потенційно може мати проблеми з продуктивністю, але не, як мається на увазі у вашому наступному викладі, оскільки у вас є дані екземпляра та функції учасника в GameObject
класі. Скоріше, проблема полягає в тому, що якщо ви ставитесь до кожного об'єкта в грі як абсолютно однаковий, ви, ймовірно, не групуєте ці об'єкти інтелектуально - вони, ймовірно, випадковим чином розкидані по всьому списку. Потенційно, тоді кожен виклик методу оновлення цього об’єкта (незалежно від того, чи є цей метод глобальною функцією чи ні, і чи є об'єкт даними екземпляра або "глобальними даними", що плавають навколо в таблиці, яку ви індексуєте, або ін.) відрізняється від виклику оновлення в останніх ітераціях циклу.
Це може спричинити посилення тиску на систему, оскільки вам може знадобитися сторінка пам'яті відповідною функцією в пам'яті та поза нею та частіше повторно заповнювати кеш інструкцій, що призводить до уповільнення циклу. Від того, чи це можна спостерігати неозброєним оком (або навіть у профілера), залежить саме те , що вважається "ігровим об'єктом", скільки їх існує в середньому і що ще відбувається у вашій програмі.
Орієнтовані на компоненти об'єктні системи є популярною тенденцією зараз, використовуючи філософію, що агрегування є переважним у спадок . Такі системи потенційно дозволяють розділити логіку "оновлення" компонентів (де "компонент" приблизно визначається як деяка одиниця функціональності, наприклад, річ, яка представляє фізично модельовану частину об'єкта, яка обробляється фізичною системою ) на декілька потоків - дискримінують за типом компонента - якщо це можливо та бажано, що може призвести до підвищення продуктивності. Принаймні, ви можете організувати компоненти таким чином, що всі компоненти даного типу оновлюються разом , оптимально використовуючи кеш процесора. Приклад такої системи, орієнтованої на компоненти, обговорюється в цій темі .
Такі системи часто сильно роз'єднуються, що також є користю для технічного обслуговування.
Дизайн, орієнтований на дані, - це пов'язаний підхід - це орієнтація на себе навколо даних, необхідних для об'єктів, як першочергового завдання, щоб ці дані могли ефективно оброблятися масово (наприклад). Це, як правило, означає організацію, яка намагається зберегти дані, які використовуються для одного кластеру цілі, разом і оперувати ними відразу. Це принципово не сумісне з дизайном OO, і ви можете знайти деякі балаканини на цю тему тут, на GDSE, у цьому запитанні .
Насправді, більш оптимальним підходом до циклу гри був би замість оригіналу
foreach(GameObject g in gameObjects) g.update();
щось більше схоже
ProcessUserInput();
UpdatePhysicsForAllObjects();
UpdateScriptsForAllObjects();
UpdateRenderDataForAllObjects();
RenderEverything();
У такому світі, кожен GameObject
може мати покажчик або посилання на свій власний PhysicsData
або Script
або RenderData
, за винятком випадків , коли вам може знадобитися , щоб взаємодіяти з об'єктами на індивідуальній основі, але фактична PhysicsData
, Scripts
, RenderData
і так далі були б всі власністю їх відповідних підсистем (фізичний симулятор, середовище хостингу сценаріїв, візуалізація) та обробляється оптом, як зазначено вище.
Це дуже важливо відзначити , що цей підхід не є чудодійним і не завжди дає приріст продуктивності (хоча це , як правило , краще дизайн , ніж глибоке дерево успадкування). Особливо ймовірно, ви помітите, що різниця в продуктивності практично не має, якщо у вас дуже мало об'єктів або дуже багато об'єктів, з якими ви не можете ефективно паралелізувати оновлення.
На жаль, не існує такого магічного циклу, який є найбільш оптимальним - кожна гра є різною і може потребувати налаштування продуктивності по-різному. Тому дуже важливо виміряти (профілювати) речі, перш ніж сліпо піти приймати поради якогось випадкового хлопця в Інтернеті.