Моделювання тиску в сітчастому моделюванні рідини


30

У моїй грі XNA у мене є 2D-водна система на основі сітки, у нас є метод, що використовує стільникові автомати для імітації падіння та розповсюдження води.

Приклад води, що стікає по схилу:

Фізика води

Кожна плитка може містити масу від 0 до 255 значень рідини, що зберігається в байті. Я не використовую floatsстару систему води, яку я зробив, проте вона додала ускладнень і вразила продуктивність.

Кожна водна плитка оновлює себе простим набором правил:

  1. Якщо плитка внизу має пробіл, перемістіть якомога більше від поточної плитки до нижньої (Flow Down)
  2. Якщо дві сторони не однакові і не дорівнюють нулю, і обидві є прохідними, отримуємо суму 3 плиток (ліва + ток + права) і ділимо її на 3, залишаючи решту на середній (поточній) плитці
  3. Якщо вищевказане правило дало число 2 як суму, слід розділити плитки на дві сторони (1, 0, 1)
  4. Якщо правило 2 дало 1 як суму, виберіть випадкову сторону, в яку слід вступати
  5. Якщо правило 2 не вдалося, слід перевірити, чи одна сторона є прохідною, а інша ні. Якщо це правда, ми розділимо поточну плитку навпіл для 2 плиток

Як я можу розширити цю логіку, щоб включити тиск? Тиск призведе до того, що рідина підніметься над «U-Вигинами» і заповнить повітряні кишені.

Приклад того, як це не вдається:

Збій тиску

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


Проблема в тому, що це важко утримати це мобільні автомати. Оскільки зараз кожен блок повинен знати більше, ніж просто те, що знаходиться поруч. Я створив систему, схожу на ту, яку ви хочете в 3D. Це досить складна система, але я думаю, що це було б більш доцільно в 2D.
MichaelHouse

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

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

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

1
Зауважте, що, як тільки ви додаєте тиск повітря, два приклади повітряної кишені є потенційно цілком дійсними (закриті камери тиску). Я припускаю, що ви не використовуєте 255 байт , а скоріше значення 0-255; у будь-якому випадку ви, мабуть, не захочете таким чином використовувати весь діапазон. Я, мабуть, обмежую це, хм, 0-15 для "1 атмосфери" тиску (немає такого поняття, як "негативний" тиск, правда?), Що дозволяє підвищити тиск, якого вам зараз не вистачає. Коли ви включите в повітряний блок «повітряні» блоки, природно більша «вага» водяних блоків повинна призвести до того, що він обертається навколо вигинів.
Завод-Муза

Відповіді:


6

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

Я намагався намагатися надати кожному блоку поверхневої води (будь-який блок з водою в ньому і без водяного блоку над ним) початкове значення тиску, рівне (або функція) його висоті від дна світу. Неявне значення тиску для будь-якої непрохідної плитки становить MAX_PRESSURE(скажімо, 255), а для плитки під відкритим небом - MIN_PRESSURE(0).

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

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

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

P' = P + qgh

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

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


20

Я створив систему, подібну до тієї, яку ви шукаєте в 3D. У мене є коротке відео, де демонструється проста механіка його тут, і допис у блозі тут .

Ось невеликий подарунок, який я зробив із механіки тиску за невидимою стіною (грав на великій швидкості):

введіть тут опис зображення

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

//Data2                          Data
//______________________________  _____________________________________
//|0    |0      |000   |000    |  |0        |0       |000      |000   |
//|Extra|FlowOut|Active|Largest|  |HasSource|IsSource|Direction|Height|
//------------------------------  -------------------------------------
  • Height - це кількість води в кубі, подібна до вашого тиску, але в моїй системі просто 8 рівнів.
  • Direction- напрямок, в якому йде потік. Вирішуючи, куди подаватиметься вода далі, швидше продовжуватиметься у своєму нинішньому напрямку. Це також використовується для швидкого відстеження потоку назад до його вихідного куба при необхідності.
  • IsSourceвказує, чи є цей куб вихідним кубом, тобто ніколи не вичерпується вода. Використовується для джерела річок, джерел тощо. Куб зліва в gif зверху є, наприклад, кубом джерела.
  • HasSourceвказує, чи цей куб підключений до вихідного куба. Підключившись до джерела, куби намагаються постукати джерелом для отримання більшої кількості води, перш ніж шукати інші "повніші" не джерела кубики.
  • Largestповідомляє цьому кубу, який найбільший потік між ним та його вихідним кубом. Це означає, що якщо вода протікає через вузьку щілину, вона обмежує потік до цього куба.
  • Active- лічильник. Коли цей куб має активний потік, що йде через нього, до нього чи від нього, активізується. В іншому випадку активність випадково зменшується. Як тільки активний потрапить до нуля (мається на увазі неактивний), кількість води почне зменшуватися в цьому кубі. Цей вид діє, як випаровування або вмочування в землю. ( Якщо у вас потік, у вас має бути прилив! )
  • FlowOutвказує, чи пов’язаний цей куб із кубом, що знаходиться на краю світу. Після того, як пройде шлях до краю світу, вода, як правило, обирає цей шлях над будь-яким іншим.
  • Extra є додатковим бітом для подальшого використання.

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

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

Псевдокод алгоритму такий:

for i = 0 to topOfWorld //from the bottom to the top
   while flowouts[i].hasitems() //while this layer has flow outs
       flowout = removeRandom(flowouts[i]) //select one randomly
       srcpath = getPathToParent(flowout) //get the path to its parent
       //set cubes as active and update their "largest" value
       //also removes flow from the source for this flow cycle
       srcpath.setActiveAndFlux() 

//now we deal with regular flow
for i = 0 to topOfWorld //from the bottom to the top
    while activeflows[i].hasitems() //while this layer has water
        flowcube = removeRandom(activeflows[i]) //select one randomly
        //if the current cube is already full, try to distribute to immediate neighbors
        flowamt = 0
        if flowcube.isfull 
           flowamt = flowcube.settleToSurrounding
        else
           srcpath = getPathToParent(flowcube) //get the path to its parent
           flowamt = srcpath.setActiveAndFlux()
           flowcube.addflow(flowamt)

        //if we didn't end up moving any flow this iteration, reduce the activity
        //if activity is 0 already, use a small random chance of removing flow
        if flowamt == 0
           flowcube.reduceActive()

 refillSourceCubes()

Основні правила розширення потоку, де (упорядковано за пріоритетом):

  1. Якщо в кубіку нижче води менше, стікайте вниз
  2. Якщо сусідній куб на одному рівні має менше води, стікайте бічно.
  3. Якщо в кубі вище води менше І вихідний куб вище куба вище, підведіть вгору.

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

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

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

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


Спасибі! Дуже інформативно! Я незабаром почну працювати над цим і прийму це, якщо все піде добре.
Cyral

Вірна думка. Я уявляю гібрид вашої системи, і цей би був дуже ефективним для 2D світу. Пінг мені в чаті (з @ byte56), якщо ви хочете обговорити деталі.
MichaelHouse

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

3
Зрозуміло. Я, мабуть, витрачав місяці, працюючи над цим (і переробляючи його). Я буду деякий час, хоча :)
MichaelHouse

2

Я якось погоджуюся з Шоном, але я би зробив це трохи інакше:

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

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

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


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

@ Byte56 Ти неправильно трактуєш те, що я сказав. Я кажу, що вода піднімається, коли тиск у блоці, який ви аналізуєте, занадто високий для тиску, що застосовується зверху, не те, що тиск зверху занадто великий!
Лорен Печтел

Гаразд, тому дозвольте перефразувати те, що ви сказали, щоб я зрозумів: "вода піднімається, коли тиск у блоці, який ви аналізуєте, більший за тиск, що застосовується зверху". Це правильно?
MichaelHouse

@ Byte56 Так. Тиск у блоці повинен бути вагою води над ним або подаватися збоку, коли у нас десь вище тверда поверхня. Занадто малий тиск на нього означає, що води недостатньо, переміщуйте воду вгору.
Лорен Печтел

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

1

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


Це також гарна ідея, не впевнений, чи спрацює вона у всіх випадках, але я буду розглядати її.
Cyral

Добре! Дайте мені знати, працювало чи ні. з повагою
almanegra

Буду, останнім часом я трохи зайнятий.
Кірал

-2

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

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


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