Как сделать океан в unreal engine 4

Добавил пользователь Владимир З.
Обновлено: 05.10.2024

Как сделать воду на UNREAL подкиньте пл3 ПОНЯТНЫЙ туториал, я никак не могу врубится у меня вода получается
как жесткое тело все время почему то Может какие то настройки надо в модели ставить или модель паленая ?
Из 3D макса экспортировал в формат OBJ

Вода. Как сделать воду менее прозрачной
Это стандартная водичка из Unity3d free. Можно ли ее как нибудь подкорректировать, что бы не было.

Как сделать перерасчет в оплате за воду 1С 7.7: Комунальные услуги?
Как сделать перерасчет в оплате за воду 1С 7.7: Комунальные услуги? Не типовая конфигурация, тариф.

Unreal Engine 4 как реализован GUI?
Приветствую, давно интересуюсь программированием на C++. Знаю, для разработки GUi есть такие.

СМА ARISTON AVL 100 P(R) S/N605126803 46303570900 Перегревает воду, Перегревает воду
Добрый вечер.Привезли на ремонт машинку и со слов клиента сильно греет воду при.

Использование игрового AI в Online CO-OP и Competitive играх.

Боевая система Final Fantasy в 2D на JavaScript с нуля.

Создание API на PHP и JavaScript для трансляции игры Lines в браузере - видеокурсы ITVDN

Создание Action RPG на Unity 3D под Android. Часть 3.

Создание Action RPG на Unity 3D под Android. Часть 2.

Создание Action RPG на Unity 3D под Android. Часть 1.

Данный урок, из серии видео уроков по "Unreal Engine 4". В этом уроке "Создание пещеры ( Hole )". Практическая работа, создания материала для пещеры и само отверстие в пещеру. Посещайте видео блог ITVDN, где, несомненно, найдете для себя всю необходимую информацию.

Всем привет! Меня зовут Александр, я уже более 5 лет работаю с Unreal Engine, и почти все это время — с сетевыми проектами.

Поскольку сетевые проекты отличаются своими требованиями к разработке и производительности, нередко необходимо работать с более простыми объектами, такими как классы UObject, но их функциональность изначально урезана, что может создать сильные рамки. В этой статье я расскажу о том, как активировать различные функции в базовом классе UObject в Unreal Engine 4.


На самом деле, статью я написал скорее как справочник. Большую часть информации крайне сложно найти в документации или сообществе, а тут можно быстро открыть ссылку и скопировать нужный код. Решил заодно поделиться и с вами! Статья ориентирована на тех, кто уже немного знаком с UE4. Будет рассмотрен С++ код, хотя знать его не обязательно. Можете просто следовать инструкциям, если вам нужно то, о чем пойдет речь. Более того, не обязательно копировать все, вы можете вставить код из раздела с нужными свойствами и он должен работать.

Немного о UObject

UObject — базовый класс почти для всего, что есть в Unreal Engine 4. От него наследуется подавляющее большинство объектов, которые создаются у вас в мире или просто в памяти: объекты на сцене (AActor), компоненты (UActorComponent), разные типы для работы с данными и прочие.

Сам класс хоть и легче производных, но при этом достаточно функционален. Например, он содержит многие полезные события, такие как изменение значений переменных в редакторе и базовые функции для сети, которые не активны по умолчанию.

Объекты, созданные этим классом, не могут находиться на сцене и существуют исключительно в памяти. Их нельзя добавить как компоненты к Actor’ам, хотя он может являться своего рода компонентом, если самому реализовать необходимый функционал.

Для чего мне UObject, если AActor уже поддерживает все, что нужно? В общем-то, примеров использования масса. Самый простой — предметы для инвентаря. На сцене, где-то в небе, хранить их нецелесообразно, поэтому можно хранить в памяти, не нагружая рендер и не создавая лишних свойств. Для тех, кто любит технические сравнения, то AActor занимает килобайт (1016 байт), а пустой UObject всего 56 байт.

В чем проблема UObject?

Проблем в целом нет, ну или я просто не сталкивался с ними. Все, чем раздражает UObject, так это отсутствие различных возможностей, которые по умолчанию доступны в AActor или в компонентах. Вот проблемы, которые я выделил за свою практику:

  • UObject’ы не реплицируются по сети;
  • из-за первого пункта мы не можем вызывать RPC события;
  • нельзя использовать обширный набор функций, требующих ссылку на мир в Блупринтах;
  • в них нет стандартных событий вроде BeginPlay и Tick;
  • нельзя добавлять компоненты из UObject’ов в AActor в Блупринтах.

Большую часть вещей можно легко решить. А вот с некоторыми придется повозиться.

Создание UObject

Прежде чем расширять наш класс возможностями, нам нужно его создать. Давайте воспользуемся редактором, чтобы генератор автоматически записал в хедер (.h) все, что нужно для работы.

Создать новый класс мы можем в Content Browser редактора, нажав кнопку New и выбрав там пункт New C++ Class.


Далее нам нужно выбрать сам класс. В общем списке его может не быть, поэтому раскрываем его и выбираем UObject.


Назовите ваш класс и выберите, в какой папке он будет храниться. Когда мы создали класс, можно зайти в студию, найти его там и начать встраивать все необходимые функции.

Новички, обратите внимание, что создается два файла: .h и .ccp. В .h вы будете объявлять переменные и функции, а в .cpp определять их логику. Найдите оба файла в вашем проекте. Если не меняли путь, то они должны быть в Project/Source/Project/.

Пока мы не продолжили, давайте в макросе UCLASS() над объявлением класса пропишем параметр Blueprintable. Должно получиться что-то вроде этого:

Благодаря этому можно создавать Блупринты, которые будут наследовать все, что мы сделаем с этим объектом.

Репликация UObject

По умолчанию UObject’ы не реплицируются по сети. Как я описал выше, создается ряд ограничений, когда нужно синхронизировать данные или логику между сторонами, но при этом не хранить мусор в мире.

В Unreal Engine 4 репликация проходит как раз за счет мировых объектов. Значит просто создать объект в памяти и отреплицировать его никак не получится. Вам в любом случае понадобится владелец, который будет управлять передачей данных объекта между сервером и клиентами. Например, если ваш объект — это навык персонажа, то владельцем должен стать сам персонаж. Он же и будет проводником для передачи информации по сети.

Подготовим наш объект к репликации. Пока в хедере нам нужно задать лишь одну функцию:


IsSupportedForNetworking() определит, что объект поддерживает сеть и может быть отреплицирован.

Однако не все так просто. Как я написал выше, нужен владелец, управляющий передачей объекта. Для чистоты эксперимента создадим AActor, который будет его реплицировать. Сделать это можно точно так же, как и UObject, только родительский класс, естественно, AActor.

Новички, если вам требуется реплицировать объект в персонаже, контроллере или еще где-то, создайте соответствующий базовый класс через редактор, добавьте в него необходимую логику и уже от этого класса наследуйтесь в Блупринтах.

Внутри нам нужны 3 функции: конструктор, функция репликации подобъектов, функция, определяющая, что внутри этого AActor реплицируется (переменные, ссылки на объекты и прочее) и место, где мы создадим наш объект.

Не забудем создать и переменную, по которой будет храниться наш объект:


Внутри исходного файла мы должны все прописать:

Теперь ваш объект будет реплицироваться вместе с этим Actor’ом. Вы можете вывести его имя на тик, но уже на клиенте. Обратите внимание, что на Begin Play объект до клиента вряд ли успеет прийти, поэтому там смысла писать лог на нем нет.

Репликация переменных в UObject

В большинстве случаях реплицировать объект смысла нет, если в нем не содержится информация, которая так же будет синхронизироваться между сервером и клиентами. Поскольку наш объект уже реплицируется, то и передавать переменные не составит труда. Это делается так же, как и внутри нашего Actor’а:


Добавив переменную и пометив на репликацию, мы сможем ее реплицировать. Тут все просто и так же, как в AActor.

Однако есть небольшой подводный камень, который виден не сразу, но может ввести вас в заблуждение. Это будет особенно заметно, если вы создаете ваш UObject не для работы в C++, а подготавливаете его для наследования и работы в Блупринтах.

Суть в том, что переменные, созданные в наследнике в Блупринтах, реплицироваться не будут. Движок автоматически их не помечает и изменение параметра на сервере в БП ничего не меняет в значении на клиенте. Но и от этого есть лекарство. Для корректной репликации переменных БП вам нужно заранее их пометить. Добавьте пару строчек в GetLifetimeReplicatedProps():

Теперь переменные в дочерних Блупринт классах будут реплицироваться как положено.

RPC события в UObject

RPC (Remote Procedure Call) события — это специальные функции, вызывающиеся на другой стороне сетевого взаимодействия проекта. С помощью них вы можете вызвать функцию с сервера на других клиентах и с клиента на сервере. Очень полезно и часто используется при написании сетевых проектов.

Если вы не знакомы с ними, рекомендую почитать один материал. В нем описывается использование в C++ и в Блупринтах.

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

Взглянув на код компонентов (UActorComponent), мы можем найти несколько функций, которые позволяют передавать вызовы по сети. Так как UActorComponent наследуется от UObject, мы можем просто скопировать необходимые участки кода и вставить в наш объект, чтобы он работал как нужно:


С этими функциями мы сможем вызывать RPC события не только в коде, но и в Блупринтах.

Обратите внимание, что для вызова Client или Server событий необходим владелец, у которого Owner — наш игрок. Например объектом владеет персонаж пользователя или же предмет, у которого Owner — это Player Controller игрока.

Глобальные функции в Блупринтах

Если вы когда-либо создавали Object Блупринт, то могли заметить, что в них нельзя вызвать глобальные функции (статичные, но для понятности назовем так), которые доступны в остальных классах, например, GetGamemode(). Создается ощущение, что вы просто-напросто не можете делать в Object классах, из-за чего вам приходится либо передавать все ссылки при создании, либо же как-то извращаться, а иногда выбор и вовсе падает на класс Actor, который создается на сцене и поддерживает все на свете.

А вот в С++, конечно же, таких проблем нет. Однако гейм-дизайнеру, который играется с настройками и добавляет разные мелочи, не скажешь, что нужно открыть Visual Studio, найти соответствующий класс и в функции doSomething() получить игровой режим, изменив в нем очки. Поэтому крайне важно, чтобы дизайнер мог зайти в Блупринт и двумя щелчками мыши сделать то, в чем заключается его работа. Сэкономите и его время, и ваше. Впрочем, Блупринты для этого и придуманы.

Суть в том, что когда вы ищите или вызываете функции в контекстном меню в Блупринте, те самые глобальные функции, которым требуется ссылка на мир, пробуют вызвать функцию внутри вашего объекта, ссылающуюся на него. И если редактор видит, что функции нет, то понимает, что использовать ее он не сможет и не показывает в списке.


Впрочем, и от этого есть лекарство. Даже два.

Давайте вначале рассмотрим вариант для более удобного использования в редакторе. Нам нужно будет переопределить функцию, которая возвращает ссылку на мир и тогда редактор поймет, что в самой игре она сможет работать:


Теперь она определена и редактор будет понимать, что в целом объект способен получить нужный указатель (хоть он не валидный) и использовать глобальные функции в БП.

Обратите внимание, что владелец (GetOuter()) тоже должен иметь выход к миру. Это может быть другой UObject с определенным GetWorld(), компонент или Actor объект на сцене.



Если ввести в поиск в БП GetGamemode, он появится в списке, как и другие подобные функции, и в параметре будет WorldContextObject, в который нужно передавать ссылку на Actor.


К слову, можно просто подавать туда владельца нашего объекта. Я рекомендую создать функцию на Actor’а, это будет всегда полезно для объекта:


Теперь можно просто использовать глобальные функции в сочетании с нашей Pure функцией для получения владельца.


Если вы во втором варианте так же объявите GetWorld() как и в первом варианте, то сможете подавать в параметр WorldContextObject ссылку на себя (Self или This).


BeginPlay и Tick события

Еще одна проблема, с которыми могут столкнуться разработчики на Блупринтах — в Object классе нет событий BeginPlay и Tick. Безусловно, вы можете их создать сами и вызывать из другого класса. Но согласитесь, что гораздо удобнее, когда это все работает из коробки.

Давайте для начала разберем, как сделать Begin Play. Мы можем создать доступную для перезаписи в БП функцию и вызывать ее в конструкторе класса, но тут есть ряд проблем, так как на момент конструктора ваш объект еще полностью не инициализирован.

Во всех классах существует функция PostInitProperties(), которая вызывается после инициализации большинства параметров и регистрации объекта в различных внутренних системах, например, для сборщика мусора. В ней как раз можно вызвать наше событие, которое будет использоваться в Блупринтах:


Вместо if(GetOuter() && GetOuter()->GetWorld()) можно поставить просто if(GetWorld()) если вы его уже переопределили.

Будьте осторожны! По умолчанию PostInitProperties() вызывается и в редакторе.

Теперь мы можем зайти в наш БП объект и вызвать событие BeginPlay. Оно будет вызываться при создании объекта.

Перейдем к Event Tick. Тут простой функцией нам не обойтись. Tick объектов в движке вызывает специальный менеджер, к которому нужно как-то подцепиться. Однако, тут есть очень удобная хитрость — дополнительное наследование от FTickableGameObject. Это позволит автоматически сделать все, что нужно, и тогда достаточно будет просто подцепить необходимые функции:

Если вы отнаследуетесь от вашего объекта и создадите БП класс, то будет доступно событие EventTick, вызывающее логику каждый кадр.

Добавление компонентов из UObject’ов

В Блупринтах UObject нельзя спавнить компоненты для Actor’ов. Эта же проблема свойственна и Блупринтам ActorComponent. Не очень понятна логика Epic Games, так как в C++ это можно сделать. Более того, вы можете добавить компонент из Actor’а другому Actor объекту просто указав ссылку. Но сделать этого нельзя.

К сожалению, с данным пунктом я так и не смог разобраться. Если у кого найдется инструкция, как это сделать, буду рад выложить сюда.

Единственный вариант, который я могу предложить на данный момент — это сделать обертку в классе UObject, предоставляющую доступ к простому добавлению компонентов. Таким образом получится добавлять компоненты Actor’ам, но у вас не будет динамически создаваться входные параметры спауна. Зачастую, этим можно пренебречь.

Настройка экземпляра через редактор

Допустим, у вас есть менеджер модификаторов для персонажа и сами модификаторы представлены классами, в которых описываются накладываемые эффекты. Гейм-дизайнер создал пару модификаторов и указывает в менеджере, какие используются.

В обычной ситуации выглядело бы вот так:




Одного этого мало, теперь необходимо указать, что та самая переменная с классом будет экземпляром. Это уже делается там, где вы храните объект, например, в менеджере модификаторов персонажа:


Обратите внимание, что мы используем именно ссылку на объект, а не на класс, так как экземпляр будет создан сразу при инициализации. Теперь мы можем зайти в окно редактора выбрать класс и настроить значения внутри экземпляра. Это гораздо удобнее и более гибко.

image

Есть в Unreal Engine еще один интересный класс. Это AInfo. Класс, унаследованный от AActor, не имеющий визуального представления в мире. Info используют такие классы, как: игровой режим, GameState, PlayerState и прочие. То есть классы, которые поддерживают разные фишки от AActor, например, репликацию, но при этом не размещены на сцену.

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

Однако учтите, что хоть и у объекта нет координат, визуальных компонентов и он не рендерится на экране, он все равно является наследником Actor класса, а значит, настолько же тяжелый, как и родитель. Резонно использование в малых количествах и ради удобства.

Заключение

UObject нужен очень часто, и я советую пользоваться им всегда, когда Actor в действительности не нужен. Жаль, что он немного ограничен, но это одновременно и плюс. Иногда приходится повозиться, когда вам нужно использовать нестандартный шаблон, но главное, что все основные ограничения можно снять.

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

Надеюсь, статья будет полезна тем, кто изучает или работает с Unreal Engine 4. Если вдруг какая-то часть не компилируется, то можете сообщить об этом в комментариях или в личку. Также буду очень благодарен, если кто-то знает еще различные полезности, связанные с UObject.

За урок нами будет создано окружение в игре. На главную сцену мы добавим дом, объекты внутри него, а также различные источники света. По итогу игрок сможет перебираться в пределах обставленной сцены.

Видеоурок

Расстановка объектов может занять от минуты и до нескольких месяцев. Unreal Engine очень крут в плане расстановки объектов и зачастую этим занятием занимаются игровые дизайнеры.

Пример расстановки объектов:


Читайте также: