Pull to refresh

Как я продолжаю изучать UE4 делая свою игру

Reading time4 min
Views5.6K

Всем доброго дня


В этой статье я хочу рассказать про проблемы, которые встретил при продолжении разработки автосимулятора и к чему пришёл пытаясь их обойти.

World composition


В прошлой статье я рассказывал, как это просто и быстро в UE4 сделать большой мир, разделённый на кусочки для оптимизации загрузки. В итоге я отказался от этого режима по следующим причинам:

  • прежде всего обратил внимание на то, что на всех примерах и видео сами Эпики (и другие разработчики) карты размером 8км х 8км делают «целиковыми». Это даже больше, чем мне надо, так что World Composition для меня — это, судя по всему, некий over optimisation.
  • прокладывая дороги с помощью Landscape Splines я обратил внимание, что UE4 не разбивает их по размеру ячейки карты (на стыках), а расширяет её границы по размеру получившегося Spline. Это вызывает проблемы при попытке перемещения карты, а так же, похоже, портит логику динамической подгрузки, загружая сразу всё, через что дорога проходит (в моём случае это половина всего мира).
  • граница кусков карты — это вообще интересный вопрос. Я переделал дороги на самодельный Blueprint Spline (об этом ниже) и, чтобы не повторить «ошибок» Landscape Splines, мне надо было реализовать автоматическое разбиение Spline на куски на границах уровней, синхронизацию изгибов в этих местах, создание дочерних объектов (чтобы каждый на свой уровень поместить для авто подгрузки)… не уверен, что это в принципе возможно, и уж точно потребовало бы уйму времени (с ходу не нашёл в Blueprints упоминания функций определения границ уровня и т.п)
  • проваливание сквозь карту. Про обход этой «фичи» с помощью BlockTillLevelStreamingCompleted() я уже рассказал в той статье. Однако, это решение привело к следующей проблеме:
  • фриз при переходе между мирами. При выборе миссии (на уровне с меню) и запуска OpenLevel (на мир с World Composition), фикс выше приводил к «замиранию» игры на полсекунды-секунду, т.е. происходил spawn игрока, отрисовывался первый кадр и вся игра замирала, пока не закончится динамическая подгрузка уровней. Чтобы найти обход этой проблемы ушло около дня, пришлось снова опускаться на уровень С++, подключать модуль «StreamingPauseRendering» и настраивать анимацию в override для «BeginLoadingScreen». В итоге я сделал просто переход между мирами через тёмный экран, что лучше, чем отрисовывание автомобиля не реагирующего на управление.
  • ещё во время написания этой статьи я вспомнил, что при переходе из меню в мир с World Composition стриминг сам собой не запускался и пришлось его триггерить опять же через С++

    void UMyGameInstance::OnWorldChanged(UWorld * OldWorld, UWorld * NewWorld)
    {
    	Super::OnWorldChanged(OldWorld, NewWorld);
    
    	if (NewWorld) {
    		if (NewWorld->WorldComposition) {
    			const TArray<ULevelStreaming*> TilesStreaming = NewWorld->WorldComposition->TilesStreaming;
    			NewWorld->ClearStreamingLevels();
    			NewWorld->SetStreamingLevels(TilesStreaming);
    		}
    	}
    }
    

Создание дорог с помощью Blueprints Spline


Я уже упоминал, что Blueprints Spline имеют огромный потенциал для «построения» дорог (автогенерация указателей, километровых столбов, остановок да и вообще любых «вдольдорожных» объектов), но куда менее настраиваемые Landscape Splines выигрывают за счёт фичи «Deform Landscape to Splines». Так вот оказалось, что эта функция есть как «глобальная», зовётся "Editor Apply Spline" и её можно вызвать для любой связки Landscape + Spline! Так что с помощью «Call In Editor» функций своей Blueprint я сделал генерацию двух параллельных Spline (типа канавы вдоль дороги) и деформации ландшафта под эту всю конструкцию. Получилось достаточно хорошо.


Трёхмерные объекты в Widgets


Похоже, что Vehicle Variety Pack так и остаётся бесплатным для всех и, в принципе, это хороший стартовый набор для любого автосима, разве что там сразу надо править центр масс для каждой модели, особенно для грузовичка, иначе он будет переворачиваться в каждом повороте. Чтобы не тратить время на полноценный 3D гараж, я решил сделать выбор подходящего авто для каждой миссии в Widget, однако оказалось, в него нельзя добавлять трёхмерные объекты! Workaround'ом для этой проблемы стали текстуры типа «Render Target», можно поставить 3х мерный объект, навести на него камеру и настроить её «показывать» в текстуру, а уже эту текстуру, как плоский объект, отображать в Widget. Делал по примеру с этого видео, расположив все машины из набора «за спиной» у основной камеры.


Выход из машины на ходу


Для меня на текущий момент не всегда очевидны пропорции объектов в игре, по этому я решил ввести в игру стандартный манекен UE4, чтобы на глаз прикидывать на сколько всё окружающее правдоподобно (ширина дороги, высота деревьев и другие ассеты понахватанные из разных наборов). Этот курс на Udemy мне, в целом, не понравился, но там рассказывается, в том числе, и как сделать вход\выход из машины. Однако, если выйти из машины на ходу, то, после «отстыковки» водителя (вместе с PlayerController) машина уезжает в даль на полном ходу. Пришлось создать и повесить его на все автомобили как AI Controller Class собственный «dummy» AIController, который не давит на газ и врубает ручник.


Фокус в меню для клавиатуры


Внезапно оказалось проблемой закрывать меню в игре по нажатию на Esc. Не было никаких сложнойстей в игре отловить Esc, поставить игру на паузу и открыть Menu Widget на весь экран… а вот по повторному Esc закрываться он не спешил, override «On Key Down» начинал срабатывать в каких-то неочевидных ситуациях, типа «вызвать консоль UE4 по ~, потом её закрыть, потом что-то нажать...» Решение оказалось до боли простым — поставить галочку «Is Focusable» в дизайнере Widget на корневом элементе (на самом Widget).


Спасибо за внимание, если мне удастся вырваться из вышедшего Mount & Blade II: Bannerlord и не впасть в выходящий Snowrunner, то продолжу развивать свой проект и писать про все неочевидные вещи, забравшие немало нервов и времени.

Tags:
Hubs:
Total votes 4: ↑3 and ↓1+6
Comments2

Articles