Карта
Я делаю RPG на основе плиток с Javascript, используя перлин-карты высоты шума, а затем назначаю тип плиток на основе высоты шума.
Карты в конечном итоге выглядят примерно так (на мини-карте).
У меня есть довольно простой алгоритм, который извлекает значение цвета из каждого пикселя на изображении и преобразует его в целое число (0-5) в зависимости от его положения между (0-255), которое соответствует плитке в словаре листов. Этот массив 200x200 затем передается клиенту.
Затем механизм определяет плитки из значений в массиве и рисует их на холсте. Итак, я получаю интересные миры с реалистично выглядящими чертами: горы, моря и т. Д.
Теперь следующее, что я хотел сделать, - это применить какой-нибудь алгоритм наложения, который бы позволял плиткам плавно сливаться с соседями, если сосед не принадлежит к тому же типу. Пример карты выше - это то, что игрок видит на своей мини-карте. На экране они видят визуализированную версию сечения, отмеченную белым прямоугольником; где плитки отображаются с их изображениями, а не как одноцветные пиксели.
Это пример того, что пользователь будет видеть на карте, но это не то же место, что показано в окне просмотра выше!
Именно с этой точки зрения я хочу, чтобы переход произошел.
Алгоритм
Я придумал простой алгоритм, который будет проходить по карте в области просмотра и отображать другое изображение поверх каждой плитки, если оно будет рядом с плиткой другого типа. (Не меняя карту! Просто рендеринг некоторых дополнительных изображений.) Идея алгоритма состояла в том, чтобы профилировать соседей текущего тайла:
Это примерный сценарий того, что движок может визуализировать, причем текущая плитка отмечена знаком X.
Создается массив 3x3 и считываются значения вокруг него. Так что для этого примера массив будет выглядеть так.
[
[1,2,2]
[1,2,2]
[1,1,2]
];
Моя идея заключалась в том, чтобы разработать серию случаев для возможных конфигураций плитки. На очень простом уровне:
if(profile[0][1] != profile[1][1]){
//draw a tile which is half sand and half transparent
//Over the current tile -> profile[1][1]
...
}
Который дает этот результат:
Который работает как переход от [0][1]
к [1][1]
, но не от [1][1]
к [2][1]
, где острый край остается. Поэтому я подумал, что в этом случае нужно будет использовать угловую плитку. Я создал два листа спрайтов 3x3, которые, как я думал, будут содержать все возможные комбинации плиток, которые могут понадобиться. Затем я повторил это для всех плиток, которые есть в игре (белые области прозрачны). В итоге получается 16 плиток для каждого типа плиток (центральные плитки на каждом листе спрайтов не используются.)
Идеальный результат
Итак, с этими новыми тайлами и правильным алгоритмом пример раздела будет выглядеть так:
Каждая попытка, которую я сделал, потерпела неудачу, хотя в алгоритме всегда есть какой-то недостаток, и шаблоны оказываются странными. Я не могу понять все случаи правильно, и в целом это кажется плохим способом сделать это.
Решение?
Итак, если бы кто-нибудь мог предложить альтернативное решение относительно того, как я мог бы создать этот эффект, или в каком направлении писать алгоритм профилирования, я был бы очень благодарен!
источник
Ответы:
Основная идея этого алгоритма состоит в том, чтобы использовать шаг предварительной обработки, чтобы найти все ребра, а затем выбрать правильный сглаживающий фрагмент в соответствии с формой ребра.
Первым шагом было бы найти все ребра. В приведенном ниже примере краевые плитки, отмеченные знаком X, представляют собой зеленые плитки с коричневой плиткой в качестве одной или нескольких из восьми соседних плиток. Для разных типов ландшафта это условие может быть преобразовано в плитку, являющуюся краевой плиткой, если у нее есть соседи с меньшим номером местности.
Как только все краевые плитки обнаружены, нужно выбрать правильную сглаживающую плитку для каждой краевой плитки. Вот мое представление ваших сглаживающих плиток.
Обратите внимание, что на самом деле не так много разных типов плиток. Нам нужны восемь внешних плиток от одного из квадратов 3х3, но только четыре угловых квадрата от другого, так как плитки с прямым краем уже найдены в первом квадрате. Это означает, что в общей сложности 12 различных случаев, которые мы должны различать.
Теперь, глядя на одну краевую плитку, мы можем определить направление поворота границы, глядя на ее четыре ближайших соседних плитки. Помечая граничную плитку X так же, как и выше, мы имеем следующие шесть разных случаев.
Эти случаи используются для определения соответствующей плитки сглаживания, и мы можем соответствующим образом нумеровать плитки сглаживания.
Для каждого случая есть выбор a или b. Это зависит от того, на какой стороне трава. Одним из способов определить это может быть отслеживание ориентации границы, но, возможно, самый простой способ сделать это - выбрать одну плитку рядом с краем и посмотреть, какой у нее цвет. Изображение ниже показывает два случая 5a) и 5b), которые можно различить, например, путем проверки цвета верхней правой плитки.
Окончательное перечисление для исходного примера будет выглядеть следующим образом.
И после выбора соответствующей плитки края граница будет выглядеть примерно так.
В качестве последнего замечания я могу сказать, что это будет работать до тех пор, пока граница будет несколько регулярной. Точнее, краевые плитки, которые не имеют ровно двух краевых плиток в качестве своих соседей, должны обрабатываться отдельно. Это будет происходить для краевых плиток на краю карты, у которых будет один соседний край, и для очень узких участков местности, где число соседних краевых плиток может быть три или даже четыре.
источник
Следующий квадрат представляет собой металлическую пластину. В правом верхнем углу есть "тепловая вентиляция". Мы можем видеть, как, когда температура этой точки остается постоянной, металлическая пластина сходится к постоянной температуре в каждой точке, естественно, ближе к вершине:
Задача нахождения температуры в каждой точке может быть решена как «Краевая задача». Однако самый простой способ отвести тепло в каждой точке - смоделировать пластину в виде сетки. Мы знаем точки на сетке при постоянной температуре. Мы устанавливаем температуру всех неизвестных точек равной комнатной температуре (как будто вентиляция только что была включена). Затем мы позволяем теплу распространяться через пластину, пока не достигнем сходимости. Это делается путем итерации: мы перебираем каждую (i, j) точку. Мы устанавливаем точку (i, j) = (точка (i + 1, j) + точка (i-1, j) + точка (i, j + 1) + точка (i, j-1)) / 4 [если точка (i, j) имеет тепловую вентиляцию с постоянной температурой]
Если вы примените это к своей проблеме, это очень похоже, просто средние цвета вместо температур. Вам, вероятно, потребуется около 5 итераций. Я предлагаю использовать сетку 400x400. Thats 400x400x5 = менее 1 миллиона итераций, которые будут быстрыми. Если вы используете только 5 итераций, вам, вероятно, не придется беспокоиться о том, чтобы удерживать какие-либо точки постоянным цветом, поскольку они не будут слишком сильно сдвигаться от своего оригинала (фактически цвет может воздействовать только на точки на расстоянии 5 от цвета). Псевдокод:
источник
Итак, первые мысли о том, что автоматизация идеального решения проблемы требует довольно сложной математической математики. Исходя из того, что вы упоминаете предварительно визуализированные изображения листов, я предполагаю, что полное решение интерполяции здесь не гарантируется.
С другой стороны, как вы сказали, завершение карты вручную приведет к хорошему результату ... но я также предполагаю, что любой ручной процесс исправления сбоев также не возможен.
Вот простой алгоритм, который не дает идеального результата, но он очень полезен, поскольку требует минимальных усилий.
Вместо того, чтобы пытаться смешать КАЖДЫЙ край, (это означает, что вам нужно либо узнать результат смешивания смежных плиток первым - интерполяция, либо вам нужно уточнить всю карту несколько раз и не полагаться на предварительно сгенерированные листы) почему бы не смешать плитки в чередующемся образце шахматной доски?
Т.е. только смешивание плиток помечено в матрице выше?
Предполагая, что единственные допустимые шаги по значению - это по одному, у вас есть только несколько плиток для проектирования ...
Всего будет 16 шаблонов. Если вы воспользуетесь симметрией вращения и отражения, их будет еще меньше.
«A» будет плиткой в стиле [1]. «D» будет диагональ.
По углам плиток будут небольшие разрывы, но они будут незначительными по сравнению с примером, который вы привели.
Если я смогу, я обновлю этот пост с изображениями позже.
источник
Я играл с чем-то похожим на это, это не было закончено по ряду причин; но в основном это будет матрица из 0 и 1, 0 - это земля, а 1 - стена для приложения-генератора лабиринта во Flash. Поскольку AS3 похож на JavaScript, переписать в JS не составит труда.
В основном это проверяет каждую плитку вокруг нее, идущую слева направо, сверху вниз и предполагает, что края плитки всегда равны 1. Я также взял на себя смелость экспортировать изображения в файл для использования в качестве ключа:
Это неполный и, вероятно, хакерский способ добиться этого, но я подумал, что это может быть полезным.
Изменить: скриншот результата этого кода.
источник
Я бы предложил несколько вещей:
не имеет значения, что такое «центральная» плитка, верно? это может быть 2, но если бы все остальные были 1, это показало бы 1?
имеет значение только то, что углы, когда есть разница в непосредственных соседях сверху или сбоку. Если все непосредственные соседи равны 1, а угол равен 2, будет показано 1.
Я бы, вероятно, рассчитал все возможные комбинации соседей, создав массив из 8 индексов, где первые четыре указывают значения верхних / нижних соседей, а вторая - диагонали:
ребра [N] [E] [S] [W] [NE] [SE] [SW] [NW] = любое смещение в спрайте
поэтому в вашем случае [2] [2] [1] [1] [2] [2] [1] [1] = 4 (5-й спрайт).
в этом случае [1] [1] [1] [1] будет 1, [2] [2] [2] [2] будет 2, а остальное должно быть решено. Но поиск конкретной плитки будет тривиальным.
источник