Unreal Engine Учебник для геймплея Framework C ++

  1. Актер
  2. ActorComponent
  3. PlayerController
  4. Доступ к PlayerControllers
  5. AIController
  6. Доступ к AIController
  7. Нерест
  8. пешка
  9. Доступ к пешкам
  10. GameModeBase
  11. Доступ к GameMode
  12. Доступ к HUD
  13. Порожденный
  14. Личные замечания
  15. Мир
  16. Доступ к миру
  17. GameInstance
  18. Доступ к GameInstance
  19. PlayerState
  20. Доступ к PlayerState
  21. Порожденный
  22. Личные замечания
  23. GameStateBase
  24. Доступ к GameStateBase
  25. UObject
  26. Нерестовые объекты
  27. Личные замечания
  28. GameplayStatics
  29. Доступ к GameplayStatics
  30. Личные замечания

Игровой фреймворк Unreal Engine 4 предоставляет мощный набор классов для создания вашей игры. Ваша игра может быть стрелялкой, симулятором фермы, глубокой РПГ, это не имеет значения, структура очень гибкая, выполняет некоторые тяжелые работы и устанавливает некоторые стандарты. Он имеет довольно глубокую интеграцию с движком, поэтому мой непосредственный совет - придерживаться этих классов, а не пытаться «раскрутить свою» игровую среду, как вы могли бы с движком, подобным Unity3D. Понимание этой структуры имеет решающее значение для того, чтобы быть успешным, а создание ваших проектов - эффективная работа

Любой, кто интересуется созданием игр с UE4, особенно тех, кто работает с C ++, и хотел бы узнать больше о Unreal's Gameplay Framework. В этом посте рассматриваются основные классы, которые вы будете использовать в Gameplay Framework, и объясняется их использование, как они создаются движком и как получить доступ к каждому из этих классов из других частей вашего игрового кода. Большая часть представленной информации относится и к Blueprint.

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

При создании игр в Unreal Engine 4 вы обнаружите, что множество шаблонов уже сделано для вас. Есть несколько классов, которые вы будете использовать при создании игр на C ++ или Blueprint. Я расскажу о каждом из классов, о некоторых изящных функциях, которые они содержат, и о том, как ссылаться на них из других мест вашего кода. Большая часть информации в этом руководстве все же относится к Blueprint, хотя я использую фрагменты C ++, и некоторые функции могут быть недоступны для Blueprint и поэтому относятся только к пользователям C ++.

Актер

Пожалуй, самый используемый класс в вашей игре. Актер является основой для любого объекта на вашем уровне, включая игроков, врагов ИИ, двери, стены и объекты игрового процесса. Актеры создаются с использованием ActorComponents (см. Следующий раздел), таких как StaticMeshComponent, CharacterMovementComponent, ParticleComponent и многие другие. Даже такие классы, как GameMode (см. Ниже) являются актерами (хотя GameMode не имеет «реальной» позиции в мире). Давайте поговорим о нескольких вещах, которые вы должны знать об актерах.

Actor - это класс, который вы можете реплицировать по сети (для многопользовательской игры), и это легко сделать, вызвав SetReplicates (true) в вашем конструкторе. Есть много вещей, которые вступают в игру, когда имеешь дело с эффективными сетями в Actors, поэтому я не смогу рассказать об этом в этом блоге.

Актеры поддерживают концепцию получения урона из коробки. Урон может быть нанесен непосредственно на актера с помощью MyActor-> TakeDamage (…) или с помощью UGameplayStatics :: ApplyDamage (…), обратите внимание, что существуют варианты, доступные для PointDamage (например, оружие для прицельного удара) и RadialDamage для таких вещей, как взрывы. Есть отличное вступление к Ущерб в UE4 на официальном сайте Unreal Engine.

Вы можете легко породить новый экземпляр Actor в коде, используя GetWorld () -> SpawnActor <T> (…); где T - класс для возврата, например. AActor одного из ваших собственных типов, таких как AGadgetActor, AGameplayProp и т. Д.

Вот фрагмент кода, в котором Actor создается во время выполнения:

FTransform SpawnTM;

FActorSpawnParameters SpawnParams;

SpawnParams. SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod :: AlwaysSpawn;

SpawnParams. Владелец = GetOwner ();

/ * Попытка назначить зачинщика (используется для нанесения ущерба) * /

SpawnParams. Зачинщик = Cast <APawn> (GetOwner ());

ASEquippableActor * NewItem = GetWorld () -> SpawnActor <ASEquippableActor> (NewItemClass, SpawnTM, SpawnParams);

Есть много способов получить доступ к актерам, обычно у вас есть указатель / ссылка на конкретный интересующий вас актер. В приведенном выше примере мы можем сохранить указатель на экипируемого актера через переменную NewItem и начать манипулировать актером. пример через это.

UGameplayStatics :: GetAllActorsOfClass (…) позволяет использовать одну из особенно полезных функций, которую вы можете использовать при создании прототипов или в работе с движком. Это позволяет вам захватывать массив всех действующих лиц класса, в который вы переходите (включая производные классы, если вы собираетесь их передать). в Actor как классе вы в основном получаете ВСЕ вещи на уровне… вероятно, не то, что вы ищете) Эту функцию часто боятся и избегают, поскольку это не очень эффективный способ взаимодействия с вашей средой, но иногда это единственный инструмент, который вы получили ,

Актеры на самом деле не имеют перевода, вращения или масштаба. Это все устанавливается и извлекается через RootComponent, например. Компонент верхнего уровня в иерархии SceneComponents (подробнее о SceneComponents см. ниже), очень часто используемые функции, такие как MyActor-> GetActorLocation (), фактически переходят в RootComponent и возвращают его местоположение в мире.

Вот некоторые дополнительные полезные функции, которые вы будете использовать в контексте Actor:

  • BeginPlay // «Первая» функция, которая вызывается после того, как Actor был создан и полностью инициализирован. Это хорошее место для настройки базовой логики, таймера или изменения некоторых свойств теперь, когда они полностью инициализированы и могут запрашивать окружение.
  • Tick // Вызывается каждый кадр, для большинства актеров это в конечном итоге будет отключено по соображениям производительности, но по умолчанию включено. Отлично подходит для быстрой настройки динамической логики и проверки данных для каждого кадра. В конце концов вы обнаружите, что перемещаете больше кода в логику на основе событий или запускаете таймеры в логику производительности на более низких частотах.
  • EndPlay // Вызывается, когда Actor удаляется из мира, включая EEndPlayReason, который указывает, почему он был вызван.
  • GetComponentByClass // Найти отдельный экземпляр компонента определенного класса, очень полезно, когда у вас нет точного типа Actor, но вы знаете, что он должен содержать определенный тип компонента. Существует также GetComponentsByClass, который возвращает все экземпляры класса, а не только первый найденный.
  • GetActorLocation // И все его варианты, * Поворот, * Масштаб, включая SetActorLocation и т. Д.
  • NotifyActorBeginOverlap // Удобно для проверки перекрытий, вызванных любым из его компонентов. Быстро настроить триггеры геймплея таким образом.
  • GetOverlappingActors // Легко узнать, какие другие акторы в настоящее время перекрывают наши, также доступен вариант компонента: GetOverlappingComponents

Актер содержит множество функциональных возможностей и переменных, это краеугольный камень игрового фреймворка в Unreal Engine, так что это неудивительно. Хороший способ дальнейшего изучения этого класса - открыть файл заголовка Actor.h в Visual Studio и посмотреть, какие функции доступны. Здесь есть еще кое-что, поэтому давайте перейдем к следующему классу в нашем списке.

Рекомендуемое чтение

ActorComponent

Компоненты находятся внутри Actors, общие компоненты включают StaticMeshComponent, CharacterMovementComponent, CameraComponent и SphereComponent. Каждый из этих компонентов обрабатывает одну конкретную задачу, такую ​​как движение, физическое взаимодействие (например, объем столкновения, чтобы просто проверить нахождение актеров) или визуально отобразить что-то в мире, например, сетку игрока.

Подклассом этого компонента является SceneComponent , который является базовым классом для всего, что имеет Transform (Position, Rotation, Scale) и поддерживает вложение. Например, вы можете прикрепить ваш CameraComponent к SpringArmComponent, чтобы настроить камеру от третьего лица, и у нее есть преобразование, и вложение требуется для правильного управления относительными позициями.

Компоненты чаще всего создаются в конструкторе Actor, вы также можете создавать и уничтожать компоненты во время выполнения. Сначала давайте посмотрим на одного из конструкторов моего актера.

ASEquippableActor :: ASEquippableActor ()

{

PrimaryActorTick. bCanEverTick = true;

MeshComp = CreateDefaultSubobject <UStaticMeshComponent> (TEXT ("MeshComp"));

MeshComp -> SetCollisionObjectType (ECC_WorldDynamic); // Просто устанавливаем свойство для нашего компонента

RootComponent = MeshComp; // Задаем наш корневой компонент для других компонентов SceneComponents, которые нужно присоединить к

ItemComp = CreateDefaultSubobject <UItemComponent> (TEXT ("ItemComp")); // не привязан ни к чему (не SceneComponent с преобразованием)

}

USkeletalMeshComponent создается с использованием CreateDefaultSubobject <T> (функция Actor) и требует указания имени (вы увидите это имя в списке компонентов Blueprint), вы будете использовать эту функцию много, если создадите свой игровой код в C ++, но ТОЛЬКО в контексте конструктора.

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

WidgetComp = CreateDefaultSubobject <UWidgetComponent> (TEXT ("InteractWidgetComp"));

WidgetComp -> SetupAttachment (MeshComp);

SetupAttachment будет обрабатывать начальное присоединение для нас, и ожидается, что он будет вызван для ВСЕХ компонентов сцены, кроме самого RootComponent, который должен быть выполнен в конструкторе. Вы можете удивиться, почему мой ItemComponent не вызывает эту функцию SetupAttachment. Это просто, потому что этот компонент является ActorComponent, но НЕ SceneComponent и не имеет Transform (местоположение, вращение, масштаб) и поэтому не требует добавления в иерархию. Компонент по-прежнему будет зарегистрирован в Actor независимо от того, как он отделен от иерархии, что означает, что функции, такие как MyActor-> GetComponentByClass, будут возвращать любые ActorComponents и SceneComponents.

Вместе с Actor эти Компоненты имеют решающее значение для построения вашей игры на C ++ и Blueprint. Они действительно являются строительными блоками для вашей игры. Вы можете легко создавать свои собственные пользовательские компоненты и заставлять их обрабатывать что-то конкретное в вашей игре, например HealthComponent, который удерживает очки жизни и реагирует на урон, который получает актер-владелец.

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

UActorComponent * SpawnedComponent = NewObject <UActorComponent> (this, UStaticMeshComponent :: StaticClass (), TEXT ("DynamicSpawnedMeshCompoent"));

if (SpawnedComponent)

{

SpawnedComponent -> RegisterComponent ();

}

Некоторые встроенные полезные функции для ActorComponents включают

  • TickComponent () // Точно так же, как Tick () Actor выполняет каждый кадр для выполнения высокочастотной логики.
  • bool bIsActive и связанные с ним функции, такие как Активировать, Деактивировать, .., чтобы включить / отключить компонент полностью (включая TickComponent), не уничтожая компонент и не удаляя его из Actor.

Чтобы включить репликацию на ActorComponent, вы должны вызвать SetIsReplicated (true), который немного отличается по имени от функции Actor. Это необходимо только в том случае, если вы пытаетесь реплицировать определенный фрагмент логики для этого компонента, например, переменную при вызовах функций, и поэтому не все компоненты реплицируемого субъекта должны быть реплицированы.

PlayerController

Основной класс для игрока, получающего вход от пользователя. Сам PlayerController не отображается визуально в окружении, вместо этого он будет «обладать» экземпляром Pawn, который определяет визуальное и физическое представление этого игрока в мире. Во время игры у игрока может быть несколько различных пешек (например, транспортное средство или свежая копия пешки при повторном порождении), в то время как экземпляр PlayerController остается неизменным на протяжении всего уровня. Это важно, так как могут быть моменты, когда PlayerController вообще не имеет пешки. Это означает, что такие вещи, как открытие меню, должны быть добавлены в PlayerController, а не в класс Pawn.

В многопользовательских играх PlayerController существует только на клиенте и сервере. Это означает, что в игре из 4 игроков сервер имеет 4 контролера игроков, а у каждого клиента только 1. Это очень важно для понимания того, куда следует помещать определенные переменные, поскольку, когда всем игрокам требуется репликация переменной игрока, она никогда не должна существовать в PlayerController, но в Pawn или даже PlayerState (будет рассмотрен позже).

Доступ к PlayerControllers
  • GetWorld () -> GetPlayerControllerIterator () // GetWorld доступен в любом экземпляре Actor
  • PlayerState-> GetOwner () // владелец playertate имеет тип PlayerController, вам нужно будет привести его к PlayerController самостоятельно.
  • Pawn-> GetController () // Устанавливается только тогда, когда пешка в данный момент «одержима» (т. Е. Контролируется) с помощью PlayerController.

Этот класс содержит PlayerCameraManager, который обрабатывает цели просмотра и преобразования камеры, включая сотрясения камеры. Другим важным классом, который обрабатывает PlayerController, является HUD (описан ниже), который используется для рендеринга Canvas (не так часто используется сейчас, когда доступен UMG) и может быть полезен для управления некоторыми данными, которые вы хотите передать в интерфейс UMG.

Всякий раз, когда новые игроки присоединяются к GameMode, для этого игрока создается новый PlayerController через Login () в классе GameModeBase.

AIController

Схожа по концепции с классом PlayerController, но исключительно для агентов ИИ, а не игроков. Обладает пешкой (см. Ниже), очень похож на PlayerController и является «мозгом» агента. Там, где Pawn является визуальным представлением агента, AIController является лицом, принимающим решения.

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

Доступ к AIController

Доступ к AIControllers можно получить таким же образом, как и к PlayerControllers из Pawn (через «Get Controller»), а в Blueprint есть функция «GetAIController», доступная в любом месте, а вход, как ожидается, будет Pawn, которым управляет AI.

Нерест

При желании AIControllers могут быть созданы автоматически, установив переменную «Auto Possess AI» в классе Pawn. Убедитесь, что вы устанавливаете переменную «AI Controller Class» в Pawn на нужный вам класс при использовании этого.

пешка

Физическое и визуальное представление того, что контролирует игрок (или ИИ). Это может быть транспортное средство, воин, турель или все, что представляет персонажа вашей игры. Распространенным подклассом для Pawn является Character, который реализует SkeletalMesh и, что еще более важно, CharacterMovementComponent с МНОГИМИ опциями для тонкой настройки того, как ваш игрок может перемещаться по окружению, используя обычное движение типа стрелка.

В многопользовательских играх каждый экземпляр Pawn реплицируется на других клиентов. Это означает, что в игре с четырьмя игроками и сервер, и каждый клиент имеют по 4 экземпляра пешки. Нередко «убивают» экземпляр Пешки, когда игрок умирает, и порождают свежий экземпляр при возрождении игрока. Помните об этом для хранения ваших данных, которые вы хотите сохранить за пределами жизни одного игрока (или воздержитесь от использования этого паттерна и сохранения вместо этого экземпляра пешки)

Доступ к пешкам
  • PlayerController-> GetPawn () // Только тогда, когда на ПК в данный момент есть пешка
  • GetWorld () -> GetPawnIterator () // GetWorld доступен в любом экземпляре Actor, возвращает ВСЕ пешки, включая AI, который у вас может быть.
Порожденный

GameModeBase порождает Pawn с помощью SpawnDefaultPawnAtTransform, класс GameModeBase также указывает, какой класс Pawn будет порождаться.

GameModeBase

Основной класс, который указывает, какие классы использовать (PlayerController, Pawn, HUD, GameState, PlayerState) и обычно используется для указания правил игры для таких режимов, как «Захват флага», где он может обрабатывать флаги, или для обработки «порождений волны». в основанном на волне шутере. Обрабатывает и другие ключевые функции, такие как порождение игрока.

GameMode является подклассом GameModeBase и содержит еще несколько функций, изначально используемых в Unreal Tournament, таких как MatchState и другие функции типа шутера.

В мультиплеере класс GameMode существует только на сервере! Это означает, что ни у одного клиента нет экземпляра. Для однопользовательских игр это не имеет никакого эффекта. Чтобы реплицировать функции и хранить данные, необходимые для вашего GameMode, вы должны рассмотреть возможность использования GameState, который существует на всех клиентах и ​​создан специально для этой цели.

Доступ к GameMode
  • GetWorld () -> GetAuthGameMode () // GetWorld доступен из любого экземпляра Actor.
  • GetGameState () // возвращает игровое состояние для репликации функций и / или переменных
  • InitGame (…) // инициализирует некоторые правила игры, включая правила, указанные в URL (например, «MyMap? MaxPlayersPerTeam = 2»), которые можно передать при загрузке уровней в игре.

HUD

Класс пользовательского интерфейса. Имеет много кода Canvas, который представляет собой код для рисования интерфейса пользователя, который был до UMG - который взял на себя большую часть сегодняшнего рисования интерфейса.

Класс существует только на клиенте. Не подходит для репликации. Принадлежит PlayerController.

Доступ к HUD

PlayerController-> GetHUD () // Доступно в вашем локальном PlayerController

Порожденный

Появляется внутри PlayerController, который владеет HUD через SpawnDefaultHUD (порождает универсальный AHUD), затем переопределяется GameModeBase через InitializeHUDForPlayer с классом HUD, указанным в GameModeBase.

Личные замечания

Я использую этот класс все реже, чем до UE4 дней, UMG может обрабатываться через PlayerController. Просто имейте в виду, что для многопользовательских игр вы должны убедиться, что контроллер плеера IsLocalController (), прежде чем создавать какие-либо виджеты.

Мир

UWorld это объект верхнего уровня, представляющий карту, на которой будут существовать и отображаться актеры и компоненты. Содержит постоянный уровень и многие другие объекты, такие как gamestate, gamemode и списки, такие как Pawns и Controllers, которые в настоящее время находятся на карте.

Трассировка линии и все ее варианты выполняются через мир с такими функциями, как World-> LineTraceSingleByChannel и многие другие варианты, как это.

Доступ к миру

Легко получить доступ, вызвав GetWorld () внутри ваших актеров.

При попытке получить экземпляр мира в статических функциях вам нужно передать «WorldContextObject», который по сути является просто входным параметром, который мы можем использовать для вызова -> GetWorld (). Вот пример из одного из моих заголовочных файлов:

статический APlayerController * GetFirstLocalPlayerController (UObject * WorldContextObject);

GameInstance

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

Доступ к GameInstance
  • GetWorld () -> GetGameInstance <T> (); // где T - тип класса, например. GetGameInstance <UGameInstance> () или ваш собственный производный тип.
  • Actor-> GetGameInstance ()
Личные замечания

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

PlayerState

Контейнер для переменных для репликации между клиентом / сервером для конкретного игрока. В многопользовательских играх он не должен запускать логику, а является просто контейнером данных, поскольку PlayerController доступен не на всех клиентах, а Pawn часто уничтожается, когда игрок умирает так непригодно для данных, которые необходимо хранить даже после смерти.

Доступ к PlayerState

Pawn имеет переменную Pawn-> PlayerState, также доступную в Controller-> PlayerState. PlayerState в Pawn назначается только до тех пор, пока Контроллер владеет этой Pawn, в противном случае это nullptr.

Список всех текущих экземпляров PlayerState (например, всех игроков в данный момент в матче) доступен через GameState-> PlayerArray.

Порожденный

Класс для появления назначается в GameMode (PlayerStateClass) и порождается AController :: InitPlayerState ()

Личные замечания

Полезно только при работе в многопользовательских играх.

GameStateBase

Аналогичен PlayerState, но для клиентов - информация об GameMode. Поскольку экземпляр GameMode не существует на клиентах, а только на сервере, это полезный контейнер для репликации информации, такой как истекшее время матча или результаты команд и т. Д.

Имеется два варианта: GameState и GameStateBase, где GameState обрабатывает дополнительные переменные, необходимые для GameMode (в отличие от GameModeBase)

Доступ к GameStateBase
  • World-> GetGameState <T> () // где T - класс, к которому нужно привести, например. GetGameState <AGameState> ()
  • MyGameMode-> GetGameState () // хранится и доступен в вашем экземпляре игрового режима (актуально только на сервере, который владеет единственным экземпляром GameMode), вместо этого клиенты должны использовать вышеуказанный вызов.
Личные замечания

Используйте GameStateBase поверх GameState, если ваш игровой режим не является производным от GameMode вместо GameModeBase.

UObject

Базовый объект для почти всего в движке, Actors являются производными от UObject, как и другие базовые классы, такие как GameInstance. Это никогда не будет использоваться для визуализации чего-либо, но может быть очень полезно для хранения некоторых данных и функций, когда структуры могут не подходить для ваших конкретных требований.

Нерестовые объекты

UObjects не создаются как Actors, но создаются с использованием NewObject <T> (), например:

TSubclassOf <UObject> ClassToCreate;

UObject * NewDesc = NewObject <UObject> (this, ClassToCreate);

Личные замечания

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

Может использоваться с сетью, но требует некоторой дополнительной настройки в классе объектов, и объекты должны храниться внутри Actor.

GameplayStatics

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

Доступ к GameplayStatics

Поскольку GameplayStatics является библиотекой UBlueprintFunctionLibrary, вы можете получить к ней доступ из любого места в вашем коде (или в этом плане Blueprint)

UGameplayStatics :: WhwhatFunction (); // к статическим функциям легко получить доступ где угодно, просто включите #include "Kismet / GameplayStatics.h"

Личные замечания

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

Если вы хотите узнать больше о C ++, у меня есть курс, посвященный C ++, посвященный Udemy, который обучает многим основным аспектам программирования в Unreal Engine 4 с помощью пошаговых видеороликов и практических примеров!

Кроме того, некоторые рекомендовали прочитать основы геймплея и программирование в Unreal Engine 4.

Например, «MyMap?