Як я можу оптимізувати світ вокселів Minecraft?


76

Я знайшов дивовижні великі світи Minecraft надзвичайно повільними для навігації, навіть із чотирьохядерним та м'яким графічною картою.

Я припускаю, що повільність Minecraft походить від:

  • Java, як просторове розділення та управління пам'яттю, є швидшими в рідному C ++.
  • Слабкий світовий поділ.

Я можу помилитися в обох припущеннях. Однак це змусило мене задуматися про найкращий спосіб управління великими воксельними світами. Оскільки це справжній 3D-світ, де блок може існувати в будь-якій частині світу, це в основному великий 3D-масив [x][y][z], де кожен блок у світі має тип (тобто BlockType.Empty = 0,BlockType.Dirt = 1 і т.д.)

Я припускаю, що для того, щоб такий світ працював добре, вам потрібно:

  • Використовуйте дерево певного сорту ( oct / kd / bsp ), щоб розділити всі кубики; здається, що oct / kd буде кращим варіантом, оскільки ви можете просто розділити на рівень куба, а не на рівень трикутника.
  • Використовуйте деякий алгоритм, щоб визначити, які блоки в даний момент можна побачити, оскільки блоки, наближені до користувача, можуть затуманити блоки позаду, що робить їх безглуздим.
  • Тримайте самі об’єкти блоку легкими, тому їх швидко додавати та видаляти з дерев.

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



2
То що ви насправді запитуєте? Ви запитуєте про хороші підходи до управління великими світами, або відгуки про ваш конкретний підхід, або думки з приводу управління великими світами?
doppelgreener

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

2
Тому будьте зрозумілі та додайте запитання до своєї публікації, щоб ми знали, на яке питання ми відповідаємо. ;)
doppelgreener

3
Що ви маєте на увазі під "надзвичайно повільним навігацією"? Однозначно дещо сповільнюється, коли гра генерує новий ландшафт, але після цього, Minecraft прагне обробляти місцевість досить добре.
Тедей

Відповіді:


107

Скелі двигуна Voxel

Трава двигуна Voxel

Що стосується Java проти C ++, я написав воксель в обох (версія C ++, показана вище). Я також пишу воксельні двигуни з 2004 року (коли вони не були в моді). :) Я можу з невеликим ваганням сказати, що продуктивність на C ++ набагато перевершує (але її також важче кодувати). Це менше про швидкість обчислення, а більше про управління пам'яттю. Руками вниз, коли ви виділяєте / розмовляєте стільки даних, скільки всього у воксельному світі, C (++) - це мова, яку потрібно бити. Однак, слід подумати над своєю метою. Якщо продуктивність є вашим найвищим пріоритетом, перейдіть із C ++ Якщо ви просто хочете написати гру без кращої продуктивності, Java, безумовно, є прийнятною (про що свідчить Minecraft). Існує багато дрібниць / крайових випадків, але в цілому можна очікувати, що Java працюватиме приблизно в 1,75-2,0 рази повільніше, ніж (добре написана) C ++. Ви можете бачити , погано оптимізований, більш стару версію мого двигуна в дії тут (EDIT: нова версія тут ). Хоча генерація шматка може здаватися повільною, майте на увазі, що вона генерує тривимірні діаграми voronoi, обчислюючи поверхневі нормали, освітлення, AO і тіні на процесорі методами грубої сили. Я випробував різні методи, і я можу отримати приблизно 100 разів швидше генерування фрагментів, використовуючи різні методи кешування та інстанції.

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

  1. Кешування. Де б ви не могли, слід обчислити дані один раз. Наприклад, я розпалюю освітлення на сцені. Він міг би використовувати динамічне освітлення (в просторі екрану, як пост-процес), але випічка в освітленні означає, що мені не доведеться переходити в норми для трикутників, а це означає ...
  2. Передайте якомога менше даних на відеокарту. Люди, як правило, забувають, що чим більше даних ви передаєте в GPU, тим більше часу потрібно. Я проходжу в одному кольорі і вершинному положенні. Якщо я хочу робити цикли день / ніч, я можу просто зробити класифікацію кольору, або я можу перерахувати сцену, коли сонце поступово змінюється.

  3. Оскільки передача даних в GPU настільки дорога, можна створити двигун у програмному забезпеченні, яке в деяких відношеннях швидше. Перевага програмного забезпечення полягає в тому, що він може робити всі види маніпулювання даними / доступ до пам'яті, що просто неможливо в GPU.

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

  5. Розгляньте списки дисплеїв (для OpenGL). Незважаючи на те, що це "старий" шлях, вони можуть бути швидшими. Ви повинні переписати список відображення в змінну ... якщо ви викликаєте операції створення списку дисплеїв у режимі реального часу, це буде нечестиво повільним. Як швидше відображається список відображення? Він лише оновлює стан атрибутів проти вершин. Це означає, що я можу пропустити до шести граней, потім одного кольору (проти кольору для кожної вершини вокселя). Якщо ви використовуєте GL_QUADS та кубічні вокселі, це може заощадити до 20 байт (160 біт) на воксель! (15 байт без альфа, хоча зазвичай ви хочете, щоб речі були 4-байтними.)

  6. Я використовую грубу силу методу візуалізації "фрагментів" або сторінок даних, що є загальною методикою. На відміну від octrees, набагато простіше / швидше читати / обробляти дані, хоча набагато менш зручні для пам’яті (однак, у ці дні ви можете отримати 64 гігабайти пам’яті за $ 200– 300 доларів)… не те, що середній користувач має це. Очевидно, що ви не можете виділити один величезний масив для всього світу (набір 1024x1024x1024 вокселів - це 4 гігабайти пам'яті, якщо припустити, що для вокселя використовується 32-бітний інт). Таким чином, ви виділяєте / діліть безліч малих масивів, виходячи з їх близькості до глядача. Ви також можете розподілити дані, отримати необхідний список відображення, а потім скинути дані, щоб зберегти пам'ять. Я думаю, що ідеальним комбо може бути використання гібридного підходу октрисів та масивів - зберігання даних у масиві під час процедурного генерування світу, освітлення тощо.

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

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

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

  10. Як правило, все, що ви робите з програмування: CACHE LOCALITY! Якщо ви можете зберегти кеш-пам'ять речей (навіть за невеликий проміжок часу, це призведе до величезної різниці. Це означає, що ви зберігаєте ваші дані в одній і тій же області пам’яті) і не перемикайте ділянки пам’яті на обробку занадто часто. в ідеалі працюйте на одному шматку за потоком і зберігайте цю пам'ять виключно для потоку. Це не стосується лише кешу процесора. Подумайте про таку ієрархію кешу (найповільніша та швидка): мережа (хмара / база даних / тощо) -> жорсткий диск (отримайте SSD, якщо у вас його ще немає), ram (отримайте потрійний канал або більшу оперативну пам’ять, якщо у вас його ще немає), кеш-пам'ять процесора, регістри. Спробуйте зберегти свої дані останній кінець, і не міняти його більше, ніж потрібно.

  11. Нитки. Зроби це. Світи Voxel добре підходять для нарізування різьби, оскільки кожну частину можна обчислити (в основному) незалежно від інших ... Я побачив буквально покращення майже в 4 рази (на 4-х ядерних, 8-ти потокових Core i7) у світовій генерації процедур, коли я писав процедури для нарізування різьби.

  12. Не використовуйте типи даних char / byte. Або шорти. Ваш середній споживач матиме сучасний процесор AMD або Intel (як, напевно, і ви). Ці процесори не мають 8-бітових регістрів. Вони обчислюють байти, вкладаючи їх у 32-бітний слот, а потім перетворюють їх назад (можливо) в пам'ять. Ваш компілятор може робити всілякі вуду, але, використовуючи 32 або 64 бітове число, ви отримаєте найбільш передбачувані (і найшвидші) результати. Так само значення "bool" не приймає 1 біт; компілятор часто використовує цілі 32 біти для bool. Можливо, заманливо робити певні типи стиснення ваших даних. Наприклад, ви можете зберігати 8 вокселів як одне число (2 ^ 8 = 256 комбінацій), якби вони були одного типу / кольору. Однак ви повинні подумати про наслідки цього - це може врятувати багато пам'яті, але це також може перешкоджати працездатності навіть при малому часу декомпресії, оскільки навіть ця невелика кількість зайвого часу масштабується кубічно з розміром вашого світу. Уявіть, як обчислити промінь; для кожного кроку радіомовлення вам доведеться запустити алгоритм декомпресії (якщо тільки ви не придумали розумний спосіб узагальнення обчислення для 8 вокселів за один крок променя).

  13. Як згадує Жозе Чавес, модель легкої ваги може бути корисною. Так само, як ви використовуєте растрову карту для представлення плитки у двомірній грі, ви можете створити свій світ із кількох типів 3D-плиток (або блоків). Недоліком цього є повторення текстур, але ви можете покращити це за допомогою дисперсійних текстур, які підходять один до одного. Як правило, ви хочете використовувати інстанцію де завгодно.

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

  15. Розкрутіть петлі і тримайте масиви рівними! Не робіть цього:

    for (i = 0; i < chunkLength; i++) {
     for (j = 0; j < chunkLength; j++) {
      for (k = 0; k < chunkLength; k++) {
       MyData[i][j][k] = newVal;
      }
     }
    }
    //Instead, do this:
    for (i = 0; i < chunkLengthCubed; i++) {
     //figure out x, y, z index of chunk using modulus and div operators on i
     //myData should have chunkLengthCubed number of indices, obviously
     myData[i] = newVal;
    }

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

EDIT 2: при використанні мультиіндексних циклів найкраще петлювати в порядку z, y, x, а не навпаки. Ваш компілятор може оптимізувати це, але я був би здивований, якби це було. Це забезпечує максимальну ефективність доступу до пам'яті та локації.

for (k < 0; k < volumePitch; k++) {
    for (j = 0; j < volumePitch; j++) {
        for (i = 0; i < volumePitch; i++) {
            myIndex = k*volumePitch*volumePitch + j*volumePitch + i;
        }
    }
}
  1. Іноді доводиться робити припущення, узагальнення та жертви. Найкраще, що ви можете зробити, це припустити, що більша частина вашого світу повністю статична, і змінюється лише кожні пару тисяч кадрів. Для анімованих куточків світу це можна зробити окремо. Припустімо також, що більша частина вашого світу є абсолютно непрозорою. Прозорі об’єкти можуть бути відображені в окремому проході. Припустимо, що текстури змінюються лише кожні x одиниці, або що об'єкти можна розміщувати лише з кроком x. Припустимо, фіксований світовий розмір ... настільки ж спокусливим, як нескінченний світ, це може призвести до непередбачуваних системних вимог. Наприклад, для спрощення генерації візерунка вороної в скелях вище, я припускав, що кожна центральна точка вороного лежала в рівномірній сітці з невеликим зміщенням (іншими словами, мається на увазі геометричне хеширование). Припустимо світ, який не загортається (має краї). Це може спростити безліч складностей, введених системою координат обертання, з мінімальними витратами на досвід користувача.

Ви можете прочитати більше про мої реалізації на моєму сайті


9
+1. Приємний дотик, включаючи фотографії вгорі, як стимул для читання есе. Тепер, коли я прочитав твір, можу сказати, що вони не потрібні, і це того варте. ;)
Джордж Дакетт

Спасибі - картина варта тисячі слів, як кажуть. :) Окрім того, щоб зробити мою стіну тексту менш страшною, я хотів дати читачам уявлення про те, скільки вокселів можна винести з розумною швидкістю, використовуючи описані методи.
Gavan Woolery

14
Я все ще бажаю, щоб SE дозволила вподобати конкретні відповіді.
joltmode

2
@PatrickMoriarty # 15 - досить поширена хитрість. Якщо припустити, що ваш компілятор не проводить цю оптимізацію (він може розкрутити ваш цикл, але він, ймовірно, не буде ущільнювати багатовимірний масив). Ви хочете зберегти всі ваші дані в одному і тому ж просторі пам'яті для кешування. Багатовимірний масив (потенційно) може бути розподілений у багатьох просторах, оскільки це масив покажчиків. Що стосується розгортання циклу, подумайте, як виглядає складений код. Для того, щоб мати найменший обмін реєстрацією та кешем, ви хочете створити найменшу кількість змін / інструкцій. Як ви думаєте, які складені детальніше?
Gavan Woolery

2
Хоча деякі моменти тут хороші, особливо щодо кешування, потоку даних та мінімізації передачі GPU, деякі з них жахливо неточні. 5: ЗАВЖДИ використовуйте VBO / VAO замість списків відображення. 6: Більше ОЗУ просто потребує більшої пропускної здатності. З відведеннями до 12: ТОЧНЕ протилежне стосується сучасної пам’яті, для якої кожен збережений байт збільшує шанси помістити більше даних у кеш. 14: У Minecraft більше вершин, ніж пікселів (усіх цих віддалених кубів), тому перенесіть обчислення до піксельного шейдера, а не від нього, бажано з відкладеним затіненням.

7

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

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

Моя ідеальна система була б трохи складнішою ієрархією.

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

Сегмент буде блоком 32x32x32 плитки.

  1. Прапори встановлюються для кожної з шести сторін, якби вся ця сторона є суцільними блоками. Це дозволило б рендеріру закуповувати сегменти за цим сегментом. Наразі Minecraft, здається, не проводить тест на оклюзію. Але згадувалося про відключення апаратної оклюзії яке може бути дорогим, але кращим, ніж надання величезної кількості полігонів на картках низького класу.
  2. Сегменти завантажуються в пам'ять лише під час діяльності (гравці, NPC, фізика води, ріст дерев, тощо). В іншому випадку вони будуть відправлені безпосередньо все ще стисненими з диска клієнтам.

Сектори будуть блоком 16х16х8 сегментів.

  1. Сектори відстежують найвищий сегмент для кожного вертикального стовпця, щоб сегменти, вищі за цей, могли швидко визначити порожніми.
  2. Він також би відслідковував нижній оклюзійний сегмент, так що кожен сегмент, який потрібно вивести з поверхні, можна було швидко схопити.
  3. Сектори також відстежують наступного разу, коли кожен сегмент потребує оновлення (фізика води, ріст дерев, тощо). Такого способу завантаження в кожному секторі було б достатньо, щоб підтримувати світ живим і завантажувати лише в сегментах досить довго, щоб виконати свої завдання.
  4. Усі позиції суб'єктів господарювання відстежувались би відносно Сектора. Це дозволить уникнути помилок з плаваючою комою, наявних у Minecraft під час подорожі дуже далеко від центру карти.

Світ був би нескінченною картою секторів.

  1. Світ відповідав би за управління секторами та їх наступні оновлення.
  2. Світ буде превентивно надсилати сегменти гравцям за їх потенційними шляхами. Minecraft реактивно відправляє сегменти, які вимагає клієнт, вимагаючи затримки.

Як правило, ця ідея мені подобається, але як би ви внутрішньо склали карту секторів світу ?
Clashsoft

Хоча масив буде найкращим рішенням для плитки в сегменті та сегментів у секторі, секторам у світі потрібно щось інше, щоб забезпечити нескінченний розмір карти. Моєю пропозицією було б використовувати хеш-таблицю (псевдо словник <Vector2i, сектор>), використовуючи координати XY для хеша. Тоді Світ може просто шукати сектор за заданими координатами.
Джош Браун

6

Minecraft досить швидкий, навіть на моєму 2-х ядерному. Тут здається, що Java не є обмежуючим фактором, хоча є дещо відставання сервера. Місцеві ігри здаються краще, тому я збираюся припустити деяку неефективність.

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

Як ви здогадалися, додаток, як ви здогадалися, повинен вирішити, чи можна бачити блок чи ні, виходячи з того, чи не затьмарені інші блоки.

Також зауважте, що є блокові ФАСИ, які можна вважати невидимими, внаслідок того, що вони або затьмарені (тобто, інший блок закриває обличчя), або за яким напрямком вказує камера (якщо камера спрямована на північ, ви можете Ви не бачите північне обличчя БІЛЬКИХ блоків!)

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

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


4
"грудочки" зазвичай називають шматками.
Марко

Хороший улов (+1); відповідь оновлена. (Спочатку робив на пам’ять і забув правильне слово.)
Олі

Неефективність, про яку ви посилаєтеся, також відома як "мережа", яка ніколи не діє так само двічі, навіть якщо однакові кінцеві точки спілкування.
Едвін Бак

4

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

Причина, що Minecraft повільна, має багато спільного з деякими сумнівними дизайнерськими рішеннями низького рівня - наприклад, щоразу, коли на блок посилається позиціонування, гра перевіряє координати приблизно з 7, якщо заяви твердять, що це не виходить за межі. . Крім того, немає ніякого способу захопити "шматок" (16x16x256 одиниця блоків, з якою працює гра), а потім посилатись блоками на нього безпосередньо, щоб обійти пошукові запити кеш-пам'яті та, ерм, дурні питання перевірки (так, кожна посилання на блок також включає порядок пошуку, серед іншого.) У своєму моді я створив спосіб схопити та змінити масив блоків безпосередньо, що підсилило масивне покоління підземелля від немислимо млявого до непомітно швидкого.

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

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

Тож якою б ви не вибрали мову, намагайтеся бути дуже інтимним із деталізацією щодо впровадження / низького рівня, тому що навіть одна маленька деталь у такому проекті, як цей, може змінити значення (один приклад для мене в C ++ був: "Чи може компілятор статично вбудовувати функцію покажчики? "Так, це можна! Зробив неймовірну різницю в одному з проектів, над якими я працював, оскільки у мене було менше коду та переваги вбудовування.)

Мені справді не подобається ця відповідь, оскільки це ускладнює дизайн на високому рівні, але це болюча правда, якщо продуктивність викликає занепокоєння. Сподіваюся, ви знайшли це корисним!

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


2

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

Що ви робите з цими даними, тоді залежить від вас. Для продуктивності GFX ви можете використовувати відсікання для обрізання прихованих об’єктів, об'єктів, які занадто малі, щоб їх було видно тощо

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


1

Щось на що подивитися - це Flyweight Design. Я вважаю, що більшість відповідей так чи інакше посилаються на цю модель дизайну.

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

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

Очевидно, єдиний спосіб знати - почати впроваджувати власні та зробити кілька тестів пам'яті для продуктивності. Дайте нам знати, як це йде!

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