Нерестові одиниці у світі, спричиненому шумом Перліна?


16

У моїй грі на основі шуму Perlin виникли деякі проблеми. Погляньте на доданий скріншот нижче.

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

Білі області, які ви бачите, - це стіни, а чорні - прохідні. Трикутник посередині - гравець.

Я реалізував фізику в цій грі, намалювавши її на текстурі (білі або чорні пікселі), а потім отримав її з процесора.

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

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

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

Однак запропоноване вище рішення може бути занадто інтенсивним процесором.

Будь-які пропозиції з цього приводу?

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


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

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

1
Або, кажучи про коментар Блау, іншим способом: на ваше запитання, очевидно, немає вірної відповіді (окрім тривіального випадку карти, у якій зовсім немає настінних плиток / пікселів), якщо гравець може рухатися. Це все ще вимагає визначити, що ви маєте на увазі під "прямою лінією", щоб мати відповідь, якщо гравець нерухомий.
Мартін Сойка

Відповіді:


3

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

Це принцип, якого слід дотримуватися для проходження межі:

http://en.wikipedia.org/wiki/File:Marchsquares.png (мені ще не вдається розмістити фотографії)

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

http://en.wikipedia.org/wiki/Marching_squares


10

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

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

"straight line" variants

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

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


Чи можна це повністю реалізувати в HLSL?
Mathias Lykkegaard Lorenzen

@Mathias Lykkegaard Lorenzen: Так, сумніваюся, виконуючи кожен крок алгоритму як піксельну шейдер і рендеруючи між двома текстурними цілями, наприклад, але ... чому ? Інформація з алгоритму на процесорі вам, швидше за все, потрібна, як мінімум, для пошуку шляху.
Мартін Сойка

1
@Mathias Lykkegaard Lorenzen: Хоча це дещо відрізняється від того, про що ви просили. У цьому випадку: Як ви визначаєте "пряму лінію", враховуючи схему розділення дискретного простору?
Мартін Сойка

2
навіть якщо ви не хочете користуватися доріжкою, можливо, попросити процесор виконати роботу заливки, пам’ятайте, що вам потрібно зателефонувати лише до заливки один раз, і тоді ви матимете текстуру з 3 кольорів, що визначають стіни, вільні простори та проривні місця. для текстури 4096x4096 для процесора знадобиться менше секунди, щоб виконати роботу із заливанням.
Ali1S232

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

1

Як щодо того, щоб просто нерести траплялися? Я не бачу в цьому особливої ​​проблеми.


А що робити, якщо вони нерестують за стіну? Як би ви змусили їх досягти гравця?
Матіас Ліккегор Лоренцен

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

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

туман війни вкриє хижі нерести
KRB

1
Це все одно не буде працювати, коли гравець рухається.
aaaaaaaaaaaa

1

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

void straightlineFill(Point startPoint, Texture target)
{
    queue<Point> pointQueue;
    for (int dx = -1;dx <=1;dx ++)
            for(int dy = -1;dy <=1;dy++)
                if(dx != 0 && dy != 0)
                    pointQueue.push(point(startPoint.x + dx, startPoint.y + dy));
    while (!pointQueue.empty())
    {
        point front = pointQueue.front();
        pointQueue.pop();
        if (target.pixelAt(front) == COLOR_SPAWNABLE||
            target.pixelAt(front) == COLOR_WALL||
            target.pixelAt(front) == COLOR_NOT_SPAWNABLE)
                continue;
        taraget.setPixelAt(front, colorFilled); 
        for (int dx = -1;dx <=1;dx ++)
            for(int dy = -1;dy <=1;dy++)
                if(dx != 0 && dy != 0)
                    pointQueue.push(point(front.x + dx, front.y + dy));
        // up until now was the normal floodfill code
        // and here is the part that will do the real straight line checking

        // lineDX & lineDY will keep how much the line we are checking is skewed
        int lineDX = front.x - startPoint.x;
        int lineDY = front.y - startPoint.y;

        // step will show us how much we have to travel to reach each point of line
        point step;
        if (abs(lineDX) < abs(lineDY))
        {
            if (lineDX < 0)
                step = point(-1,0);
            if (lineDX == 0)
                if (lineDY < 0)
                    step = point(0,-1);
                else
                    step = point(0,1);
            if (lineDX > 0)
                step = point(1,0);
        }

        if (abs(lineDX) < abs(lineDY))
        {
            if (lineDY < 0)
                step = point(0,-1);
            if (lineDY == 0)
                if (lineDX < 0)
                    step = point(-1,0);
                else
                    step = point(1,0);
            if (lineDY > 0)
                step = point(0,1);
        }

        // moved will keep how much we have traveled so far, it's just some value that will speed up calculations and doesn't have any mathematical value
        point moved = 0;

        // spawnable will keep if the current pixel is a valid spawnpaint

        bool spawnable = true;

        // now we will travel on the straight line from player position to the edges of the map and check if whole line is valid spawn points or not.

        while (target.isInside(front))
        {
            front = front + step;
            moved = moved + point(step.x * lineDX, step.y * lineDY);
            if (step.x != 0 && moved.x < moved.y)
            {
                moved.x = moved.x - lineDY * sign(lineDY);
                front.y = front.y + sign(lineDY);
            }
            if (step.y != 0 && moved.y < moved.x)
            {
                moved.y = moved.y - lineDX * sign(lineDX);
                front.x = front.x + sign(lineDX);
            }

            if (target.getPixelAt(front) == COLOR_WALL)
                spawnable = false;

            if (spawnable)
            {
                target.setPixelAt(front,COLOR_SPAWNABLE);
                for (int dx = -1;dx <=1;dx ++)
                    for(int dy = -1;dy <=1;dy++)
                        if(dx != 0 && dy != 0)
                            pointQueue.push(point(front.x + dx, front.y + dy));             
            }
            else
            {
                target.setPixelAt(front,COLOR_NOT_SPAWNABLE);
            }
        }
    }
}

1

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

Це статичні дані, щоб ви могли їх попередньо оцінити.

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

  1. Горизонтальний: там, де змінюється оранжевий на синій.
  2. По вертикалі: там, де червоний змінюється на зелений та оранжевий.

enter image description here


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

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

@Loren Pechtel, нагадайте, що об'єктивом є уникнення нересту в таких місцях, як жовтий. Цей спосіб гарантує, що якщо ви випустите противника в ту саму область, що містить плеєр, це буде доступно. Звичайно, реалізувати це може бути непросто, але ідея справедлива.
Блау

Ваш перегляд не допомагає. Дві точки на опуклої кривій ніколи не матимуть законної прямої лінії між ними, період. Більше підрозділів не допоможе.
Лорен Печтел

будь ласка, ознайомтеся з визначенням опуклості з посиланням на райони або набір точок ... en.wikipedia.org/wiki/Convex
Blau

1

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


0

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

Будь-яку точку нересту, яка не має шляху, можна внести до списку виключень; або навпаки (будь-яку точку зі шляху можна внести до списку включень).

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