
Разработка игры -> Restoration of Teim
7 постов
7 постов
9 постов
5 постов
6 постов
5 постов
Но у вас в организации полно студентов - стажёров
Доброго времени суток! Если вы вдруг захотели сделать игру со случайной генерацией мира (В моем случае это приключенческий выживач-боссобойка) но у вас как и у меня нет либо навыков, либо желания делать сложную процедурную генерацию полноценных структур, то, возможно, вам подойдет мой вариант, который я постараюсь расписать ниже.
Сам принцип:
Играли в Морской Бой? В нем на двухмерной матрице 10x10 на нужно расставить опр. количество маленьких, средних и больших кораблей.
Вот у нас в ядре своем, мир тоже будет двухмерной матрицей (только нужного вам размера), в котором случайные ячейки мы помечаем как будущие: малые острова (синие), средние острова (зеленые), и крупные острова (красные)
Потом, используя данные этой карты, мы в координатах игрового мира будем размещать случайные ландшафты островов из заранее созданного пресета (об это далее). И схематично, на выходе мы получим что-то вот такое:
Само собой это можно будет конфигурировать под ваши нужны, например если бы вам хотелось чтобы крупных островов было больше, а маленькие, к примеру, могли бы прилегать к островам побольше. Да в принципе и понятие "большой" можно наверное превратить и в целые материки, не 2x2 ячейки, а скажем 6x6.
Штош, хватит картинок и буковок, займемся кодом! (Ага, теперь буковки даже без картинок пойдут...)
2. Пишем код для генерации 2d матрицы с данными о расположении островов
Для начала определимся что карта островов будет int двумерным массивом, где:
0 - пустое пространство
1 - маленький остров
2 - средний остров
3 - большой остров
И так, создаём скрипт "IslandMapGenerator", и первым делом задаём перечисление (enum) с нашими островами (заодно видны настройки класса, он не статический, и не Monobehavior)
Далее, я хочу подвязать генерацию карты с seed, вы видели это наверное во всех играх с процедурной генерацией мира. Если нет, то это необходимо чтобы создать эдакий "ключ генерации", при котором мир будет генерироваться каждый раз одинаково.
Метод GenerateIslandsMap()
Далее пишем основной метод, который и будет возвращать 2d массив с островами, она же наша карта островов
Метод принимает следующие параметры:
worldSize - размер мира, то есть размер нашего 2d массива
b|m|s_islandCount - количество островов каждого типа, которые необходимо генерировать.
Далее метод использует другой метод PlaceIslands() (который вы еще не написали, да) для каждого вида островов, начинаем с больших, и заканчиваем маленькими.
Возвращает метод int[,] islandsMap, то бишь необходимый нам результат в виде 2д массива с будущими островами, пока что это просто цифорки)
Метод PlaceIslands()
Теперь, собственно, перейдем к методу PlaceIslands() :
Метод принимает 2d массив карты (1), который мы определили методом ранее, размер мира (2), количество островов (3) и тип острова (4).
Он что делает... Он выполняет цикл while пока :
А Не будет создано необходимое кол-во островов.
Б количество попыток/итераций превысит лимит.
В каждой попытке он через наш _random определяет случайную координату для нашего массива, и... И вызывает еще один метод (Обожаю, сука, методы в методах!) TryPlaceIsland(), и если этот метод успешен (вернул true), то мы увеличиваем значение созданных островов на 1 (сама пометка ячейки под цифру острова происходит "глубже")
Метод TryPlaceIsland()
Принимает в параметрах этот метод следующее:
1. 2d массив карты
2. размер мира
3 и 4. координаты в которых будем генерироваться (пытатся) остров, ну и вид острова.
Он через Switch определяет вид острова, и в зависимости от вида, вызывает ЕЩЕ ОДИН ВЛОЖЕННЫЙ МЕТОД (Эти последние, правда! (нет)), для каждого вида острова свой, зощем? Да потому что у каждого вида острова своя логика размещения.
(3) Большие острова - это 4 ячейки вместе (2х2), и соотв. за раз метод красит 4 ячейки и проверяет отсутствие соседей вокруг этих 4 ячеек, а не вокруг одной.
(2) Средние острова могут быть горизонтальными или же вертикальными, и состоят из 2х соседних ячеек
(1) Ну а с мелкими всё и так понятно
И наконец последние 3 метода, которые и выполняют всю логику пометок ячеек массива соотв. числом.
Все следующие методы будут принимать один и тот же набор параметров:
1. 2d массив карты
2. размер мира
3. позицию генерации х (внутри массива) и позицию y
Метод для большого острова TryPlaceBigIsland()
1) Первым делом мы проверяем что наша координата массива (startX и startY) не находятся в правом крайнем, или нижнем ряду массива, ведь тогда при попытке создать 4 ячейки острова он просто выпадет в ошибку (выход за границы массива)
2)
Далее мы циклом перебираем все 4 ячейки будущего большого острова (красной точкой я отметил нашу startX | startY ячейку), внутри которых выполняем метод (этот точно последний, простите) IsCellValidForIsland(), метод выполняет проверку всех соседей вокруг ячейки, и возвращает true если соседей нет. (Код этого метода напишу в конце)
3) Если все 4 ячейки успешно прошли проверку этим методом, тогда мы переходим к третьему циклу, в котором мы точно так же проходимся по всем 4м нашим ячейкам, и передаем им значение 3 ((int)IslandSize.Big это 3)
Метод для среднего острова TryPlaceMediumIsland()
Так как средний остров может быть либо вертикальным, либо горизонтальным, тут 2 поведения, в зависимости от значения horizontal, которое мы определяем через простенькое выражение (1) _random.Next(0, 2), генерирует случайное число в заданном диапазоне, и если == 0, то горизонтальная ориентация, иначе вертикальная.
2) Делаем в принципе аналогичные действия что и для большого острова, только для 2х ячеек а не для 4х, и со смещением на одну вправо по x
3) Аналогично, но смещаемся на одну ячейку вниз по y
Метод для маленького острова TryPlaceSmallIsland()
Ну тут все максимально просто, проверили соседей, влепили ячейке 1
Ну сам метод проверки отсутствия соседей IsCellValidForIsland()
Как я уже написал ранее, этот метод принимает в параметрах координаты ячейки, проверяет все ячейки вокруг (от x -1 y -1 до x+1 y+1) и возвращает истину если ни одна из этих ячеек не занята, и не выходит за границы массива
На этом всё! Код который будет нам генерировать шаблон размещения островов по сиду в принципе готов. Надо только теперь его проверить как-то, хотя бы схематично и для отладки
Давайте создадим еще скрипт (В этот раз стандартный Monobehavior ), и назовём его WorldGenerator, и повесим его на новый объект в сцене, и назовем его World
И напишите в скрипте следующий код:
DebugPrintIslandsMap() выведет в консоль игры текстовый вариант карты, которую мы в параметре ему передаем
А в Start объявляется в переменную генератор наш IslandMapGenerator, с сидом 123, создается маленькая карта через генератор, 10 ячеек, 2 больших острова, 3 средних и четыре маленьких, и выполняется метод вызова в консоль.
У меня при заданном сиде 505 получился вот такой результат, немного повело из-за разницы в размере символ, но в целом читается.
На этом первую часть думаю стоит завершить, слишком много текста получилось. Пока что довольно непрезентабельно и примитивно, но я сам вызвался писать поэтапно) А это по сути просто массив-заготовка. Всё еще впереди)
Очень много шума в интернете на тему что "нейросети сейчас всех заменят!". И я решил показать как я сейчас делаю 3д-модели для игровых проектов с использованием нейросетей)
Шаг 1: С помощью нейросети вроде "Шедеврум" генерируем себе дизайн-референс персонажа
Красота!
Шаг 2: Во второй нейросети (Meshy AI) делаем готовую 3д модель по арту:
И получаем просто великолепнейший результат! Очень красиво и круто! Но, нет не так... НО!!!
Как говорится, дьявол кроется в деталях. ТРИСТА ТЫСЯЧ ПОЛИГОНОВ и кривая топология (сетка модели) на выходе. Для какого нибудь статичного рендера это пойдет, но для игры это никуда не годится.
А у меня небольшая около-стратегия, где максимальный лимит полигонов на юнита, это 1-2к полигонов.
Поэтому вздыхаем, и идём делать модель вручную :D
Но как итог, нейросеть это невероятно удобный вспомогательный инструмент при работе, но пока что, никак не замена. Как минимум у меня с лёту появился референс для "облепки" модели, дизайн, и в какой-то степени готовая текстура (арт натянуть на развертку)
Тоскуя что в очередной раз с друзьями мы не соберемся в DnD сессию на выходных (Второй месяй!). Я обратился к нейронке Дикпик DeepSeek с вопросом:
Когда нейросети похожие тебе смогут заменить гейм-мастера в настольных ролевых играх типа DnD?
На что я получил ответ типа:
Та я как бы могу
Она начала там что-то оправдыватся про то что "Ой да я только базово знаю" "Да я буду водить по упрощенной модели" "Да у меня контекстная память 10-15 сообщений" Но меня было уже не остановить, в конце концов не такой уж этот отчет для начальника и срочный!
Я создал новый чат-диалог, и написал следующее:
Я ожидал что-то коряво-бредовое и бессмысленное, потерю контекста истории, и... Ну знаете как играть в DnD с дедом склеротиком у которого еще и альцгеймер
- Дед, ну че там дракон делает
- КТО ЗДЕСЬ?!
Однако...
Но к своему удивлению (Если нарочно не нести ерунду и не руинить выстраивающийся нейросетью сюжет), получается увлекательная складная история, с бросками кубика, боями, гармоничной сменой сцен, и черт возьми, он даже вплел светящиеся волосы главной героини в историю постоянно напоминая как они реагируют на пространство!
Как итог я получил короткое, поверхностное по механикам, с огрехами, но невероятно увлекательное приключения с логическим началом (которое я задал сам), и концовкой (которое уже придумала нейросеть). Были и сражения с чудищами на болотах, и мистика, и реакция окружения на моё поведение!
Важно отметить! Чтобы получить именно такой экспириенс какой вы хотите, необходимо обговорить с нейронкой сразу важные для вас вещи, кто будет кидать кубы (вы сами, или он за вас), как будет строится повествование, как я здесь:
Так же от ошибок тоже никто не застрахован, например здесь он пропустил бой с чудищем на болотах, и перешел сразу к руинам (а мы шли к ним через болота), но ничего страшного, просто укажите ему на это, и он отмотает повествование:
Если кому вдруг интересно как выглядит вся моя кампания про Агнесс с Дикпиком DeepSeek от начала и до конца в формате PDF, то вот (МАДЕРАТОР НЕ БЕЙ!) :
А заодно чего-нибудь авторского в Пикабушку подкинуть)
Бомжорно Добрый день! Я уже очень долгое время (Целый год, ага), пытаюсь реализовать свою задумку в виде приключеской игры (с налётом RPG), где мы будем исследовать множество миров-дисков (Осколков) бороздящих просторы вселенной.
А для того что эти осколки продуцировать, нужна система генерации этих самых миров. Вот с ней и вожусь, вотъ
Вот так генерация леса и окружения выглядела ранее:
А вот так это все выглядит сейчас:
Несмотря на то что мир состоит из огромных гексагонов (Да, странное решение), я пытаюсь сделать это менее заметным, а мир более живым, рельеф, каменистые склоны, растительеость и.т.д. Впереди конечно ещё очень много работы
Буквально вчера сделал эти динамические облачка через шейдеры, нраица
Модель игрока и текстурки - временные плейсхолдеры (заглушки)
Благодарю за внимание)