Створення карти плитки


25

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

Ігровий малюнок

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

Бажаний результат


1
Окрім запропонованих відповідей, ви можете написати власний двигун стільникового автомата для генерації таких карт. Змінюючи правила автомата, ви могли генерувати дуже різну поведінку, ведучи в дуже різних типах карт. Наприклад, gievn 2d автомат, схожий на Life, правила затоплення можуть призвести до "океану та островів" (Як на вашому малюнку вище), і таке правило, як 1267/17, може призвести до прекрасних лабіринтів.
— Manu343726

Відповіді:


19

Що ви можете зробити, це випадковим чином створити карту Вороного на зразок такої:

  1. Вибір випадкових center points(див. Чорні точки) та випадковим чином вирішують, чи є вони травою чи брудом.
  2. Тоді для всіх плиток перевірте, чи вона найближча до center pointбруду чи трави.
  3. Готово!

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

Ви можете покращити це, поділивши center pointsна islandsалгоритм, який:

  1. Вибирає невелику групу centers pointsі позначає їх як leaders.
  2. Ітеративно додає кожен виток випадкової сусідньої невизначеної центральної точки.
  3. Готово!

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


1
Дякую, але це здається дуже складним рішенням.
— Вільда

2
Це не дуже складне рішення. Спочатку виберіть випадковим чином center points. Тоді вирішіть, чи це трава чи бруд. Тепер переведіть петлю над масивом і вирішіть, чи кожна плитка знаходиться найближче до брудної точки або точки трави. Можливо, скажіть мені, яка частина складна?
— вовкдаун

Вимірювання відстані. У всякому разі, я спробую і повідомити вам про це.
— Вільда

Гаразд, тому я успішно створив деякі моменти. ( dropbox.com/s/dlx9uxz8kkid3kc/random_tile_map2.png ) і тому весь мій клас для генерації виглядає так: dropbox.com/s/pxhn902xqrhtli4/gen.java . Але це все ще не працює.
— Вільда

3
@ViliX ваші посилання порушені
— Artur Czajka

24

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

Тоді ви можете використовувати висоту в якості порадника, наскільки високий шанс появи трави / бруду в одному регіоні карти.

Приклад (значення шуму Перліна від 0-256): Якщо значення перевищує 200, шанс розміщення трави становить 80% (бруд 20%). Якщо значення становить від 100 до 200, шанс помістити траву - 50% (бруд також 50%). Якщо значення нижче 100, шанс помістити траву становить 20% (бруд 80%).


Добре, скажімо, у мене є масив [] [] float (0-1 ймовірності), і я можу використовувати його для нерестування плиток з ймовірністю. Але як я заповнити цей масив ймовірностей? Масив - це, скажімо, 400x200, як заповнити його значеннями ймовірності?
— Вільда

Він пропонує наповнити його перліновим шумом (замість білого шуму, як монетки).
— вовкдаун

Так, але як я можу цього досягти?
— Вільда

Посилання, яке я розмістив, може очистити це питання. Спочатку генеруйте шум, а потім згладьте цей шум. Результатом буде двовимірний масив, який ви можете використовувати для подальшого генерування карти каре. посилання
— Klitz

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

8

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

http://gamedevelopment.tutsplus.com/tutorials/generate-random-cave-levels-using-cellular-automata--gamedev-9664

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

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

і воно закінчується схожим на печеру

за допомогою цього коду індекс можна перетворити в положення x & y і назад

public int TileIndex(int x, int y)
{
    return y * Generator.Instance.Width + x;
}
public Vector2 TilePosition(int index)
{
    float y = index / Generator.Instance.Width;
    float x = index - Generator.Instance.Width * y;
    return new Vector2(x, y);
}

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

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

private int GetAdjacentCount(List<bool> list, Vector2 p)
{
    int count = 0;
    for (int y = -1; y <= 1; y++)
    {
        for (int x = -1; x <= 1; x++)
        {
            if (!((x == 0) && (y == 0)))
            {
                Vector2 point = new Vector2(p.x + x, p.y + y);
                if (PathFinder.Instance.InsideMap(point))
                {
                    int index = PathFinder.Instance.TileIndex(point);
                    if (list[index])
                    {
                        count++;
                    }
                }
                else
                {
                    count++;
                }
            }
        }
    }
    return count;
}
private List<bool> GetCellularList(int steps, float chance, int birth, int death)
{
    int count = _width * _height;
    List<bool> list = Enumerable.Repeat(false, count).ToList();
    for (int y = 0; y < _height; y++)
    {
        for (int x = 0; x < _width; x++)
        {
            Vector2 p = new Vector2(x, y);
            int index = PathFinder.Instance.TileIndex(p);
            list[index] = Utility.RandomPercent(chance);
        }
    }
    for (int i = 0; i < steps; i++)
    {
        var temp = Enumerable.Repeat(false, count).ToList();
        for (int y = 0; y < _height; y++)
        {
            for (int x = 0; x < _width; x++)
            {
                Vector2 p = new Vector2(x, y);
                int index = PathFinder.Instance.TileIndex(p);
                if (index == -1) Debug.Log(index);
                int adjacent = GetAdjacentCount(list, p);
                bool set = list[index];
                if (set)
                {
                    if (adjacent < death)
                        set = false;
                }
                else
                {
                    if (adjacent > birth)
                        set = true;
                }
                temp[index] = set;
            }
        }
        list = temp;
    }
    if ((steps > 0) && Utility.RandomBool())
        RemoveSmall(list);
    return list;
}

2
Поясніть, будь ласка, що робить ваш код, а не розміщувати зразок того, що він робить, посилання та сам код. Ваша відповідь повинна бути самодостатньою, так що навіть якщо посилання розриваються, вона все ще може бути корисною.
— Фонд позову Моніки

6

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

Для кожного пункту цього списку ви відвідуєте всіх сусідів. Поки у вас залишилось достатньо енергії (починається з 40), додайте бажану плитку та додайте її до списку, який потрібно відвідати. Дайте новій плитці меншу потужність, визначену вами. Найпростіше = випадкове опускання. Після того як ви відвідали плитку зі списку, видаліть її. Почніть спочатку, відвідавши будь-яку небачену, але створену плитку.

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