📜 ⬆️ ⬇️

The basis of the gameplay in C ++ for the Unreal Engine

image

The basis of the gameplay for Unreal Engine 4 provides the developer with a powerful set of classes for creating a game. Your project can be a shooter, farm simulator, deep RPG - it doesn’t matter, the foundation is very versatile, does some of the hard work for you and sets some standards. It is quite integrated into the engine, so I recommend that you stick to these classes, rather than trying to reinvent your own game base, as is often the case with engines like Unity3D. Understanding this framework is very important for successful and effective work on projects.

Who is this article for?


For everyone who is interested in creating games in UE4, specifically in C ++, and who wants to learn more about the basis of the Unreal gameplay. This post discusses the base classes that you will use at the heart of the gameplay, explains their use, the process of creating their instances with the engine, and how to access these classes from other parts of the game code. Most information is also valid for blueprints.

If you want to get acquainted with the basics of Unreal Engine 4, then study my previous manual . I also have a separate guide dedicated to virtual reality for beginners . It is useful to those who study the specifics of VR in the Unreal Engine 4.

When creating games in Unreal Engine 4, you will encounter many ready-made boilerplate blanks. There are several classes that you will often use when creating games in C ++ or in blueprints. We will look at each of these classes, their nice features, and learn how to refer to them from other parts of the code. Most of the information in this guide also applies to blueprints, however, I use code fragments in C ++ and therefore some functions will not be available in blueprints and are useful only for C ++ users.
')

Actor


Probably the most frequently used class in games. Actor is the basis for any object on a level, including players controlled by AI of enemies, doors, walls and gameplay objects. Actors are created using ActorComponents (see the next section), such as StaticMeshComponent, CharacterMovementComponent, ParticleComponent, and many others. Even classes such as GameMode (see below) are actors (although GameMode does not have a “real” position in the world). Let's discuss a couple of aspects that you need to know about actors.

Actor is a class that can be replicated over a network (for multi-user mode). This is easily done using a call in the SetReplicates (true) constructor. To create effective network programming actors need to take into account many aspects that I can not consider in this article.

Actors support the concept of taking damage. Damage can be applied directly to the actor using MyActor-> TakeDamage (...) or via UGameplayStatics :: ApplyDamage (...). It is worth considering that there are variations: PointDamage (for example, for weapons, the hit from which is calculated by the ray tracing (hitscan)) and RadialDamage (for example, for explosions). The official Unreal Engine website has a great introductory article Damage in UE4 .

Create a new instance of the actor in the code, you can simply using GetWorld () -> SpawnActor <T> (...); where T is the return class, for example, AActor for one of your own classes — AGadgetActor, AGameplayProp, etc.

Here is an example code in which an actor is created during the execution of an application:

FTransform SpawnTM; FActorSpawnParameters SpawnParams; SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; SpawnParams.Owner = GetOwner(); /* Attempt to assign an instigator (used for damage application) */ SpawnParams.Instigator = Cast<APawn>(GetOwner()); ASEquippableActor* NewItem = GetWorld()->SpawnActor<ASEquippableActor>(NewItemClass, SpawnTM, SpawnParams); 

There are many ways to access actors. Usually you will have a pointer / link to a specific actor that you need. In the example shown above, we store a pointer to the actor of the worn object in a variable and begin to manipulate the actor instance through it.

A very useful function that can be used for prototyping or mastering the engine is UGameplayStatics :: GetAllActorsOfClass (...) . It allows us to get an array of all the actors of the passed class (including the generated classes; if you pass as a class Actor, then we get ALL the objects of the level). This function is often feared and avoided as a not very effective way of interacting with the environment, but sometimes it is the only available tool.

Actors do not have their own transfer, rotation or scale. All this is set and obtained using RootComponent, i.e. the top-level component in the SceneComponents hierarchy (more on SceneComponents is described below). The most commonly used functions like MyActor-> GetActorLocation () actually go to the RootComponent and return its location in the world.

Here are some more useful functions that are used in the context of an actor:


Actor contains a huge functionality and a lot of variables - it is the foundation of the gameplay core in the Unreal Engine, so this is not surprising. For further study of this class, it would be nice to open the header file Actor.h in Visual Studio and see what functionality it has. In the article we still have a lot to consider, so let's move on to the next class in the list.

Actorcomponent


The components are located inside the actors, the standard components are StaticMeshComponent, CharacterMovementComponent, CameraComponent and SphereComponent. Each of these components handles its own particular task, for example, movement, physical interaction (for example, the amount of collision to clearly check interacting actors) or visually display something in the world, for example, the mesh of a player.

A subclass of this component is SceneComponent - this is the base class for everything associated with Transform (Position, Rotation, Scale) that supports pinning. For example, we can attach a CameraComponent to a SpringArmComponent to configure a third-person camera. Both transform and attachment are required to set the relative position correctly.

Most often, components are created in the actor constructor, but you can also create and destroy them during execution. To begin, let's consider one of the constructors of my actor.

 ASEquippableActor::ASEquippableActor() { PrimaryActorTick.bCanEverTick = true; MeshComp = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("MeshComp")); MeshComp->SetCollisionObjectType(ECC_WorldDynamic); // Just setting a property on our component RootComponent = MeshComp; // Set our root component for other SceneComponents to attach to ItemComp = CreateDefaultSubobject<USItemComponent>(TEXT("ItemComp")); // not attached to anything (not a SceneComponent with a transform) } 

USkeletalMeshComponent is created using the CreateDefaultSubobject <T> (actor function) and requires the name to be specified (this name can be seen in the list of blueprint components). If you are writing game code in C ++, you will often use this function, but ONLY within the context of the constructor.

You may also notice that we set MeshComp as the new RootComponent. All Scene Components should now be attached to this mesh, which can be easily done using the following line:

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

SetupAttachment will handle the initial attachment; it is expected that it will be called in the constructor for ALL components of the scene, except for the RootComponent itself. One may wonder why my ItemComponent does not call this SetupAttachment function. It happened so simply because this component is an ActorComponent, but NOT a SceneComponent and does not have a Transform (position, rotation, scale), and therefore should not be added to the hierarchy. However, the component will still register with Actor. Being separated from the hierarchy means that functions like MyActor-> GetComponentByClass will return all ActorComponents and SceneComponents.

Along with Actor, these components are crucial for creating games in both C ++ and blueprints. They are the building blocks of the game. You can easily create your own components so that they handle some specific aspects of the game, such as the HealthComponent, which stores health points and responds to the damage taken by its parent actor.

Using the code below, you can create your own components during the execution process. This is different from the CreateDefaultSubobject behavior, which is used only for constructors.

 UActorComponent* SpawnedComponent = NewObject<UActorComponent>(this, UStaticMeshComponent::StaticClass(), TEXT("DynamicSpawnedMeshCompoent")); if (SpawnedComponent) { SpawnedComponent->RegisterComponent(); } 

Here is some of the useful functionality of ActorComponents:


To ensure the replication of ActorComponent, it is necessary to call the function SetIsReplicated (true), whose name is slightly different from the function of the actor. This is necessary only when you need to replicate a specific part of the component's logic, for example, a variable when you call a function, that is, you do not need to replicate all components of the replicated actor.

Playercontroller


This is the base class for the player receiving input from the user. PlayerController itself is not visually displayed in the environment, instead it controls the Pawn instance, which determines the visual and physical representation of this player in the world. During gameplay, a player may have several different Pawn (for example, a vehicle or a fresh copy of Pawn in respawn), and an instance of PlayerController remains the same throughout the level. This is important, because at some points PlayerController may not have any pawn at all. This means that things like opening the menu should be added to the PlayerController, and not to the Pawn class.

In multiplayer games, PlayerController exists only on the client that owns it and on the server. This means that in a 4-player game, the server has 4 player controllers, and each client only has one. It is very important to understand when it is necessary to use variables; if all players require replication of a player variable, then it should exist not in PlayerController, but in Pawn or even in PlayerState (discussed below).

Accessing PlayerControllers


This class contains the PlayerCameraManager , which handles the camera’s view targets and transforms, including shaking. Another important class that PlayerController manages is HUD (discussed below). It is used for rendering on Canvas (now used less frequently because there is a UMG) and it can be used to manage the data that needs to be transferred to the UMG interface.

When a new player connects to GameMode, PlayerController is created for this player in the GameModeBase class using Login ().

Pawn


It is a physical and visual representation of what the player (or AI) controls. It can be a car, a warrior, a tower, or anything else that represents a character in a game. The standard Pawn subclass is Character, which implements SkeletalMesh and, more importantly, CharacterMovementComponent with many options to fine-tune the player’s movement around the environment using the usual motion shooter.

In multiplayer games, each instance of Pawn is replicated to other clients. This means that there are 4 pawn instances in the game for 4 players both on the server and on each client. Quite often, a Pawn instance is “killed” when a player dies, while a respawn creates a new instance. Keep this in mind when storing data that should be saved after the end of the player’s life (or completely abandon this pattern and keep the pawn instance alive at all times)
Accessing Pawn


Creature

GameModeBase creates a pawn using the SpawnDefaultPawnAtTransform. The GameModeBase class also determines which Pawn class to create.

Gamemodebase


Base class that defines which classes to use (PlayerController, Pawn, HUD, GameState, PlayerState). Often used to set game rules in modes such as “Capture the Flag”; he can handle flags or waves of enemies. Handles other important functions, such as player creation.

GameMode is a subclass of GameModeBase. It contains a few more features that were originally used in the Unreal Tournament, such as MatchState and other shooter features.

In multiplayer mode, the GameMode class exists only on the server! This means that no client has an instance of it. In single player games, it has no influence. You can use GameState, which exists on all clients and is designed specifically for this purpose, to replicate the functions and store the data necessary for GameMode.

Accessing GameMode


Hud


This is the user interface class. It contains a lot of Canvas code, which is a user interface drawing code written before the appearance of UMG . Today, the main work on drawing the user interface is engaged in UMG.

The class exists only in the client. Replication is not possible. It is owned by PlayerController.

Accessing HUD

PlayerController-> GetHUD () // Available in local PlayerController.

Creature

It is created using SpawnDefaultHUD (creates a regular AHUD) inside PlayerController, which owns the HUD, and then overwritten by GameModeBase using the InitializeHUDForPlayer HUD class specified in GameModeBase.

My personal notes

I began to use this class less and less, and I use UMG, which can be controlled through PlayerController. Don't forget - before creating widgets in multiplayer games, you need to make sure that the player's controller is IsLocalController ().

World


UWorld is a top-level object representing the map on which actors and components will exist and render. Contains a constant level and many other objects, such as gamestate, gamemode, as well as lists of Pawns and Controllers on the map.

Line tracing and all its variations are performed through the World using functions such as World- > LineTraceSingleByChannel and many other similar variations.

Accessing the World

To gain access, just call GetWorld () inside the actors.

When you need to get an instance of World in static functions , you need to pass WorldContextObject, which is essentially a word for any actor that you can use to call -> GetWorld (). Here is an example from one of my header files:

 static APlayerController* GetFirstLocalPlayerController(UObject* WorldContextObject); 

Gameinstance


GameInstance has one instance that continues to exist for the duration of the entire game. When navigating between maps and menus, the same instance of this class will be saved. You can use this class to create event handlers or handle network errors, load user data such as game parameters, and functions that are not related to just one game level.

Accessing GameInstance


My personal notes

Usually not used in the early stages of a project. Do not do anything critical, unless you dive into the development (can control aspects such as gaming sessions, playing a demo or transferring data between levels)

Playerstate


Container for variables replicated between client / server for an individual player. In multiplayer games, it is not designed to perform logic and is simply a data container, since PlayerController is not available to all clients, and Pawn is often destroyed when the game player dies, therefore not applicable to data that should be stored after death.

Accessing PlayerState

Pawn contains it as a variable Pawn-> PlayerState, also available in Controller-> PlayerState. PlayerState in Pawn is assigned only when Pawn owns the Controller; otherwise, it is nullptr.

A list of all available PlayerState instances (for example, all players in a match) can be obtained via GameState-> PlayerArray.

Creature

The creating class is assigned in GameMode (PlayerStateClass) and created in AController :: InitPlayerState ()

My personal notes

Useful only when working on multiplayer games.

GameStateBase


Looks like PlayerState, but provides clients with GameMode information. Since the GameMode instance does not exist in clients, but only on the server, this class is a useful container for replicating information, such as the end of a match, team points, etc.

It has two variations - GameState and GameStateBase. GameState handles additional variables required by GameMode (unlike GameModeBase)

Accessing GameStateBase


My personal notes

Use GameStateBase instead of GameState, only if the gamemode is not inherited from GameMode instead of GameModeBase.

Uobject


The basic object for almost everything in the engine. Actors are inherited from UObject, as well as other base classes, such as GameInstance. It should never be used for rendering, but is very useful for storing data and functions when a struct is not suitable for you.

Creating UObjects

UObjects do not spawn like actors, but are created using NewObject <T> (). For example:

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

Personal notes

It is unlikely that you will create classes directly from a UObject, unless you have mastered the engine well and do not want to delve into creating your own systems. I, for example, use it to store lists of information from a database.

It can be used for the network, but additional configuration of the object class is required, and the objects must be stored in the actor.

Gameplaystatics


Static classes are used to handle various standard game functions, for example, playing sounds and creating particle effects, creating actors, applying damage to actors, getting a player's Pawn, PlayerController, etc. This class is very useful for all sorts of access to gameplay features. All functions are static, that is, you do not need a pointer to an instance of this class and you can call functions directly from anywhere, as shown in the example below.

Accessing GameplayStatics

Since GameplayStatics is a UBlueprintFunctionLibrary, you can access it from anywhere in the code (or blueprint)

 UGameplayStatics::WhateverFunction(); // static functions are easily accessed anywhere, just include #include "Kismet/GameplayStatics.h" 

My personal notes

In this class, many useful features and it must be known when creating any game. I recommend to study it to learn about its capabilities.

Links


Recommended for learning the basics of gameplay and programming in the Unreal Engine 4 materials.

Source: https://habr.com/ru/post/357976/


All Articles