Процедурне покоління, оновлення гри та ефект метеликів


10

ПРИМІТКА: Я запитав це в Stack Overflow кілька днів тому, але у нього було дуже мало переглядів і жодної відповіді. Зрозуміло, що я повинен запитати на gamdev.stackexchange.

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

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

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

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

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

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

Зараз я працюю в Unity3D / C #, хоча це мовне агностичне питання.

ОНОВЛЕННЯ:

Дякую за відповіді.

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

Я вважаю, що концепція "Клітки" Stormwind є особливо корисним способом мислення про речі. Клітка - це, в основному, переселене місце, що запобігає побічним впливам невеликих змін, тобто ув'язнення метелика.


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

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

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

Відповіді:


8

Я думаю, ви тут накрили основи:

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

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

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


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

1
Це взагалі неможливо. Ви навіть не гарантуєте, що існує нове джерело нового генератора, яке дає такий же вихід, як і старий. Зазвичай ці насіння містять близько 64 біт, але кількість можливих світів, яку може підтримувати ваша гра, швидше за все, перевищує 2 ^ 64, тому кожен генератор коли-небудь виробляє лише їх підмножину. Зміна генератора, швидше за все, призведе до нового підмножини рівнів, яке може мати мало або навіть не перетинатися з попереднім набором генератора.
DMGregory

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

4

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

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

Числа: періодичні послідовності / шліців Припустимо, у вас є один генератор чисел , який служить для всього. Він не присвоює значення, він просто виписує числа в послідовності - як і будь-яка PRNG. Враховуючи одне і те ж насіння протягом двох циклів, ми отримуємо однакові послідовності, так? Тепер ви задумаєтесь і вирішите, що у вашій грі буде 30 аспектів, які регулярно потребуватимуть випадкового значення. Тут ми призначаємо циклічну послідовність з 30 слотів, наприклад, кожне перше число в послідовності - це приблизне розташування місцевості, кожне друге число - збурення місцевості ... і т.д. ... кожне десяте число додає деяку помилку до стану AI для реалізму. Отже ваш період - 30.

Після 10 у вас 20 вільних слотів, які ви можете використовувати для інших аспектів у міру розвитку дизайну гри. Тут варто зрозуміти, що ви повинні створити номери для слотів 11-30, навіть якщо вони наразі не використовуються , тобто завершують період, щоб повернутися до наступної послідовності 1-10. Це має ціну процесора, хоча вона повинна бути незначною (залежно від кількості вільних слотів). Інший недолік - ви повинні бути впевнені, що ваш остаточний дизайн може бути розміщений у кількості слотів, які ви зробили доступними на самому початку процесу розробки ... і чим більше ви призначаєте на початку, тим більше "порожніх" слотів вам, можливо, доведеться пройти кожен, щоб справи працювали.

Ефекти цього:

  • У вас є один генератор, який виробляє номери для всього
  • Зміна кількості аспектів, для яких потрібно генерувати числа, не вплине на детермінізм (за умови, що ваш період достатньо великий, щоб вмістити всі аспекти)

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


Привіт. Це схоже на деякі речі, які я роблю. Я, як правило, генерую купу підсеменів на передній частині на основі початкового світового насіння. Нещодавно я почав попередньо генерувати довгий масив шуму, і тоді кожен "слот" є просто покажчиком цього масиву. Таким чином, кожна підсистема може просто захопити потрібне насіння і працювати ізольовано. Ще одна чудова техніка - використовувати координати x, y для створення насіння для кожного місця. Я використовую код з відповіді Euphoric на цій сторінці стеку: programmers.stackexchange.com/questions/161336/…
null

3

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

Звичайно, найпопулярніший підхід - це перетворення згенерованих даних у статичні дані, як ви вже згадували.

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


Це розумна ідея просто використовувати різні генератори для різних областей.
null

2

Я підтримую площу близько 30000 квадратних кілометрів, на якій розміщено близько 1 млн. Будівель та інших об'єктів, на додаток до рандомізованих розміщень різного роду. Зовнішнє моделювання ofc. Збережені дані становлять приблизно 4 Гб. Мені пощастило мати місце для зберігання, але це не необмежено.

Випадковий випадковий, неконтрольований. Але можна трохи поставити її до клітки:

  • Контролюйте його початковий кінець (як згадується в інших публікаціях, номер насіння та кількість створених чисел).
  • Обмежте його числовий простір, напр. генерувати цілі числа лише від 0 до 100.
  • Зсуньте його числовий простір, додавши значення (наприклад, 100 + [згенеровані числа між 0 і 100] видає випадкові числа між 100 і 200)
  • Масштабуйте її (наприклад, помножте на 0,1)
  • І застосуйте навколо нього різні клітки. Це скорочення, скорочення частини покоління. Напр. якщо генерується у двовимірному просторі, можна поставити прямокутник поверх пар чисел і скребкувати те, що знаходиться назовні. Або коло, або багатокутник. Якщо у 3D-просторі можна прийняти, наприклад, лише трійки, які знаходяться всередині сфери, чи якусь іншу фігуру (зараз мислення візуально, але це не обов'язково має нічого спільного з реальною візуалізацією чи позиціонуванням).

Ось про це. Клітки також споживають дані, на жаль.

Є приказка по-фінськи, Hajota ja hallitse. Переводить на розділення і перемагай .

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

Що можна керувати для управління чи керування числовими пробілами?

  • Булева сітка є (біти маленькі!)
  • Кутові точки є
  • Як і структура дерева (= слідкувати за "клітками, що містять клітки")

У сервісному обслуговуванні та взаємозамінності версій ... у нас є
: якщо версія = n, то
: elseif версія = m, то ...
Так, база коду зростає :-).

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

Не зовсім сумісний із кумедним "nuke it fom orbit", запропонованим DMGregory, але, можливо, використовуйте маленькі та точні ядерні ядра? :-)


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

З усіх відповідей я вважаю, що найбільше думаю про цю. Мені сподобалось твої трохи філософські описи речей. Я вважаю термін "Клітка" дуже корисним при поясненні ідей, тому за це дякую. Нехай метелик летить ... у своїй клітці :)
null

PS Мені дуже цікаво дізнатися, над якою грою ти працюєш. Чи можете ви поділитися цією інформацією?
недійсне

Можна додати ще одне про числовий простір: Варто завжди залишатися близько нуля. Що ви знали, мабуть, уже. Близький до нуля дає найкращу числову точність та найвищий удар за найменші біти. Ви завжди зможете змістити цілу купу чисел, близьких до нуля, згодом, але для цього вам знадобиться лише одне число. Аналогічно, ви можете (я б майже сказав, що ВАМ ПОВИНЕН) перемістити віддалений обчислення ближче до нуля, зі зміщенням. - Stormwind
Stormwind

Оцінюючи попереднє, розглянемо невеликий рух транспортного засобу, приріст на 1 кадр 0,01 [метри, одиниці]: Ви не можете точно обчислити 10000,1 + 0,01 в 32-бітній цифровій точності (одинарний), але ви можете обчислити 0,1 + 0,01. Отже, якщо "дія" відбувається далеко (за горами :-)), не йдіть туди, а перемістіть гори до вас (рухайтесь з 10000, значить, ви зараз у 0,1). Дійсно також для місця для зберігання. Можна жадібно зберігати числові значення, близькі один до одного. Зберігайте загальну частину їх один раз, а варіанти окремо - це може зберегти шматочки! Ви знайшли посилання? ;-)
Stormwind
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.