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


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.