Кодування, кероване даними
Кожна річ, яку ви згадуєте, - це те, що можна вказати в даних. Чому ви завантажуєте aspecificmap
? Оскільки конфігурація гри говорить про те, що це перший рівень, коли гравець починає нову гру, або тому, що це ім'я поточної точки збереження у файлі збереження, який він тільки що завантажив, тощо.
Як ви знаходите aspecificmap
? Тому що це у файлі даних, в якому перераховані ідентифікатори карт та їх дискові ресурси.
Потрібно лише особливо невеликий набір "основних" ресурсів, які законно важкі або неможливі, щоб уникнути жорсткого кодування. Додавши трохи роботи, це може бути обмежено однією жорстко кодованою назвою активу за замовчуванням на зразок main.wad
або тому подібне. Цей файл потенційно можна змінити під час виконання, передавши в гру аргумент командного рядка, ака game.exe -wad mymain.wad
.
Введення коду, керованого даними, спирається на кілька інших принципів. Наприклад, можна уникнути того, щоб системи або модулі запитували певний ресурс, а замість цього інвертувати ці залежності. Тобто не DebugDrawer
завантажуйте його debug.font
в код ініціалізації; натомість DebugDrawer
взяти ручку ресурсу в його код ініціалізації. Ця ручка може бути завантажена з основного файлу конфігурації гри.
В якості конкретних прикладів з нашої бази даних, у нас є об'єкт "глобальних даних", завантажений із бази даних ресурсів (яка сама за замовчуванням є ./resources
папкою, але може бути перевантажена аргументом командного рядка). Ідентифікатор бази даних ресурсів цих глобальних даних є єдиним необхідним жорстко кодованим іменем ресурсу в кодовій базі (у нас є інші, оскільки інколи програмісти лінуються, але ми, як правило, виправляємо / видаляємо їх у підсумку). Цей глобальний об'єкт даних переповнений компонентами, єдиною метою яких є надання конфігураційних даних. Одним із компонентів є компонент Global Data UI, який містить обробку ресурсів для всіх основних ресурсів інтерфейсу (шрифти, файли Flash, піктограми, дані локалізації тощо) серед ряду інших елементів конфігурації. Коли розробник інтерфейсу вирішує перейменувати основний актив інтерфейсу з /ui/mainmenu.swf
у/ui/lobby.swf
вони просто оновлюють цю глобальну посилання на дані; ніякий код двигуна взагалі не потрібно змінювати.
Ми використовуємо ці глобальні дані для всього. Усі відтворювані персонажі, усі рівні, інтерфейс, аудіо, основні засоби, конфігурація мережі, все. (ну, не все , але інші речі - це помилки, які потрібно виправити.)
Цей підхід має безліч інших переваг. Для одного, це робить упаковку та пакет ресурсів невід'ємною частиною всього процесу. Шляхи жорсткого кодування в двигуні також мають на увазі те, що ці самі шляхи повинні бути жорстко кодовані в будь-яких сценаріях чи інструментах, що запакують ігрові активи, і ці шляхи можуть потім вийти з синхронізації. Замість цього, спираючись на один основний актив та референтні ланцюги, ми можемо створити набір активів за допомогою однієї команди на зразок bundle.exe -root config.data -out main.wad
і знати, що вона буде включати всі необхідні нам активи. Далі, оскільки постачальник буде просто дотримуватися посилань на ресурси, ми знаємо, що він буде включати лише потрібні нам активи та пропустити весь залишений пух, який неминуче накопичується протягом життя проекту (плюс ми можемо автоматично генерувати списки цього пух для обрізки).
Хитрий кутовий випадок усього цього - у сценаріях. Зробити керовану даними двигуна концептуально просто, але я бачив дуже багато проектів (хобі до AAA), коли сценарії вважаються даними, а отже, їм "дозволено" просто використовувати шляхи ресурсів без розбору. Не робіть цього. Якщо для файлу Lua потрібен ресурс, і він просто викликає таку функцію, як textures.lua("/path/to/texture.png")
тоді, конвеєр активів матиме багато проблем, знаючи, що сценарій потребує /path/to/texture.png
коректної роботи і може вважати цю текстуру невикористаною та непотрібною. До сценаріїв слід ставитися як до будь-якого іншого коду: будь-які потрібні їм дані, включаючи ресурси або таблиці, повинні бути вказані у записі конфігурації, яку двигун та ресурс трубопроводу можуть перевірити на наявність залежностей. Дані, на яких написано "сценарій завантаження foo.lua
", повинні говорити "foo.lua
і надайте йому ці параметри "там, де параметри включають будь-які необхідні ресурси. Якщо скрипт випадково породжує ворогів, наприклад, передайте список можливих ворогів у скрипт із цього файлу конфігурації. Потім двигун може попередньо завантажити ворогів рівнем ( оскільки він знає повний перелік можливих нересурсів) і конвеєр ресурсів знає поєднувати всіх ворогів з грою (оскільки вони остаточно посилаються на дані конфігурації). Якщо сценарії генерують рядки імен шляхів і просто викликають load
функцію, то ні двигун та ресурс не мають жодного способу дізнатися, які саме ресурси може спробувати завантажити сценарій.