генерация мира
Нужен функционал у предмета как у око эндера, только чтобы он искал мою структуру. Посмотрел код предмета, оно ищет только структуры, которые наследуют MapGenStructure, в этом классе есть метод getStructureName, через который и ищется структура. В майнкрафте такие структуры регистрируются только.
- DakotaBearr
- Тема
- 28 Апр 2023
- генератор структур генерациягенерациямирагенерация сооружения многоблочная структура структура
- Ответы: 1
- Форум: Вопросы
Как сгенерировать блок на определённых координатах?
Здравия желаю Можете, пожалуйста, рассказать, как сгенерировать блок на определённых координатах в мире? К сожалению, я не нашёл достаточно подробных туториалов (потому что искать не умею, но это уже другая история) Изначально пробовал через setBlockState, но так не получится сгенерировать.
Скрыть контент игры
Мне необходимо предотвратить спаун некоторых мобов, например: зомби, криперы, скелеты, пауки, а также убрать рецепты некоторых предметов, кирки, лопаты и все остальное. Реализовать нужно все это модом. Я читал, что нужно использовать EntityJoinWorldEvent (документация Forge) для замены.
- GrolliCraft
- Тема
- 21 Июл 2022
- генерациямира структуры
- Ответы: 18
- Форум: Вопросы
Удалить генерацию руд
Как удалить генерацию всех руд в мире? Нужно ивент какой-то отменить или как?
Генератор ландшафта
Добрый день. Такой вопросик. Есть ли какой-нибудь генератор генерации ландшафта :), в котором с помощью настроек можно создать свою собственную для измерения. Или, написав какой-то код, сразу видеть результат?
- liapel
- Тема
- 14 Авг 2021
- генерациямира ландшафт
- Ответы: 1
- Форум: Вопросы
Принцип работы генератора чанков. Начало
Всем привет! Данную статью я хотел написать уже давно, и вот наконец желание оказалось сильнее отсутствия времени 🙂 В ней я постараюсь простыми словами описать тот сложный процесс, который в майне зовётся генерацией. Слова буду подкреплять схемами и скриншотами, так как с ними материал будет.
- Liahim
- Ресурс
- 8 Июл 2021
- генерациямира чанк
- Категория: Туториалы
Создание собственного измерения
Да-да. Знаю эта тема уже поднималась: https://forum.mcmodding.ru/threads/sozdanie-sobstvennogo-izmerenie.28945/ но тут я ничего не нашёл. Может кто-то снизойдет и объяснит мне, как это работает.
- tree
- Тема
- 14 Июн 2021
- генерациямира своё измерение
- Ответы: 11
- Форум: Вопросы
Генерация мира
Здрасте, на днях понадобилось ограничить генерацию мира до определенных координат. Может знает кто, как это можно сделать?
- PeTcHeNyShOhKa
- Тема
- 16 Май 2021
- генерациямира структура
- Ответы: 2
- Форум: Вопросы
Замена биома своим собственным
Здравствуйте! Можно ли как нибудь заменить, например тёмный лес, на свой собственный биом? Мне не нравится именно тёмный лес, и хотелось бы вставить на его место, например, Extreme Hills из Беты 1.8. (В релизном 1.7.2 горы сделали другие, и хотелось бы вернуть старые). Может, можно просто.
Проблема с генератором мира
Дело дошло до ген. Мира и всё вроде хорошо но есть одно НО. когда делаю новый мир. Майн крашится
Произвольный генератор мира
Есть один важный вопрос. Сделал я свой chunkProvider, так же как и свой генератор мира. Все бы ничего, все работает как надо, структуры генерируются. И тут возникает один вопрос. По сути структурам все равно где генерироваться, если даже в чанке не будет блоков вообще, то там вполне может.
- Asd1995sse
- Тема
- 13 Мар 2020
- генератор структур генерациямира
- Ответы: 4
- Форум: Вопросы
изменение генерации мира
как изменить генерацию мира так чтобы заместо камня спавнился мой камень , железо и т.д или отключить
Процедурная генерация в играх: что это такое и зачем она нужна
Раньше произведения искусства создавались вручную. В XXI веке для этого есть алгоритмы.
Артём Фролов
Игровой энтузиаст. Любит видеоигры, настолки и рассказывать всем, как они устроены.
Процедурная генерация — незаменимый инструмент в геймдизайне. С её помощью создают огромные виртуальные миры в Minecraft и No Man’s Sky, а также — отдельных персонажей, уровни, сюжеты и даже игровые правила. Иногда кажется, что в будущем алгоритмы будут делать всю работу за геймдизайнеров — но всё не так просто.
Как работает процедурная генерация
Чтобы объяснить принцип её работы, достаточно колоды карт таро. Возьмите в руки карты, перетасуйте их, а затем разложите на столе согласно правилам — вот вы и получили предсказание, сгенерированное процедурно.
Карты в этом случае служат тайлами — фрагментами одинакового размера, из которых складывается общая картина. Правила же гадания выполняют функцию алгоритма, который эту картину собирает.
Тайлы часто используются в стратегиях: например, в играх серии Civilization карты генерируются из шестиугольников, имитирующих разные типы ландшафта. Игроки при этом могут менять параметры создаваемого мира: его размер, рельеф, количество ресурсов и так далее. Иначе говоря, они «настраивают» формулу процедурной генерации.
Но как сделать, чтобы эта формула каждый раз выдавала новый результат? Здесь на помощь приходит зерно — код, созданный генератором случайных чисел. Этот код «скармливают» алгоритму, который затем выдаёт в качестве результата карту, созданную процедурно.
Тайлы не единственный метод процедурной генерации. Авторы Minecraft и Terraria, например, используют шум Перлина — алгоритм градиентного шума. Изначально его придумали для создания достоверных текстур поверхности. Со временем, однако, дизайнеры нашли ему ещё одно применение — в процедурной генерации ландшафта.
Работает это так: светлые участки шума Перлина считываются как возвышенности, а тёмные — как низины. На их основе алгоритм создаёт приблизительный рельеф будущей карты. Процесс повторяется несколько раз, пока не получается достаточно достоверный ландшафт с горами, долинами и ущельями. После этого мир наполняют флорой, фауной, монстрами, деревнями и так далее.
Генерация миров при этом подчиняется множеству заранее прописанных правил, чтобы избежать досадных нестыковок вроде хвойных лесов в пустыне. Поэтому в Minecraft хвойные леса растут в тундре, а в пустыне можно найти лишь сахарный тростник.
Процедурная генерация как игровая философия
Как правило, мы ассоциируем процедурную генерацию с конкретными жанрами. Например, с «рогаликами» (англ. roguelike), где геймплей строится на том, что вы будете пробовать, умирать и начинать заново. Следовательно, уровни всякий раз тоже генерируются заново — чтобы не надоесть игроку и не дать ему пройти игру на мышечной памяти.
Жанр развился из данжен-кроулеров (англ. dungeon crawler) — игр про блуждания в подземельях. У них уже были все приметы roguelike — скажем, пошаговый геймплей (то есть одна команда соответствует одному действию и ходу) и «перманентная смерть». Классические «рогалики» вроде Rogue 1980-го (её именем жанр и назвали) или NetHack 1987-го только добавили к нему процедурную генерацию подземелий, чтобы повысить реиграбельность.
Со временем требования к жанру смягчились и часть некогда важнейших его элементов перестала быть обязательной — но только не случайно созданные уровни.
Сегодня roguelike запросто комбинируют с другими жанрами: с платформерами — в Spelunky и Rogue Legacy, с RPG — в Diablo, со стратегиями — в FTL: Faster Than Light. Или просто создают привычные, казалось бы, «рогалики» про условные подземелья, но с динамичным геймплеем — как в The Binding of Isaac и Hades. И во всех этих играх в том или ином виде применяется процедурная генерация — уровней, экипировки, оружия, врагов и так далее.
Или вот «песочницы», где процедурная генерация служит всему подряд, вплоть до нарратива.
Так, Dwarf Fortress перед началом каждой новой игры генерирует не только мир, но и сотни лет его истории. А RimWorld поручает игроку жизни трёх процедурно созданных астронавтов, чей корабль разбился на планете, также появившейся в ходе процедурной генерации.
Вдобавок игра предлагает на выбор трёх «рассказчиков» — это своего рода «генераторы» истории, каждый со своим стилем повествования. Кассандра строит рассказ по канонам приключенческих повестей, Фиби время от времени даёт время на передышку, а Рэнди кидает игрока в пучины хаоса. Всё для того, чтобы превратить каждое прохождение в уникальный опыт.
Здесь ваши герои могут погибнуть от холода в тундре. Ядерная зима уничтожит весь ваш урожай. Один из колонистов сойдёт с ума и перебьёт остальных. Или это сделают агрессивные аборигены. В RimWorld такие моменты — сплошь и рядом, но воспринимаются не как наказание за ошибки, а как истории, которые вы будете рассказывать друзьям.
No Man’s Sky и вовсе использует процедурное звуковое сопровождение. У игры, конечно, есть альбом с саундтреком, записанный группой 65daysofstatic, и треки из него играют в ключевые моменты сюжетной кампании: например, первая стыковка с космической станцией происходит под крещендо песни «Asimov».
Да, локации вышли однообразными, но преимущества процедурной генерации были слишком очевидны, чтобы ими не воспользовались другие разработчики. Например, авторы The Witcher 3: Wild Hunt, которым требовалось создать мир, в 35 раз превышающий размерами карту из второй части. Сделать это вручную было почти невозможно, поэтому команда художников под руководством Марчина Голлента применила кисти.
Кисти — это инструменты с наборами ассетов, а в случае третьего «Ведьмака» — с типами растительности. С их помощью разработчики создали все биомы игры — от тайги на севере до лиственных рощ на юге.
Вдобавок они научили алгоритм распознавать особенности ландшафта, чтобы регулировать плотность растительности. Например, в долинах, в которые стекает дождевая вода, генератор выращивал куда более густой лес, чем на каменистых горных склонах.
Кисти не просто сэкономили время и ресурсы CD Projekt Red — они помогли сделать мир «Ведьмака» куда более живым и достоверным.
Процедурная генерация бывает полезна даже в тех случаях, когда карта создаётся по мотивам реального места. В Marvel’s Spider-Man события происходят на виртуальной версии острова Манхэттен, 80% которого создали алгоритмы.
Разработчики нанесли на карту только основные улицы, достопримечательности и места сюжетных миссий, после чего система генерации прочертила дополнительные улицы и переулки, расставила вдоль них здания и декорировала их. Кое-что, конечно, пришлось подправить — например, крыши, где игрок проводит большую часть времени.
Алгоритм действует и в самой игре: он генерирует уличный трафик, пешеходов и случайные события вроде погонь и столкновений с бандитами. Во время драки он следит, чтобы у Человека-Паука всегда были под рукой предметы, которыми герой швыряется в противников: люки, строительные балки и почтовые ящики.
Можно сказать, система генерации в Marvel’s Spider-Man играет в градостроительный симулятор — с той разницей, что её город — это декорация для истории про знаменитого супергероя.
Алгоритмы в играх, которые создаются «вручную», могут пригодиться не только для работы над локациями. Помните опцию «Создать случайного персонажа» почти в любой RPG? За это тоже отвечает алгоритм процедурной генерации.
Для него есть и более необычные применения. В серии Borderlands геймплей построен вокруг добычи случайно сгенерированных образцов экипировки и оружия. А в серии Watch Dogs одна из самых разрекламированных особенностей — созданные алгоритмом горожане со своими биографиями и перками. Правда, именно Watch Dogs показывает, что происходит, когда процедурная генерация работает не так, как нужно.
И это подводит нас к одному из давних споров…
Процедурная генерация — это хорошо или плохо?
Споры о преимуществах и недостатках процедурной генерации продолжаются столько, сколько существует сам инструмент. И у обеих сторон есть веские аргументы.
За: масштаб. Как отметил Яп ван Мёйден, создатель инструментов для левел-дизайнеров Guerrilla Games, огромный открытый мир Horizon: Zero Dawn был бы невозможен без процедурной генерации. Алгоритм позволил художникам студии не только сократить время на проработку карты, но и быстро редактировать вручную созданные локации.
Космические песочницы No Man’s Sky и Elite: Dangerous и вовсе невозможно представить без этого инструмента. В их вселенных требуются сотни миллиардов лет, чтобы облететь каждую планету, — о том, чтобы создавать их вручную, не может быть и речи.
Против: даже лучшие песочницы вроде Minecraft или той же No Man’s Sky страдают от однообразия. Обе игры предлагают впечатляющие вариативностью биомы, но спустя неделю-другую их контент начинает повторяться.
Авторы No Man’s Sky и сами признали эту проблему. Глава студии Hello Games Шон Мюррей рассказывал: «Это и впрямь так работает: игроки встречают одни и те же местности, биомы и планеты». Разработчики попытались решить эту проблему, но отказаться от процедурной генерации всё же не смогли.
Она, к слову, может испортить и более традиционные игры. Bethesda пыталась заполнить мир The Elder Scrolls 5: Skyrim процедурно созданными квестами, чтобы в неё можно было «играть бесконечно». Результат был предсказуемым: система генерации заполнила игру однообразными заданиями по типу «собери пять цветков» и «убей десять бандитов».
За: экономия памяти. Когда локации создаются вручную, каждый объект на них сохраняется отдельно, тогда как, скажем, процедурно сгенерированная растительность хранится в виде отдельной карты. Это позволяет существенно сэкономить место.
Если же алгоритм создаёт целые миры, объём жёсткого диска и вовсе перестаёт быть проблемой — для их загрузки вам нужно только зерно. Именно поэтому No Man’s Sky «весит» чуть больше 10 ГБ: на жёстком диске игра хранит только ассеты, из которых при каждом запуске алгоритм собирает вселенную на 18 квинтиллионов планет.
Против: ошибки генератора. Пример с Watch Dogs: Legion хорошо показывает, что система генерации требует тонкой настройки. К сожалению, предусмотреть все комбинации почти невозможно — значит, всегда есть шанс допустить оплошность, которая сломает баланс или просто выдаст смешную комбинацию.
За: элемент неожиданности. Процедурная генерация — один из главных способов сделать геймплей непредсказуемым. Без неё поклонники Civilization (или Worms) быстро исчерпали бы запас возможных тактик, а фанаты Hades вызубрили бы наизусть каждый уровень игры.
Против: ошибки геймдизайнера. На канале Noclip есть отличное интервью с создателем Dwarf Fortress, где он рассказывает, как открытие баров в игре привело к массовой смерти кошек от алкогольной интоксикации.
Такие дыры в геймплее встречаются и в «обычных» играх, однако процедурная генерация в несколько раз усложняет процесс их отслеживания. Обратная сторона эффекта неожиданности — ни игрок, ни разработчик в точности не знает, чем обернётся следующий патч.
За: возможности для инди-разработчиков. Процедурная генерация — потрясающий инструмент для инди-студий и геймдизайнеров. На момент выхода No Man’s Sky в студии Hello Games работало всего 15 человек. Позже её коллектив вырос до 26 сотрудников.
Minecraft и вовсе создал один геймдизайнер, который после релиза стал знаменитостью, — Маркус «Нотч» Перссон.
Против: меньше рабочих мест для AAA-разработчиков. Экономия ресурсов также значит, что студиям нужно куда меньше сотрудников. Всего три человека в Guerrilla Games нарисовали 500 типов растений для Horizon: Zero Dawn, а их шаблонами занимался один технический художник.
Впрочем, ключевые локации всё равно создаются вручную, да и сам алгоритм кто-то должен программировать. А это значит, что работа для людей всегда найдётся.
Все эти «против» — лишь одна из причин, по которой алгоритмы до сих пор не заменили всех геймдизайнеров. И ещё одна — тот факт, что процедурная генерация — инструмент для выполнения некоторых, вполне конкретных задач. С её помощью сегодня создают просторные открытые миры и отдельные локации, врагов и оружие для «рогаликов», даже сюжеты. Но уникальный игровой опыт всё ещё «строят» сами разработчики — его рядом случайных цифр задать не получится.
Как происходит генерация мира Minecraft
Задумывались ли вы когда-нибудь, сколько на нашей планете песчинок? По грубым оценкам, более 7 квинтиллионов! Это 7 с 18 нулями. И всё-таки это даже меньше половины количества уникальных миров в Minecraft. Как же Minecraft и другим похожим играм удаётся создавать такие сложные, красивые, однако полностью процедурные миры? В этой статье я расскажу, как игра генерирует свои миры, от самой высокой горы до самой глубокой пещеры.
Часть 1: процедурная генерация
Для многих из вас Minecraft может быть первой (а может быть, и единственной) игрой, в которой миры не творятся вручную дизайнером уровней, а создаются процедурно.
Однако первой игрой с процедурно сгенерированным миром является «Elite», первая версия которой вышла для компьютера BBC Micro в 1984 году. Это прапрадед относительно новой «Elite: Dangerous», выпущенной в 2014 году.
Автоматическая генерация новых миров может казаться привлекательным способом ленивого создания бесконечного контента для игры. Однако на самом деле всё наоборот! Чтобы научить машину тому, как выглядит хороший уровень… нужно быть очень хорошим программистом и дизайнером уровней.
Контент должен быть достаточно разнообразным, чтобы выглядеть свежим, но не настолько разнообразным, чтобы казаться атипичным. И необходимо создавать миры, на которые не просто интересно смотреть, но которые обеспечивают справедливую с точки зрения игрока сложность.
Процедурная генерация контента определённо не для слабых духом. Однако какими бы ни были ваши алгоритмы, все они зависят лишь от одного аспекта: случайности. И Minecraft в этом не исключение: каждый мир начинается с порождающего значения (seed); по сути, это число, используемое для инициализации генерации рельефа и всего, что на нём будет находиться.
Пусть эти алгоритмы и случайны, однако они детерминированы. Это значит, что при наличии одинаковых исходных условий (одинакового seed) они всегда дают одинаковые результаты. И именно благодаря этому каждый мир Minecraft можно воссоздать по его seed. А поскольку сами seed хранятся как 64-битные числа, то существует 18,4 квинтиллиона уникальных значений, которые можно создать.
В No Man’s Sky тоже используются 64-битные seed, и это объясняет, почему в этой игре тоже 18,4 квинтиллиона уникальных планет.
«Rogue» (1980 год)
Но как случайные числа (по сути, получаемые «бросанием кубиков» компьютером) могут создавать миры? Наверно, для объяснения нужно начать с чего-то меньшего, чем Minecraft. Добро пожаловать в «Dungeons of Doom».
Выпущенная в 1980 году игра «Rogue» считается первой графической адвенчурой, она стала главным источником вдохновения для разработчиков тысяч игр в жанре dungeon crawler, выпущенных за последующие десятилетия.
Minecraft тоже позаимствовала многие характеристики, сделавшие Rogue знаменитой, и генерация процедурных подземелий для исследований — лишь одна из них.
Rogue обычно называют первой «графической» адвенчурой, и она определённо была, по крайней мере, одной из первых.
Как же Rogue создавала свои «Dungeons of Doom» (подземелья рока) в 1980 году? Каждый уровень разделялся на сетку 3 на 3, а в каждую ячейку помещалась случайная комната.
Далее алгоритм выбирал комнату для создания игрока и помечал её как «достижимую». Затем он итеративно обходил все остальные комнаты, соединяя их с ранее достигнутым соседом (если это возможно), или переходя к следующей. Затем в последней присоединённой комнате размещалась лестница на следующий уровень.
В Rogue также могли появляться тупики, потайные двери и даже комнаты монстров! И всё это было реализовано примерно в девяти тысячах строках кода и более чем трёхстах функциях! …307, если точнее! Для сравнения: в Minecraft 1.18 насчитывается более 52 тысяч функций, находящихся примерно в 4200 файлах!
Итак, приготовьте свою алмазную броню и зачарованный меч, мы начинаем спускаться в предательские глубины исходного кода Minecraft.
Исходный код Rogue
Оригинальный исходный код «Rogue» можно найти в проекте Decoded: Rogue, где Mai Zure провёл тщательный разбор каждого файла. Основная часть кода была написана до появления стандарта ANSI C, что объясняет присутствие большого количества того, что не стоит считать антипаттернами.
Например, авторы использовали макросы для создания циклов until :
#define until(expr) while(!(expr))
И как будто этого недостаточно, они ещё и заменили ключевые слова C case и default на when и otherwise :
#define when break;case #define otherwise break;default
Недавно я говорил об этом в Twitter, что привело к интересному обсуждению:
Когда вы почувствуете вину из-за написанного вами кода, то просто вспомните, что в исходном коде «Rogue» были макросы для переопределения ключевых слов switch .
#define when break;case
#define otherwise break;default
Кодинг «Rogue» в 1980-х, должно быть, сильно походил на игру в рогалик. pic.twitter.com/HbAJbwqlBP— Alan Zucconi (@AlanZucconi) December 18, 2020
Важно помнить, что несмотря на то, что исходный код по современным стандартам кажется устаревшим и некачественным, он был и остаётся невероятным достижением технических навыков и изобретательности на момент своего написания. Очевидно, что игра не появилась бы на свет, если бы её авторы не мыслили нестандартно.
Исходный код Minecraft
Строго говоря, исходный код Minecraft никогда не публиковался. Однако учитывая, что основная версия игры написана на Java, её достаточно легко декомпилировать. Mojang была толерантна и поддерживала эту практику, поскольку она помогала создать сообщество моддеров.
Если вам любопытно узнать больше об исходном коде Minecraft, то стоит изучить MCP Reborn — Mod Coder Pack, предназначенный для создания модифицированных клиентов и исследования их внутренней работы.
Часть 2: история Minecraft
Как бы ни была сложна эта игра, нельзя отрицать тот факт, что созданная Mojang вселенная построена на идеях, техниках и алгоритмах, первопроходцами в которых были другие игры (и даже фильмы), а некоторые из них выпущены десятки лет назад.
И было неправильным говорить об истории Minecraft без упоминания игры, которая стала источником вдохновения её разработчика: «Infiniminer».
Поначалу кажется, что это игра про добычу полезных ископаемых, в которой две команды соревнуются в сборе наибольшего количества руды, золота и алмазов. Но «Infinimer» был не только про добычу ресурсов, но и про создание; не только своей базы, но и историй.
Легко заметить, что игра стала непосредственным источником вдохновения для разработки Minecraft: блоки, кирка, пещеры и лавовые озёра, золото и алмазы, небо и пустота! Даже TNT! В параллельной Вселенной Minecraft могла бы выглядеть так.
Хотя каждая карта «Infiniminer» далеко не бесконечна, все они и в самом деле генерируется процедурно. Всё начинается с цельного блока земли, в котором отрисовывается множество рудных жил. Каждая начинается в случайной точке, и при каждой итерации жила движется в случайном направлении. Эта техника называется «случайным блужданием» (random walk).
Горы и пещеры создаются при помощи точно такой же методики: первые воздвигаются заменой воздуха землёй, вторые вырезаются заменой земли воздухом. Алмазы случайным образом разбрасываются по нижней части уровня.
Такой подход может показаться простым, может, даже слишком, однако это очень похоже на то, как работала Minecraft в первые девять месяцев своей разработки. В своей самой первой версии, в то время называвшейся «Cave Game», каждый мир состоял всего из 256 блоков в ширину и 64 в высоту.
Чтобы реализовать мечту о безграничном мире Minecraft, потребовалось девять месяцев. И реализована она была при помощи очень простого трюка: каждый раз, когда игрок забирался слишком далеко, создавался новый «фрагмент» мира.
Благодаря этому каждый мир был ограничен ПО: например, на 32-битной системе это примерно расстояние в 4,3 миллиарда блоков от точки создания игрока.
Но постойте, прежде чем вы начнёте паковать рюкзак, знайте, что на самом деле так далеко забраться невозможно! Игроки ограничены площадью 60 000 000 на 60 000 000 блоков. По сравнению с бесконечностью кажется, что это не очень много. Однако это всё равно в семь раз больше, чем поверхность Земли. Примерно в половину размера Нептуна!
Земля | Minecraft | Нептун | |
---|---|---|---|
Радиус | 6371 км 2 | 16925 км 2 | 24622 км 2 |
Площадь поверхности | 510064 км 2 | 3600000000 км 2 | 7618000000 км 2 |
Сторона квадрата | 22584 км | 60000 км | 87281 км |
Но даже при этом «больше» не всегда означает «лучше». Ни одна версия Minecraft не даёт игрокам никакой новой геймплейной механики в масштабе больше 25000 блоков. Хотя вблизи мир выглядит богатым и разнообразным, но чем дальше мы отходим, тем сильнее начинает проявляться паттерн. Рано или поздно каждый достаточно большой фрагмент мира будет неотличим от любого другого. В таком масштабе мир Minecraft изотропен, почти как наша Вселенная при максимальном масштабе. Это даёт нам понимание об «истинном» масштабе, в котором в неё нужно играть. И, следовательно, о масштабе, в котором должна по-настоящему работать генерация мира.
2048 блоков
32768 блоков
131072 блока
524288 блоков
2097152 блока
Как генерировать карты биомов?
Minecraft позволяет игрокам рендерить карты мира при помощи стола картографа. Однако она может иметь ограниченное разрешение. Если вы хотите генерировать крупные карты биомов, то лучше всего использовать одну из множества утилит, созданных сообществом моддеров. Две лучшие Java-библиотеки — это BiomeUtils автора KaptainWutax и SeedFinding/mc_biome_java автора hube12. Для более новых версий Minecraft ещё одна библиотека на C — это Cubitect/cubiomes.
Это инструменты, которые можно использовать для сэмплирования биома любого мира в любой точке. Именно так сгенерированы карты из этой статьи.
Теперь вы видите, что все современные карты Minecraft выглядят «пятнистыми»: это вызвано тем, что каждый цвет представляет отдельный «биом»: область со своими географическими особенностями: растительностью, животными, зданиями и природными условиями.
Спустя девять месяцев после обновления, добавившего «бесконечность», в версии Alpha 1.2.0, больше известной как «Halloween Update», появилось десять таких биомов.
Игра определяла, к какому биому принадлежит конкретная часть мира, довольно простым образом: при помощи так называемых «карт шума». Если вкратце, это изображения, пиксели которых созданы при помощи случайных чисел. На основании исходных параметров и конфигурации их можно использовать для генерации множества различных паттернов.
В ранних версиях Minecraft использовались три такие карты шума. Одна — для определения высоты рельефа, две другие — для температуры и осадков.
И именно сочетание последних двух определяло биом области.
Высокая температура и низкая влажность? Пустынный биом!
Низкая температура и низкая влажность? Биом тундры!
Это сработало, потому что карты температуры и осадков были достаточно плавными, поэтому между биомами присутствовали переходы. Это значило, что редко можно было встретить лес по соседству, допустим, с саванной.
Так как биомы не зависели от рельефа, они могли располагаться на любой высоте, что создавало довольно необычные ландшафты.
Существенно переделали эту систему в Beta 1.8: «Adventure Update».
Во-первых, разработчики избавились от Далёких земель. Они обозначали своего рода точку невозврата, после которой генерация мира переставала работать правильно. Они обнаруживались на расстоянии примерно 12 миллионов блоков в любом направлении от точки создания игрока.
Однако избавление от Далёких земель стало лишь побочным эффектом более глубоких изменений. В «Adventure Update» появился совершенно новый генератор рельефа!
Опытные игроки помнят, что в ту эпоху миры имели очень отчётливый стиль. Они были довольно «континентальными»: большие острова, разделённые ещё более обширным океаном.
Всё полностью изменилось в Minecraft 1.7.2, больше известной как «The Update that Changed the World». И это обновление действительно изменило довольно многое! Например, сильно уменьшился размер океанов.
За три года Mojang существенно изменила способ генерации миров. Причём дважды! И это достаточно сильно повлияло на все старые серверы, например, на знаменитый 2b2t – старейший анархический сервер Minecraft. FitMC записал очень интересное видео, демонстрирующее, как такое простое изменение, вроде апгрейда на новую версию, навсегда изменило и так уже неспокойную ситуацию на 2b2t.
Несмотря на некоторые другие изменения в последующих обновлениях, генератор миров, появившийся в Minecraft 1.7.2, использовался практически 10 лет.
И хотя в Minecraft 1.18 кое-что изменилось, миры, которые вы годами исследовали, строили, любили и теряли… были созданы одним и тем же алгоритмом.
И, думаю, вы пришли сюда затем, чтобы узнать, как же он работает на самом деле.
Итак, Minecraft использует конгруэнтные генераторы для создания порождающих значений карт шума Перлина, которые используются как октавы для карт шума фрактального броуновского движения, которые затем обрабатываются несколькими слоями операторов наподобие клеточных автоматов для задания биомов, которые далее модулируют амплитуду карты фрактальной плотности, управляющей высотой рельефа.
Хм, наверно, это не самый эффективный способ объяснения работы алгоритма.
Может быть, стоит показать на примерах?
Часть 3: генерация мира
Всё начинается с так называемой «карты биомов», используемой в качестве шаблона, определяющего, какой тип биома должен находиться в каждой области мира. Равнины, пустыни, горы и океаны — всё это примеры возможных биомов, и сегодня в одном только Верхнем мире их насчитывается более шестидесяти.
Во второй фазе генерации мира происходит работа с рельефом, она разбита на три этапа.
На первом создаётся базовый контур при помощи карты биомов, определяющей высоту, которую может иметь каждая область. В результате получается сплошной бесплодный ландшафт, полностью состоящий из камня, на котором каждый пустой блок ниже превращается в воду.
На последующем этапе все каменные блоки на поверхности заменяются типом, соответствующим их биому. Травой в случае равнин, песком для пустынь, гравием для океанов, и так далее. Также на этом этапе генерируется слой коренной породы. Любопытно, что в Java Edition её паттерн не зависит от seed мира и одинаков для каждого мира Minecraft.
На третьем этапе из камня вырезаются пещеры и ущелья.
Третья фаза заполняет мир оставшимися элементами. Сначала размещаются такие постройки, как деревни, крепости и океанические монументы, затем идут декоративные элементы наподобие деревьев и травы. Также в этой фазе в мир добавляются рудные жилы, и этот процесс схож с используемым в «Infiniminer».
Давайте подробнее рассмотрим, как работает каждая фаза…
Карта биомов
Генерация карты биомов — самая критически важная фаза, потому что она служит чертежом для создания всего остального мира.
Карта создаётся последовательностью довольно простых операций, называемых «слоями», наложенными друг поверх друга. Каждый слой получает карту биомов с предыдущего слоя, добавляет деталей и передаёт её следующему.
Миры Minecraft создаются при помощи не одного, а целых четырёх наборов слоёв.
Основной отвечает за сушу, а два других поменьше используются для отрисовки рек и придания температур океану. Дополнительный набор применяется для добавления нюансов холмам и рекам.
Всё начинается с карты шума (случайно сгенерированного изображения), на которой присутствуют только два цвета, обозначающих сушу и океан в пропорции 1 к 10. Процесс схож с бросками кубика D10 для каждого пикселя: если выпадает 1, пиксель становится сушей, в противном случае он превращается в океан.
Разумеется, у Minecraft нет кубика D10, однако она может «бросать» случайные числа при помощи так называемого квадратичного конгруэнтного генератора.
Внутри исходного кода это называется Island Layer, потому что каждый отдельный пиксель этой карты шума будет шаблоном, из которого возникают континенты. На самом деле, каждый пиксель соответствует 4096 игровым блокам.
Чем глубже мы опускаемся по слоям биомов, тем детализированней становится карта. Это возможно благодаря слоям масштабирования (zoom), которые в два раза увеличивают разрешение, с которым будут работать последующие слои.
Например, если пиксель из Island layer соответствует 4096 блокам, то каждый добавленный после масштабирования пиксель будет иметь в игре размер 2048 блоков.
Слои Zoom в Minecraft имеют ещё одну важную задачу: добавление разнообразия. Они не масштабируют карты идеально точно, а иногда вносят небольшие изменения. Они закодированы работать как старый фотокопировальный аппарат: добавляют случайные погрешности и размазывают края идеально квадратных островов.
Следующий слой в генерации биомов предназначен для расширения уже имеющихся островов, создания более связанного мира.
Каждая часть суши имеет вероятность расширения в углы мелководья по соседству, но также может в процессе подвергнуться эрозии.
Если выполнять этот слой снова и снова, то мы увидим, что он не всегда обеспечивает одинаковый результат. Даже слои добавляют случайности!
Поэтому чтобы лучше понять, как они работают, можно представить их в виде стохастических клеточных автоматов. Иными словами, это простые правила, изменяющие пиксель на основании цвета пикселей по соседству. Под стохастичностью подразумевается, что на некоторые из этих правил может влиять случайность.
Клеточные автоматы выглядят обманчиво простыми, однако скрывают в себе бесконечную вселенную сложности. И они являются одним из самых популярных инструментов в процедурной генерации для видеоигр. На моём YouTube-канале есть целая посвящённая им документалка.
Основная часть формы суши создаётся попеременным использованием слоёв AddIsland и Zoom. Это позволяет создавать в мире уникальные элементы в различных разрешениях.
Области океанов
Форма океана в основном задаётся двумя слоями.
Первый был добавлен в «Adventure Update», чтобы сделать мир менее «континентальным» и более «взаимосвязанным». В коде Minecraft это в буквальном смысле называется Remove Too Much Ocean («убираем слишком большое количество океана»).
Все области океана, окружённые океаном, имеют вероятность 50% превращения в сушу.
Это не только создаёт более фрагментированные побережья, но и изменяет соотношение суши к воде с 27% до более чем 50%.
Следующий слой из основного набора помечает все области океана, окружённые другим океаном, как «глубокие». Позже это приведёт к созданию биомов мелководья и глубоководья.
Температуры и биомы
Ранее мы упоминали только два элемента: сушу и океан. Прелюдией к созданию биомов является последовательность слоёв климата, отвечающих за определение температуры каждой области: Warm (тёплый), Temperate (умеренный), Cold (холодный) или Freezing (морозный). В дальнейшем эта информация будет определять, в какие биомы могут превращаться эти области.
Сначала каждой точке суши случайно назначается температура: Warm (тёплая), Cold (холодная) или Freezing (морозная) в пропорциях 4, 1 и 1.
При таком случайном распределении рядом с заснеженной тундрой вполне может возникнуть пустыня. Чтобы избежать этого, в следующих двух слоях выполняется смешивание температуры каждой области, что обеспечивает более плавные переходы между ними.
Любая тёплая суша по соседству с холодной или морозной превратится в умеренную. А морозная суша рядом с тёплой или умеренной превратится в холодную.
В конечном итоге эти температуры являются основным фактором определения того, каким биомом станет конкретный фрагмент суши. Например, тёплые области имеют вероятность 50% превращения в пустыню, 33% в саванну, а оставшиеся 17% — в равнины.
Аналогичным образом умеренные, холодные и морозные области имеют определённые вероятности превращения в умеренный, холодный и морозный биомы (леса, тайгу и ледяные равнины).
Варианты биомов
На этом этапе ландшафт уже выглядит знакомым, но ему недостаёт вариативности в отдельных биомах. Чтобы исправить это, в данном слое имеется небольшая вероятность превращения биома в его «холмистый» вариант. Например, он может превратить пустыню в пустынные холмы, лес в лесистые холмы, а саванну в плато.
Этот слой работает и с областями океана, он может превращать глубокие океаны в равнины или леса. Это разбавляет океан множеством крошечных островов.
Выбор изменяемых областей зависит от дополнительной карты шума, которая генерируется отдельным набором слоёв. Когда цвет каждого пикселя выбирается случайным образом и независимо от остальных (как в данном случае), это называется «белым шумом». Примерно такое распределение мы получаем, когда смотрим на экран старого телевизора, не получающего никакого сигнала.
Обычно каждый слой работает с картой локально, игнорируя общую картину. А при наличии такого количества шагов сложно гарантировать гармоничное смешение между биомами.
Чтобы избежать проблем, ещё два слоя обеспечивают наличие плавного перехода между различными типами климата и наличие областей с экстремальными температурами.
Второй слой (Shore) также добавляет пляжи, на которых суша встречается с мелководьем океана.
Редкие биомы
Особого упоминания заслуживают редкие биомы, поскольку их генерация выполняется немного иначе. Кроме назначения температур слой климата имеет вероятность 1/13 пометить область как «особую».
Когда настаёт время назначения биомов в зависимости от температуры, особые области обрабатываются иначе. Тёплые, умеренные и холодные климатические области могут превратиться в собственные особые варианты: бесплодные плато, джунгли и многолетнюю тайгу.
Другая ситуация возникает с более нишевыми биомами, например, с бамбуковыми джунглями и подсолнуховыми равнинами: смысл в том, что они являются не отдельными областями, а небольшими участками крупных областей.
Два дополнительных слоя отвечают за превращение одних из десяти джунглей в бамбуковые джунгли, а одних из 57 равнин — в подсолнуховые равнины.
Легендарные грибные острова создаются схожим образом. Каждый блок океана, окружённый водой, имеет вероятность 1/100 превращения в грибное поле. Отвечающий за это слой находится довольно высоко, поэтому грибные острова обычно довольно большие и однородные.
Это один из редчайших биомов в Minecraft, единственный, где естественным образом не создаются враждебные мобы.
Слои создания рек
Основной набор слоёв в основном занимается сушей и не делает ничего для создания рек. Они создаются в отдельном наборе слоёв, который работает с той же картой шума, что используется при создании холмов.
После многократного масштабирования карта шума выглядит довольно неоднородно. Слой рек работает как своего рода алгоритм обнаружения краёв, создавая потенциальные русла рек вдоль швов разнородных участков.
Затем они сглаживаются фильтром низких частот, чтобы устранить любые зазоры или грубые края, и передаются в основной набор слоёв через River Mixer Layer.
Этот процесс вырезает реку в суше, за исключением биомов заснеженной тундры, в которых вместо этого создаются замёрзшие реки, и грибных полей, в которых, похоже, вообще нет рек.
Набор слоёв температуры океана
Последний элемент, задействованный в генерации биомов — это набор слоёв температуры океана. Он добавляет вариативности океану, который за исключением мелководья и глубоководья не имеет других отличительных черт.
Этот набор слоёв при помощи шума Перлина создаёт собственную карту температур. Это очень популярный алгоритм для создания процедурных карт шума, который был разработан в 1982 году, но не для игры, а для фильма «Трон».
Если создать карту белого шума, бросая кубик для каждого пикселя, как это происходило в первом слое, то в целом результат будет некрасиво хаотичным, потому что соседние пиксели, скорее всего, будут иметь очень отличающиеся значения. Шум Перлина создаёт очень красивые и плавные изображения.
Он генерирует случайные значения в сетке, по размерам гораздо больше, чем нужное нам готовое изображение. Все промежуточные точки плавно интерполируются между этими случайными значениями, что обеспечивает гораздо более гладкий результат. В шуме Перлина есть гораздо больше элементов, но углубляться в его изучение мы не будем.
Существуют ли альтернативы шуму Перлина?
С момента публикации статьи о шуме Перлина в 1985 году он стал очень популярен во всех медиа, где в той или иной форме присутствует процедурная генерация. Он настолько известен, что в большинстве движков имеется собственная реализация шума Перлина, например, Mathf.PerlinNoise движка Unity (документация) или Noise Texture Node в Blender.
Из-за его доступности и удобства управления иногда на шум Перлина возлагают слишком большие надежды. Поэтому многие разработчики создают свои миры и уровни на основе шума Перлина. Хотя в этом нет ничего плохого, карты шума Перлина легко распознаются намётанным глазом, что разбивает иллюзию реалистичного рельефа, когда проявляются его типичные артефакты. Характерной особенностью карт шума Перлина является то, что во всех углах ячейки их значение равно нулю, как показано на рисунке ниже.
Из-за этого созданные при помощи шума Перлина ландшафты обычно бывают очень «квадратными» и в них часто присутствуют выровненные по сетке элементы, раскрывающие происхождение шума, использованного при их создании.
Некоторые разработчики предупреждают, что не стоит во всём полагаться на шум Перлина как на первый, а иногда и единственный тип шума для творчества. Если вы хотите узнать об интересных альтернативах, не имеющих недостатков шума Перлина, то крайне рекомендую прочитать статью The Perlin Problem: Moving Past Square Noise.
Например, симплексный шум (наследник шума Перлина) вычисляется в сетке треугольников, благодаря чему карты получаются гораздо менее «квадратными». Симплексный шум был запатентован, но срок действия патента истёк в январе 2022 года. Кроме того, существует множество оперсорсных реализаций, например, OpenSimplex автора K.jpg.
После завершения генерации карта увеличивается в масштабе и вливается в полный набор слоёв при помощи OceanMixer Layer. Это наконец создаёт биомы в областях океана, которые могут быть тёплыми, тепловатыми, холодными и замёрзшими.
Самый последний этап — увеличение масштаба карты ещё два раза. Это выполняется не традиционными слоями Zoom, которые мы видели раньше, а при помощи другой техники, которая ещё сильнее разрушает края между разными биомами.
После этого у нас на руках остаётся готовая карта биомов, в которой каждый пиксель соответствует реальному блоку игры.
И мы готовы двигаться к следующей фазе!
Высота рельефа
Во второй фазе, разбитой на три этапа, генерация мира занимается рельефом.
На третьем этапе из камня в буквальном смысле вырезаются пещеры и ущелья. Эта операция выполняется усложнённым вариантом случайного блуждания, называемого «червями Перлина». Но по своей сути смысл такой же: мы плавно перемещаем сферу в случайных направлениях, вырезая по её пути длинные туннели.
Первый из трёх этапов генерации рельефа Minecraft определённо требует подробного объяснения.
Minecraft создаёт сложный и интересный рельеф при помощи техники под названием «фрактальный шум броуновского движения»: это ещё одно название карты шума.
Фрактальный шум создаётся сложением нескольких карт шума Перлина, сэмплируемых с разным масштабом. Каждая новая (называемая октавой) имеет в два раза большее разрешение по сравнению с предыдущей, но её вклад также снижается вдвое.
Фрактальный шум известен тем, что создаёт правдоподобно выглядящие рельефы. И он работает, потому что добавляет разную степень детализации в разных масштабах. Именно это мы и наблюдаем в реальных рельефах.
Minecraft запросто могла бы сэмплировать фрактальную карту в каждой координате , чтобы получить высоты рельефа. Однако алгоритмы игры работают иначе!
Так как же Minecraft получает высоту рельефа? Она начинает с самой вершины мира, в координате , и начинает двигаться вниз, вычисляя значение фрактального шума для каждой конкретной координаты вдоль этого виртуального столбца. Первая координата , для которой фрактальный шум равен или больше нуля, становится окончательной высотой рельефа в координате .
В ранних девлогах объяснялось, зачем нужен этот процесс: мы должны интерпретировать «значение шума как „плотность“ — всё меньше нуля будет считаться воздухом, а всё, что больше или равно нулю, будет землёй».
В том же самом посте также говорится о том, насколько вычислительно затратен этот процесс. Поэтому ради оптимизации эту карту фрактального шума сэмплируют с меньшим разрешением: мир разделён на «ячейки» размером 4x8x4 блоков каждая.
Если точнее, в Minecraft не используется единая карта фрактального шума: на самом деле их три! Причина этого проста: эти карты замечательны, но довольно однородны. Благодаря использованию двух карт, инициализированных с разными параметрами и смешанными согласно третьей карте шума, Minecraft позволяет добавлять ещё более интересные и естественно выглядящие вариации рельефа.
Но и это ещё не всё! В ранних версиях Minecraft биомы и карта высот рельефа не зависели друг от друга. Однако начиная с Beta 1.8 и далее карта биома напрямую влияет на генерацию рельефа, модулируя максимальную высоту каждого биома.
Это выполняется при помощи двух параметров: «глубины» и «масштаба». Эти значения зависят от типа биома, они представляют его среднюю высоту и степень отклонения от неё. Благодаря тому, что биом напрямую связан с высотой рельефа, в конечном итоге создаётся гораздо более естественный ландшафт, в котором не возникают странные элементы наподобие пляжа в горах, например.
Строго говоря, в генерации рельефа задействовано ещё как минимум две карты шума. Карта «шума глубин» добавляет вариативности для компенсации того, что интерполяция между ячейками сглаживает мелкие детали. А карта «шума поверхности» определяет, сколько блоков камня нужно заменить стандартным блоком в каждом биоме.
И, вероятно, существует ещё с десяток других карт, используемых в мелких деталях наподобие распределения цветов. Но в этой статье мы в такие дебри залезать не будем!
Элементы мира
После создания карты биомов и высот рельефа мы получаем практически готовый ландшафт, однако на нём отсутствует растительность, животные, здания и даже руда.
Мир Minecraft не был бы полным без десятков различных элементов: травы, цветов, деревьев, грибов, шахт, подземелий, сломанных порталов, деревень и аванпостов, рудных жил, капельника и жеодов аметиста, окаменелостей, океанических монументов, хижин ведьм, храмов в джунглях и пустынях, айсбергов, иглу, обломков кораблей, океанских руин и поместий.
Так как каждый элемент создаётся по собственным правилам, в этой статье невозможно будет рассказать обо всех. Поэтому давайте сосредоточимся только на зданиях, которые необходимы для победы в игре: на крепостях.
Эти подземелья — единственный способ попасть в измерение Край. В каждом мире есть лишь 128 крепостей, созданных внутри восьми концентрических колец, последнее из которых имеет радиус 22-24 тысяч блоков от начальной точки.
В каждом кольце крепости генерируются приблизительно под прямыми углами от центра.
Хотя сами крепости размещаются в мире с другими зданиями на этапе заполнения, их позиция вычисляется даже до генерации рельефа. В отличие от других элементов, крепости являются ключом к завершению игры, поэтому это критический этап генерации мира, которому отдаётся больший приоритет, чем украшениям или другими избыточными элементами.
Поздравляю: теперь вы специалист по процедурной генерации!
Ну а теперь давайте возьмём все полученные знания и выбросим их в лаву.
Часть 4: Minecraft 1.18+
Потому что с «Caves & Cliffs Update» в Minecraft 1.18 появился совершенно новый генератор рельефа. Раньше ландшафт имел высоту лишь 128 блоков, а теперь растянулся вверх на 320 блоков. Из-за такого увеличения вертикального пространства неудивительно, что одним из крупнейших изменений стали горы, которые теперь гораздо выше и пропорциональнее к остальной части мира.
И чтобы избежать катастроф при игре в старые миры, в Minecraft 1.18 выполняется продуманное смешение. Это позволяет новым фрагментам бесшовно интегрироваться в окружающий ландшафт и биомы.
Но основная разница заключается в том, что для генерации карт биомов Minecraft 1.18 использует совершенно новый алгоритм. И это чётко можно увидеть при сравнении их со старыми версиями, созданными при помощи описанного выше набора слоёв. Ниже показано, как существенно изменился мир Minecraft между версиями 1.16 и 1.18:
Minecraft 1.16
Minecraft 1.18
Ещё более важно то, что теперь биомы в какой-то степени стали трёхмерными! Благодаря этому у подземных пещер могут быть собственные биомы, как это и происходит в долгожданных пышных пещерах.
И это тоже играет важную роль в новой системе пещер. Кроме вырезания пещер при помощи червей Перлина Minecraft 1.18 использует три новых типа пещер: «сырные» пещеры, «спагетти»-пещеры и «макаронные» пещеры. Да, здесь нет никакой ошибки.
Все они выполняют генерацию одинаково: применяют пороговое значение к 3D-карте шума Перлина для выбора подземных областей, которые должны быть вырезаны из камня. И просто создавая разные порождающие параметры для этих карт шума, они могут генерировать большие пещеры, длинные туннели и мелкую сеть взаимосвязанных проходов. Сыр, спагетти и макароны.
Также появилась новая функция, создающая внутри пещер столбы.
Кроме того, обновление привязывает генерацию пещер к новому распределению руды, которое должно стимулировать к исследованиям.
Как же работает Minecraft 1.18? Это сложный вопрос. К тому же, учитывая новизну этой версии, может быть слишком поспешно вдаваться в подробности системы, в которую по-прежнему вносят улучшения и исправления.
Но могу сказать, что биомы и рельеф теперь связаны ещё теснее.
Если раньше ландшафт изменялся в зависимости от биома, теперь они оба зависят от 3D-карты климата.
Каждая четверть фрагмента — кусок размером 4x4x4 блока — получает из карты шума пять климатических параметров: температуру, влажность, «континентность», эрозию и «странность».
Первые два очевидны, «континентность» определяет, насколько далеко область находится от побережья, а от эрозии зависит, насколько плоским или гористым должен быть рельеф. «Странность» определяет варианты биомов.
Каждый биом определяется по его собственной идеальной температуре, влажности, «континентальности», эрозии и «странности». Каждой четверти фрагмента присваивается биом, наиболее точно соответствующий этим пяти параметрам.
Например, стандартная пустыня будет иметь высокую температуру, «континентальность» и эрозию, при этом низкую влажность и «странность». Все области, соответствующие этим параметрам, превратятся в пустыни.
Очень любопытно, что эта новая система работает схоже с Alpha 1.2.0, но с пятью параметрами (шестью, если учитывать ещё и глубину) вместо двух.
Очевидно, существует ещё много особенностей, делающих Minecraft такой очаровательной игрой. И почти каждая из них имеет собственную карту шума. В новой версии только для одного рельефа используется больше пятидесяти карт.
Часть 5: заключение
Ни одна статья о генерации мира не была бы полной без упоминания потрясающего сообщества, активно проводящего исследования Minecraft.
Тысячи людей использовали платформы для распределённых вычислений в поисках порождающего значения потерянного мира по одному изображению, а одна команда нашла высочайший кактус в игре — 23 блока!
Как найти высочайший кактус?
Если вы знакомы с пустынным биомом, то, вероятно, знаете, что кактусы растут высотой до трёх блоков. Однако два (или больше!) кактусов можно поставить один на другой, чтобы создать более высокий. Это относительно редкое событие, но оно позволяет превысить ограничение в три блока.
До июня 2022 года рекорд высочайшего кактуса в Minecraft 1.14 составлял 23 блока. Его можно найти в мире с порождающим значением 184693195438010998 в следующих координатах XYZ: 16274576 64 10230656 .
Непрекращающийся поиск самого высокого кактуса требует невероятного количества находчивости, навыков и вычислительной мощи. Подробнее об этом невероятном исследовании можно прочитать здесь.
И как не упомянуть ежегодное соревнование The Generative Design in Minecraft Competition, участники которого стремятся расширить границы возможного для процедурной генерации.
В конечном итоге, именно это делает Minecraft настолько привлекательной игрой: вся её притягательная сложность возникает вследствие взаимодействия очень простых механик. И дело не только в геймплее, но и в генерации мира игры.
- minecraft
- процедурная генерация
- процедурная генерация карт
- шум перлина
- карта шума
- Разработка игр
- Алгоритмы
- Игры и игровые консоли
Создание генератора мира для minecraft
Думаю, почти все читатели Хабра слышали про майнкрафт, кто-то играл в сингле, кто-то на одном из многочисленных серверов, был даже небольшой сервер у кого-то из хабраюзеров. После двух месяцев игры я задумался — а реально ли написать свой генератор карты? Как оказалось, это вполне возможно сделать за несколько дней неторопливого гугления и кодинга.
Немного технической части
- 4096 байт, содержащих оффсеты чанков (так называются блоки 16x16x128) и их размер в блоках по 4кб, округляя вверх, 3 байта оффсет, 1 — размер
- 4096 байт timestamp’ов чанков, по 4 байта на каждый
- Оставшееся место до конца файла — собственно, данные чанков, сжатые Zlib. 4 байта — размер сжатых данных, 1 — способ сжатия (по умолчанию 2, Zlib (RFC1950)), размер-1 запакованная злибом NBT-структура, т.е сам контейнер кубов
Если упакованные данные занимают меньше целого числа секторов по 4 кб, то остаток сектора заполняется нулями, т.к каждый чанк должен начинаться с оффсета, выраженного целым числом секторов по 4096 байт
Выбор языка
Реализовать такую структуру можно на любом языке, я остановился Delphi 7. Во-первых, это пока единственный язык, который я знаю, во-вторых, именно на 7 версии года 4 назад я начинал писать блокноты по мануалам из Игромании.
Код
Так как данные хранятся в сжатом виде, нам необходим модуль zlib.
Я использовал ZlibEx
Для начала создадим класс чанка, в который будем впоследствии писать данные
Tchunk = class(TObject) private public Data: tmemorystream; c_data: tmemorystream; c_stream: tzcompressionstream; constructor Create; procedure writeblock(x, y, z, block: integer); overload; procedure writeblock(x, y, z, block, color: integer); overload; procedure compress; end;
Код этого класса:
constructor tchunk.Create; begin Data := TMemoryStream.Create; Data.size := 82360; Data.LoadFromFile('data.bin'); c_data := TMemoryStream.Create; c_stream := tzcompressionstream.Create(c_data, zcdefault, 15, 8, zsdefault); end; procedure tchunk.writeblock(x, y, z, block: integer); begin Data.Seek(form1.getoffset(x, y, z) + 16487, 0); Data.Write(block, 1); end; procedure tchunk.compress; var buffer: array [0..82360] of byte; begin c_data.Position := 0; Data.Position := 0; Data.Read(buffer, 82360); c_stream.writebuffer(buffer, 82360); c_stream.Free; c_data.SaveToFile('file' + IntToStr(n)); end;
Функция getoffset выдает нужое смещение по формуле y + ( z *128 + ( x * 128 * 16 ) )
function tform1.getoffset(x, y, z: integer): integer; begin Result := y + (z * 128 + (x * 128 * 16)); end;
Добавим в var пару переменных:
chunks:array[0..32] of array[0..32] of tchunk; n: integer=0;
Процедура для сборки всех чанков в готовый файл:
procedure tform1.SwapEndiannessOfBytes(var Value: cardinal); var tmp: cardinal; i: integer; begin tmp := 0; for i := 0 to sizeof(Value) - 1 do Inc(tmp, ((Value shr (8 * i)) and $FF) shl (8 * (sizeof(Value) - i - 1))); Value := tmp; end; procedure tform1.generatefile; var fileoffset: integer; time, compressiontype, counter: integer; filename: string; regionfile: tfilestream; tmp: cardinal; size: integer; n_x, n_z: integer; bu: array[0..99999] of byte; n: integer; roundedsize: integer; neededsize: integer; d: byte; begin fileoffset := 2; time := $d8de2f4e; compressiontype := $02; filename := GetVar('Appdata') + '\.minecraft\saves\NewWorld\region\r.0.0.mcr'; regionfile := tfilestream.Create(filename, fmcreate); n := 0; for n_x := 0 to 31 do for n_z := 0 to 31 do begin chunks[n_x][n_z].compress; roundedsize := ((chunks[n_x][n_z].c_data.Size) div 4096); if (((chunks[n_x][n_z].c_data.Size) mod 4096) > 0) then Inc(roundedsize); regionfile.seek((4 * ((n_x mod 32) + (n_z mod 32) * 32)), 0); tmp := fileoffset; SwapEndiannessOfBytes(tmp); tmp := tmp shr 8; regionfile.Write(tmp, 4); regionfile.seek(4 * ((n_x mod 32) + (n_z mod 32) * 32) + 3, 0); regionfile.Write(roundedsize, 1); size := chunks[n_x][n_z].c_data.Size + 1; regionfile.seek(fileoffset * 4096, 0); tmp := size; SwapEndiannessOfBytes(tmp); regionfile.Write(tmp, 4); regionfile.Write(compressiontype, 1); chunks[n_x][n_z].c_data.Position := 0; chunks[n_x][n_z].c_data.readbuffer(bu, chunks[n_x][n_z].c_data.size); regionfile.Writebuffer(bu, chunks[n_x][n_z].c_data.size); regionfile.seek((n) * 4 + 4096, 0); regionfile.Write(time, 4); fileoffset := fileoffset + ((chunks[n_x][n_z].c_data.Size) div 4096); if (((chunks[n_x][n_z].c_data.Size) mod 4096) > 0) then fileoffset := fileoffset + 1; Inc(n); end; neededsize := 4096 * fileoffset - regionfile.Size - 1; regionfile.Seek(regionfile.Size, 0); d := 00; for n := 0 to neededsize do regionfile.Write(d, 1); regionfile.Free; end;
Всё, теперь мы имеем метод записи любого блока по любой координате, в пределах региона. При желании, несложно повторить то же для остальных регионов, надо строк 10 кода.
Обертка для writeblock:
procedure tform1.writeworld(x, y, z, block: integer); var xw, zw: integer; begin xw := (x div 16); zw := (z div 16); chunks[xw][zw].writeblock(x mod 16, y, z mod 16, block); end;
Генерация мира, его сжатие и сохранение.
procedure TForm1.Button4Click(Sender: TObject); var x, y, z: integer; xx, zz: integer; image: tbitmap; begin for xx := 0 to 31 do for zz := 0 to 31 do begin chunks[xx][zz] := tchunk.Create; end; image := tbitmap.Create; image.LoadFromFile('image.bmp'); for x:=0 to 127 do for y:=0 to 116 do begin if image.Canvas.Pixels[x,y]=clblack then form1.writeworld(x,117-y,0,49); if image.Canvas.Pixels[x,117-y]=clwhite then form1.writeworld(x,y,0,80); end; form1.generatefile;
Результат:
Можно генерировать не только пиксельарт, но произвольные фигуры, все, что можно задать какой-либо формулой. Например, пол в виде синусоиды:
Проект можно скачать тут.
- Невозможно сохранять изменения в сгенерированном регионе (возможно, из-за того, что пишется одинаковый timestamp, который не совпадает с временем последнего сохранения в level.dat, как разберусь с форматом последнего — попробую реализовать)
- Спавн лучше переставить с помощью McEdit, т.к вполне возможно, что после генерации он окажется в сотне блоков над землей, что чревато летальным исходом(тоже можно менять в level.dat)
- Нет генерации света, вместо этого освещены все блоки, даже под землей(Рассчет освещения — отдельная серьёзная задача, пока не готов ее решать)
- Починить сохранение, т.к без этого теряется половина смысла
- Сделать поддержку записи дополнительной инфы(цвет шерсти, листвы, ориентация печек, etc) // частично готово
- Какое-то подобие ландшафта(холмы/дома/озера)
- Доработал generatefile , сделал нормальный разворот
- Форматирование кода
- Наброски a dditional block data , см. в проекте, ссылка обновлена
- Описание формата карт
- ID блоков для функции writeblock/writeworld
- Zlib для Delphi