Usage Docs -- FString in Unreal Engine
API Docs
General purpose string container with Unicode support (internally stored as UTF-16).
FString my_str = FString(TEXT("Hello, world"));
// Dereferencing an FString converts it to a TCHAR that is appropriate for printf-style interpolation
UE_LOG(LogTemp, Warning, "my_str says: %s", *my_str);
Because FStrings are encoded in UTF-16, using a simple dereference when passing to non-wide-char libraries or functions will likely result in one or zero-length strings for ASCII due to the null padding bytes. Use the TCHAR_TO_ANSI()
macro to perform the conversion.
In the opposite direction-- this also can cause issues when trying to use the UE logging functions with a bare char*
string in plain ASCII. Turning it into an FString first fixes this.
// To ANSI
TCHAR_TO_ANSI(*my_str);
// From ANSI
FString(my_charptr);
Numeric strings to numeric type conversions using FCString
.
int32_t my_int = FCString::Atoi(*my_str);
int64_t my_bigint = FCString::Atoi64(*my_str);
float my_float = FCString::Atof(*my_str);
double my_double = FCString::Atod(*my_str);
Usage Docs -- FText in Unreal Engine
API Docs
String container with localization and templating support.
Usage Docs -- FName in Unreal Engine
API Docs
Usage Docs -- Arrays in Unreal Engine
API Docs
An array or vector list used for storing multiple items. Supports C++17 style for-loop iterators.
Simple empty declaration and adding new values via Emplace()
:
TArray<FString> name_list;
// Appending values to the end of the array
name_list.Emplace(FString(TEXT("Winkey")));
name_list.Emplace(FString(TEXT("Nancy")));
name_list.Emplace(FString(TEXT("Froggy")));
Using an initializer list:
// Using implicit declarations via class inference
TArray<FString> new_hires = { TEXT("Diddy"), TEXT("Dixie"), TEXT("Lankey") };
// Using explicit declarations
TArray<FString> big_bosses = { FString(TEXT("Ridley")), FString(TEXT("Bowser")) };
Get the length (number of entries) in the array:
// Get number of entries
int name_count = name_list.Num();
Get specific entry via index.
// Get a specific entry
// This is a potentially dangerous operation
// and should be wrapped with a bounds check to
// ensure the value referenced actually exists
FString &first = name_list[0];
Note: using the
[]
operator can potentially return anullptr
or invalid reference. Be very careful to check that the index actually exists.
Iterating through the array with a range-based for loop:
// Iterate through the array
for(auto &tname : name_list) {
UE_LOG(LogTemp, Warning, "Got name: %s", *tname);
}
Check if a value exists via Contains()
:
// Checking to see a value exists
if(name_list.Contains(TEXT("Winkey"))) {
UE_LOG(LogTemp, Warning, "Winkey is here!");
}
Joining two arrays together via Append()
:
name_list.Append(new_hires);
Usage Docs -- Set Containers in Unreal Engine
API Docs
Similar to TArray
, but only allows unique values.
TSet<FString> flag_list;
flag_list.Emplace(FString(TEXT("running")));
flag_list.Emplace(FString(TEXT("fast")));
flag_list.Emplace(FString(TEXT("running"))); // this will not be added
// Get items in list -- this should return 2
int flag_count = flag_list.Num();
// Iterate through the array
for(auto &tflag : flag_list) {
UE_LOG(LogTemp, Warning, "Got flag: %s", *tflag);
}
Joining multiple sets. This also works for adding values from a TArray
to a TSet
, as long as they share the same initializer types (eg. adding TArray<FString>
to TSet<FString>
):
TArray<FString> new_flags = { TEXT("v8"), TEXT("fancy"), TEXT("wobbly") };
flag_list.Append(new_flags);
Usage Docs -- Map Containers in Unreal Engine
API Docs
A dictionary or hash structure for storing key/value associations. The type class used for the key portion must have comparison operators implemented (this includes most base types and Unreal container types, but should be kept in mind when using custom classes).
TMap<FString, AActor*> my_actors;
// Append entries to the map
// my_actors["GoodGuy"] = GoodGuyActor
my_actors.Emplace(TEXT("GoodGuy"), GoodGuyActor);
my_actors.Emplace(TEXT("BadGuy"), BadGuyActor);
// Iterate through the map
for(auto& [tkey, tvalue] : my_actors) {
// Print key name and X,Y,Z location of the actor via its pointer
UE_LOG(LogTemp, Warning, "Got actor: %s @ <%s>", *tkey, *tvalue->GetActorLocation().ToString());
}
Docs:
General Unreal architecture overview
wiki.unrealengine.com Archive
Handles rules of the game.
Handles current state/variables of the game in the current run/iteration. Includes state information that is not tied to a specific character.
Handles player input. Player input can also be directly handled inside of the game's ACharacter subclass, if it has one (which seems to be how most of the UE4 first- and third-person examples are configured). The main reason for implementing PlayerController is to seperate input handling from a specific character/pawn.
Why even implement a PlayerController class in the first place, instead of just putting the functionality into your Character base class?
"To represent an agent in the world we typically use 2 objects, a Pawn and a Controller. Think of the Pawn as the in-world representation of the agent and the Controller as the "will" or the "brain" that drives it. The Pawn is kind of like a sock puppet, with the PlayerController being the person whose hand is inside. A Controller can possess/unposses a pawn to take/release control of it. A Pawn doesn't always have to have a Controller, and a Controller doesn't always need to be possessing a Pawn."
- @Byooler (Unreal Engine Developer) [see forum post]
DefaultInput.ini
BindAction
- bind an action named BindKey
(as defined in Project Settings > Input) to a function CallbackBindAxis
- for fractional/analog input (eg. axes)BindTouch
- for multi-touch inputBindGesture
- for gesture-based inputBindVectorAxis
- used for things like rotation/tilt that return an FVector instead of boolean or float componentExample of a PlayerController base class with a SetupInputComponent()
function, and a couple delegate examples. Note that if this were instead defined inside of the Character base class, we wouldn't need to get a reference with GetPawn()
.
void AMyPlayerController::SetupInputComponent() {
Super::SetupInputComponent();
// BindAction(BindKey, PressedReleased, this, &PlayerController::DelegateFunc)
InputComponent->BindAction("Jump", IE_Pressed, this, &AMyPlayerController::Jump);
InputComponent->BindAction("Jump", IE_Released, this, &AMyPlayerController::StopJumping);
// BindAxis(BindKey, this, &PlayerController::DelegateFunc)
InputComponent->BindAxis("MoveForward", this, &AMyPlayerController::MoveForward);
InputComponent->BindAxis("MoveRight", this, &AMyPlayerController::MoveRight);
// BindTouch(PressedReleased, this, &PlayerController::DelegateFunc)
InputComponent->BindTouch(EInputEvent::IE_Pressed, this, &AMyPlayerController::MoveToTouchLocation);
InputComponent->BindTouch(EInputEvent::IE_Repeat, this, &AMyPlayerController::MoveToTouchLocation);
}
void AMyPlayerController::Jump()
{
if(AMyCharacter* MyPlayer = Cast<AMyCharacter>(GetPawn()))
{
MyPlayer->Jump();
}
}
void AMyPlayerController::MoveForward(float Value)
{
if(AMyCharacter* MyPlayer = Cast<AMyCharacter>(GetPawn()))
{
FRotator PlayerRot = MyPlayer->Controller->GetControlRotation();
FRotator YawRotation(0.0f, PlayerRot.Yaw, 0.0f);
// Scale by X axis for forward movement; for left/right, scale by Y instead
FVector Direction = FRotationMatrix(YawRotation).GetScaledAxis(EAxis::X);
MyPlayer->AddMovementInput(Direction, Value);
}
}
...
Turn
/ Look
- refer primarily to mouse look (or player camera orbiting-- eg. by using the right stick on an Xbox or PS4 controller)Used to control the current camera state. Can be subclassed (in C++ or Blueprints) in order to set custom pitch/yaw/roll limitations, as well as implementing custom camera controls that are independent from player or pawn movement.
Setting custom defaults for your camera in the constructor:
AMyPlayerCameraManager::AMyPlayerCameraManager()
{
// Set default pitch parameters
ViewPitchMin = -90.0f;
ViewPitchMax = -15.0f;
}
Make sure to designate your selected CameraManager in either Blueprints, or the C++ class. Example of setting it inside of a custom PlayerController subclass:
AMyPlayerController::AMyPlayerController()
{
PlayerCameraManagerClass = AMyPlayerCameraManager::StaticClass();
}
Fetching the current CameraViewPoint (location, rotation) info from the Character class:
APlayerController* PC = GetController<APlayerController>();
if (PC != nullptr)
{
FVector CamLoc;
FRotator CamRot;
PC->PlayerCameraManager->GetCameraViewPoint(CamLoc, CamRot);
GEngine->AddOnScreenDebugMessage(1, 2.0f, FColor::Green, FString::Printf(TEXT("CameraMgr rot: <%0.02f, %0.02f, %0.02f>"), CamRot.Pitch, CamRot.Yaw, CamRot.Roll));
GEngine->AddOnScreenDebugMessage(2, 2.0f, FColor::Green, FString::Printf(TEXT("CameraMgr loc: <%0.02f, %0.02f, %0.02f>"), CamLoc.X, CamLoc.Y, CamLoc.Z));
}
Current state/variables for a player.
Implements any object in the game world that can be spawned or manipulated.
CreateDefaultSubobject<>()
- create a new component for an actorSetRootComponent()
- set root component// MyMeshSubobject is a class property that is of type UStaticMeshComponent
// 0 = the first material
UMaterialInstanceDynamic* MyMaterial = MyMeshSubobject->CreateDynamicMaterialInstance(0);
if(MyMaterial != nullptr) {
MyMaterial->SetScalarParameterValue(FName("MyValue"), SomeCustomValue);
}
Holds a series of events, floats, vectors or colors with associated keyframes, and uses that data to affect some actor properties.
Example class definitions. Showing how to animate the Z-axis of an Actor with a "floating" effect.
public:
UPROPERTY()
void TimelineProgress(float Value);
protected:
FTimeline CurveTimeline;
UPROPERTY(EditAnywhere, Category = "Timeline")
UCurveFloat* CurveFloat;
UPROPERTY()
FVector StartLoc;
UPROPERTY()
FVector EndLoc;
UPROPERTY(EditAnywhere, Category = "Timeline")
float ZOffset;
...
Binding delegate in BeginPlay:
if (CurveFloat) {
FOnTimelineFloat TimelineProgress;
TimelineProgress.BindUFunction(this, FName("TimelineProgress"));
CurveTimeline.AddInterpFloat(CurveFloat, TimelineProgress);
CurveTimeline.SetLooping(true);
// here, we set Start and End equal, except for Z, since that's
// the only axis we care about animating
StartLoc = EndLoc = GetActorLocation();
EndLoc.Z += ZOffset;
CurveTimeline.PlayFromStart();
}
And in the Actor Tick function...
CurveTimeline.TickTimeline(DeltaTime);
TimelineProgress function to update the parameters associated with our timeline:
FVector NewLocation = FMath::Lerp(StartLoc, EndLoc, Value);
SetActorLocation(NewLocation);
Implements a component that can be attached to an Actor. Actor components add additional functionality, and can also contain things like StaticMeshes, InstancedStaticMeshes, additional attributes for an Actor, etc.
AActor* GetOwner()
When using Instanced Static Meshes, all materials in-use by the instanced meshes must be marked as Use with Instanced Static Meshes under the Material Uses properties. Otherwise, the appropriate shaders will not be compiled and the default grid material will be used instead.
Logic that handles how a player interacts with the world.
GetWorld()
- get reference to current worldRole
- determines if we are server (ROLE_Authority
) or clientcomponent->GetComponentLocation()
- get FVector location of a child component (such as FirstPersonCameraComponent
, etc.)component->GetForwardVector()
- get normalized direction FVector of componentUAnimInstance* AnimInstance = MyMeshProp->GetAnimInstance();
// MyMeshProp is a class property pointing to a meshAnimInstance->Montage_Play(MyAnimation, 1.0f);
// MyAnimation is a class property pointing to an animationGetWorld()->GetTimerManager().SetTimer(TimerHandle, this, &AMyActor::CallbackMethod, 123.0f);
TimerHandle
is an FTimerHandle
property defined by the class123.0f
is the timeoutGetWorld()->GetTimerManager().ClearTimer(TimerHandle)
TSubclassOf<AActor> ActorToSpawn
public property to a class if we want to define the Actor class in BlueprintsSpawnActor
- spawn an actor to current world and cast it to the specified type (either AActor
or a more specific subclass)FVector Loc = FVector(1.0f, 2.0f, 3.0f);
FRotator Rot = FRotator(90.0f, 0.0f, 0.0f);
FActorSpawnParameters SpawnParams;
// SpawnActor<ActorClass>(ActorClass, FTransform, FActorSpawnParameters)
AActor* SpawnedActor = GetWorld()->SpawnActor<AActor>(ActorClass, Loc, Rot, SpawnParams);
// Spawning a specific Actor subclass (most common)
// Here, the parameters for SpawnActor include the class constructor arguments
// There are various different prototypes for this function that also include the new location,
// rotation, etc.
ASRQuadMap* MyQuadMap = GetWorld()->SpawnActor<ASRQuadMap>(ConstructorParam1, ConstructorParam2, ...);
Pawn->bUseControllerRotationYaw = false
CharacterMovement->bOrientRotationToMovement = true
SpringArmComp->bUsePawnControlRotation = true
DefaultPawnClass
to the new BP_Character (or whatever) classstatic ConstructorHelpers::FClassFinder<APawn> PlayerBPClass(TEXT("/Game/MyGame/Blueprints/BP_Character"));
if (PlayerBPClass != nullptr) {
DefaultPawnClass = PlayerBPClass;
}
GetPlayerViewPoint - gets location/rotation of player character viewpoint, useful for tracing. Gets returned in Loc
and Rot
params.
LineTraceSingleByChannel - trace a ray against the world using a specific channel, and return the first blocking hit.
FCollisionQueryParams
- create instance and pass to LineTrace param; use AddIgnoredActor()
method to set ignored actors for the line traceFHitResult
(first param). Call Cast<>(HitResult.GetActor())
to get pointer to the result, cast to the correct class. NULL/nullptr
means no hits.SweepMultiByChannel - sweep a shape against the world and return all initial overlaps using a specific channel, then return all overlapping hits and first blocking hit.
FVector Loc;
FRotator Rot;
FHitResult Hit;
TArray<FHitResult> HitActors;
float TraceDistance = 1000.0f;
// Get player controller (eg. the camera) location and rotation
// then use that to set Start and End search params for the trace
GetController()->GetPlayerViewPoint(Loc, Rot);
FVector Start = Loc;
FVector End = Start + (Rot.Vector() * TraceDistance);
// Setup the LineTrace using Visibility channel
// Result will be returned in Hit variable
FCollisionQueryParams TraceParams;
bool bHit = GetWorld()->LineTraceSingleByChannel(Hit, Start, End, ECC_Visibility, TraceParams);
// Check if anything was hit
if (bHit) {
// Return Actor that was hit
AActor* HitActor = Hit.GetActor();
// Make a sphere collision object with a radius of 200
FCollisionShape SphereCol = FCollisionShape::MakeSphere(200.0f);
// Perform a Sweep with the Sphere which is stetched between Hit.Location and Hit.Location + 0.01
// Rotation is set to quaternion identity, channel is WorldStatic
// return the result in the HitActors array
bool bSweepHit = GetWorld()->SweepMultiByChannel(HitActors, Hit.Location, Hit.Location + FVector(0.01f, 0.01f, 0.01f), FQuat::Identity, ECC_WorldStatic, SphereCol);
if (bSweepHit) {
for (auto& ThisHit : HitActors) {
UStaticMeshComponent* MeshComp = Cast<UStaticMeshComponent>(ThisHit.GetActor()->GetRootComponent());
if (MeshComp) {
...
}
}
}
}
A class/asset that determines how to move/shake a camera over time, either via animations or math functions (eg. sinusoidal).
TSubclassOf<>
- property that references another class or Blueprint, that is a child of the templated classUPROPERTY(EditAnywhere, Category = "Assets")
TSubclassOf<class AZinger> ZingerBP;
Use Window > Developer Tools > Output Log to view the logs from within the Editor.
// UE_LOG(CategoryName, Verbosity, Format, __VA_ARGS__)
UE_LOG(LogTemp, Warning, TEXT("Wow, that was great %s!"), PlayerName);
// AddOnScreenDebugMessage(Key, TimeToDisplay, DisplayColor, DebugMessage)
GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Orange, TEXT("Hello, world!"));
If Key
is -1
, then a new message will be written, trying not to override existing messages. Otherwise, if a specific key is used, that message can be updated with a subsequent function call.
Inside of Character class:
// DrawDebugSphere(GetWorld(), Location, Radius, Segments, FColor, bPersistent, LifeTime);
DrawDebugSphere(GetWorld(), Hit.Location, 200.0f, 32, FColor::Orange, false, 2.0f);
UPROPERTY(Server, Reliable)
UPROPERTY(ReplicatedUsing=myReplicationMethod)
UMG
is added to PublicDeps; Slate
and SlateCore
to PrivateDeps in .Build.csPublicDependencyModuleNames
PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
API Documentation: Interfaces in C++
UE4 Docs: Using Blueprint Interfaces
Used to facilitate safe and efficient communication between classes/objects (typically between various types of Actors or Pawns). The ideal way to exchange information or query objects of potentially unknown classes, since no casting is required.
The Interface just defines the function names, inputs, and return values. It does not actually implement any code. The code is written in the classes that implement (eg. use/include) the Interface.
UInterface
child class is empty (other than the UINTERFACE()
reflection macro) and is only used by UE's reflection systemIInterface
child class contains the functions that the interface should provideMyInteraction(AActor* YourActor)
MyInteraction_Implementation(AActor* YourActor)
UFUNCTION()
params for utilization in Blueprints: (BlueprintNativeEvent, BlueprintCallable)
UFUNCTION()
reflection macroUCLASS(Blueprintable)
class ASuperDuperMissile : public AActor, public IMyInterface
{
GENERATED_BODY()
...
public:
virtual bool ReactToTrigger() override;
}
bool ASuperDuperMissile::ReactToTrigger()
{
// do stuff here
return true;
}
Collision Setup Docs
Collision How-TosAPI Docs:
OnOverlapBegin function
Mesh->OnComponentBeginOverlap.AddDynamic(this, &WhateverClass::OnOverlapBegin)
BeginPlay()
instead of class constructorAPI Docs:
AddImpulse
AddRadialImpulse
AddForce
Moveable
and that bSimulatePhysics
is enabled for any component that will have physics applied to itMeshComp->AddImpulse(FVector Impulse, bVelChange=false)
- activate a physics impulse from an object in direction of Impulse
vector. If bVelChange
is true, then the velocity is changed by Impulse, without taking mass into account.MeshComp->AddRadialImpulse(FVector Origin, float Radius, float Strength, ERadialImpulseFalloff Falloff, bVelChange=false)
- activate a physics impulse from an Origin point eminating radially with a specified Radius and Strength, interpolated with FalloffMeshComp->AddForce(FVector Force)
- apply a force to a rigid body, which will continue indefintely until changedDocs:
Landscapes
Technical Guide
Using Custom Heightmaps and Layers
Landscape Materials
Foliage
Ensure landscape resolution is compatible with UE4
Heightmap export
Texture data export (Heatmap)
UE4 Import
Create a new Landscape Material
Create an instance of the Landscape Material to use for the Landscape
In the Layer setup, add all of the Layers, then right-click and Import from File to bring in the heatmap alpha map for that layer
Similar to normal instructions above, but instead of ensuring the overall mapsize has the correct terrain dimensions, we need to ensure each submap has the correct dimensions. Example: 4x tiles @ 505x505 = 2020x2020 total landscape size in WC2 (where 505x505 is once of the acceptible UE4 Landscape dimensions)
Hightmap export settings
Texture data export (Heatmap)
UE4 Import
Creating custom collision mesh objects is necessary for any large non-convex meshes that the player will need to interact with (eg. the mesh has interior corners, holes, etc.). Examples: overhanging lamp post, archway, door frame, etc.
To add a custom Simple Collision mesh to an asset, create additional objects in Blender that have the same name as the original object, but have one of the prefixes (and optional numeric suffixes) below. For example, to create collision bodies for an archway, you might create 3 different box meshes-- UBX_Archway_00
, UBX_Archway_01
, and UBX_Archway_02
. When exporting with FBX, be sure to select the original object and all collision and related objects. UE4 will correctly set them up during the import process.
UBX_xxx_##
- Box meshesUCP_xxx_##
- Capsule meshesUSP_xxx_##
- Sphere meshesUCX_xxx_##
- Convex meshAfter import, open the object in Asset Editor and view the Simple Collision mesh to ensure it imported everything correctly.
Capture and profile draw calls from the next frame, and immediately open a GPU Visualizer window with the results. If the r.*
values below are also set, then per-material time estimations are also performed.
r.rhicmdbypass 1
r.rhithread.enable 0
r.showmaterialdrawevents -1
profilegpu
MyGame.Build.cs
or MyModule.Build.cs
) by adding a new function to setup your external libraries and includes. Use the Target.Platform
property to determine the current target platform.string PlatformString = "";
if(Target.Platform == UnrealTargetPlatform.Win64) PlatformString = "win64";
// ...
// LibraryBasePath is the local path to your library binaries
PublicAdditionalLibraries.Add(Path.Combine(LibraryBasePath, PlatformString, "fastwfc.lib"));
PublicAdditionalLibraries.Add(Path.Combine(LibraryBasePath, PlatformString, "lua53.lib"));
PublicIncludePaths.Add(LuaIncludePath);
PublicIncludePaths.Add(FastWFCIncludePath);
.dll
, .so
, etc.) should reside in your project's Binaries/$PLATFORM
directory, otherwise your game/module will fail to load (eg. game fails to launch or hot-reload will fail). Check the Output Log for details.Important: When compiling with MSVC, external static libraries also built with MSVC must be built with the
/MD
(or/MDd
) flag or linking will fail! You can double-check your libraries by runningdumpbin /all mylibrary.lib | grep MD_Dynamic
, which should return some matching lines). This does not apply to external libraries built with clang or gcc.
More info: Unreal Wiki - Linking Static Libraries
MyGame.Build.cs
), in the main constructor, add the following after the PCHUsage
setting:CppStandard = CppStandardVersion.Cpp17;