Ну начнем по маненьку.
Для начала, хотелось бы рассказать технической части (из готового) и немножко о геймплее.
Если кто заходил ко мне в контактик (на всякий случай ссылка: https://vk.com/lima_strace), то вы видели, что записи посвящены мультиплееру и генераторам L1 и L2, вот о последних и поговорим.
Весь игровой мир можно условно разделить на слои (layer). Всего их 4, начиная с нуля:
L0 – или слой Вселенной. По задумке, на поздней стадии разработки будет добавлен в сетевом режиме игры и будет показывать ближайшие игровые галактики, созданные другими игроками и добавленными на текущий игровой Хаб.
L1 – слой галактики. Представлен в виде структуры, содержащими такие параметры, как позиция, цвет основной звезды, сид звездной системы и набор бит флагов. Самое интересное здесь бит флаги, т.к. в них содержатся все данные об экономике, политике, фракциях, итд. Таким образом можно сохранить все необходимые данные, не разворачивая звездную систему из сида. Для одиночной игры это экономит место на диске/в оперативке. Для сетевой игры это сильно экономит траффик, хоть и наводит некоторые ограничения по кол-ву флагов на систему. Также на этом слое будет происходит генерация туманностей (когда я придумаю как их быстро рисовать)
L2 – слой звездной системы. Как и L1 он представлен в виде небольшой структуры, в которой хранятся сиды планет, их стартовые (момент времени t0) позиции. В отличии от L1 этот слой разворачивается только в момент прибытия игрока в конкретную систему.
L3 – слой орбиты. Он присутствует только у тех планет, где L2 разместил станции. И содержит шаблон станции, данные по импортам-экспортам, продаваемых на верфях модулей кораблей.
Для генерации галактики был взят очень простой и быстрый метод.
Сначала генерируется Балдж (Bulge), по формулам эллипса и шумом в расположении звезд таким образом, чтобы в условных нулях осталось достаточно места для размещения массивной черной дыры.
Потом генерируется диск. Для него снова берутся те же формулы, но в отличии от балджа берется не один, а N эллипсов, причем больший радиус следующего эллипса (A) несколько больше предыдущего. Все эллипсы, кроме самого малого, повернуты на некоторое одинаковое кол-во градусов относительно друг друга таким образом, чтобы самый больший эллипс был повернут относительно самого малого эллипса на 2Пи радиан. Таким образом получаются рукава.
Сами звезды рисуются через единую систему частиц. Приходится использовать не совсем обычные функции для этого, т.к. необходимо передать достаточно внушительный объем данных на конвеер визуализации. Раньше для этого использовалась текстура, в которой каждый пиксель обозначал конкретную звезду. В формате R32G32B32A32, можно было задать 4 вектора, которых было достаточно для позиционирования, масштабирования и окрашивания, однако при тестировании оказалось, что метод не совсем удачный, т.к. не было учтено то, что для получении пробы точка выбирается по текстурным координатам (UV 0..1) и в некоторые моменты в качестве пробы могло прийти интерполированное значение от нескольких смежных пикселей, что в результате давало либо мерцание, либо наложение нескольких звезд в одной точке:
https://www.youtube.com/watch?v=L07smX_Fs9k (вставить видео не могу, поэтому ссылка)
Поэтому от этого метода было решено отказаться, а заместо него использовать другой. Этот новый метод основан на двух путях:
Путь 1 – простой. У Эмиттера в UnrealEngine4 есть не экспортируемая в редактор функция ForceSpawn, который позволят создать один или несколько партиклов в заданной локации и, если необходимо, с заданной скоростью. В дальнейшем можно получить объект этого партикла и установить параметры, такие как цвет, размер на необходимые. Из минуса этого метода можно назвать невозможность использования с GPU партиклами (банально не вернется объект), а также приличную нагрузку на процессор при обходе массива с ними.
Путь 2 – каскадный. Более сложный, т.к. требует понимания того, как реализованы частицы в UE4. Из минусов можно назвать то, что при работе каскадного модуля нельзя узнать точно, какая из частичек сейчас обрабатывается (на самом деле можно: если система частиц не имеет модуля Lifetime, а сама система частиц настроена только на один единственный прогон, то можно взять переменную ActiveParticles и отнять от нее единицу, и таким образом получить текущий индекс частицы), а также невозможность получить из этого модуля данные из игрового треда простым путем.
Сейчас, временно используется первый путь из-за его простоты. Чуть позднее перейду на второй (когда разберусь с передачей данных при GPU частицах)
С планетами все несколько проще. Берется SimplexNose, который генерируется из сида планеты, мерджится с несколькими подобными нойсами и выбирается цвет, в зависимости от цветности точки по типу поверхности. Также из результирующего шума можно сгенерировать NormalMap и/или HeightMap для штатного тасселятора.
С планетами все несколько проще. Берется SimplexNose, который генерируется из сида планеты, мерджится с несколькими подобными нойсами и выбирается цвет, в зависимости от цветности точки по типу поверхности. Также из результирующего шума можно сгенерировать NormalMap и/или HeightMap для штатного тасселятора.
А вот самих локаций планет (т.е. посадок на них) не будет. Не будет их по нескольким причинам:
1) Нет и не будет достаточного кол-ва контента для их заполнения (Брабен, Крис, привет)
2) Для них необходима совершенно другая физика полета.
3) Полноценная терра генерация занимает приличное к-во времени, которое можно было бы потратить на более интересные для игрока вещи (например, квесты).
Теперь кратенько о геймплее и мультиплеере. Подробно буду рассказывать в последующих постах.
Геймплей можно условно разделить на 3 части:
Прибытие – Когда игрок только прибывает в новую галактику в ней никого нет (или есть, если включен сетевой режим). Нам дается небольшой корабль без команды, шахтерское и простенькое сборочное оборудование и, собственно, все. У нас несколько задач: первая – это найти как можно больше пригодных для заселения и богатых ресурсами планет; вторая – найти ресурсы и собрать маяк для моста Эйнштейна-Розена, ну а третья доставить и установить этот маяк в центре галактики недалеко от массивной черной дыры.
Воссоединение – Как только мост будет активирован, через него начнут прибывать колонисты. На этом этапе задача игрока помогать кораблям добраться до найденных ранее планет и всячески помогать им обустроить свой быт. Также игрок продолжает искать новые пригодные планеты.
Со временем колонии начнут выходить в космос, строить свои корабли и объединятся с соседями во фракции, налаживать торговые связи. Появляются местные валюты (может быть одна, может быть несколько [зависит от расположения фракций относительно друг друга]). Когда некоторое кол-во фракций будет сформировано, а их границы соприкоснутся начнется третий этап игры.
Передел – На данный момент это последний планируемый этап игры. Он основан на политических и военных играх между фракциями, гонкой вооружения и прочими вкусностями высоко развитых миров. На этом этапе самые развитые фракции начинают поглощение и ассимиляцию малых фракций, также возможны конфликты между высоко развитыми, которые могут привести к полномасштабной войне. В прочем, игрок может и не вмешиваться, а спокойно заниматься своими делами в сторонке.
Конец игры наступает в случае, если в галактике остается только одна фракция и игрока отсылают исследовать новую галактику для начала нового цикла (событие «Новый день»); если игрок находит и активирует событие под кодовым названием «Мистерия»; если происходит событие «Дорога домой»
Мультиплеер это отдельный режим игры, в котором игрок волен выбирать свою роль. Он может стать пилигримом и найти новую галактику для заселения, либо присоединится к колонистам в уже обжитой.
Топология игры создается таким образом, что каждый отдельно взятый игрок может создать свой собственный сервер со своей собственной галактикой. В этом случае он может играть со своими друзьями, или же добавить свой сервер на игровой Хаб, тем самым расширив пределы игрового мира (и контента) на общее кол-во серверов внутри хаба. В этом случае будет возможно путешествие по мосту Эйнштейна-Розена в центре галактики (при условии, что установлен маяк) к соседям, и, соответственно соседей к нам.