See our new Wiki!

This wiki is in legacy mode. Check our new wiki here!

Videogames UE4 Development

UE4 and Git-LFS

We have a project setup right here on GitHub.

UE4 C++

Crash course: Converting Blueprints to C++. Documentation: Gameplay Architecture.

Common includes

Class #include
UWorld Engine/World.h
AActor GameFramework/Actor.h
UActorComponent Components/ActorComponent.h
USceneComponent Components/SceneComponent.h
UGameplayStatics Engine/World.h
UKismetSystemLibrary Kismet/GameplayStatics.h
UKismetMathLibrary* Kismet/KismetMathLibrary.h
FMath Math/UnrealMathUtility.h
UPhysicsHandleComponent PhysicsEngine/PhysicsHandleComponent.h
  • (*) KismetMath is usually a wrapper to FMath. Review implementation and try to call directly FMath.

Mapping types

Blueprint C++
String FString
Name FName
Vector FVector
Rotator FRotator
Transform FTransform
Object UObject*
Actor AActor*
ActorComponent UActorComponent*
Float float
- double
Integer int32
- uint32
Integer64 int64
- uint64
Bool bool

Properties Visibility

  • Blueprint:
    • BlueprintReadonly
    • BlueprintReadWrite
  • Defaults and instance:
    • VisibleAnywhere
    • EditAnywhere
  • Only defaults:
    • VisibleDefaultsOnly
    • EditDefaultsOnly
  • Only instance:
    • VisibleInstanceOnly
    • EditInstanceOnly

Tips

  • You can create C++ files either manually or using the UE4 editor, first case requires to regenerate project files (left click on .uproject Generate Visual Studio Project Files).
  • After syncing files with Git, it’s a good idea to regenerate project files.
  • If Hot reloading doesn’t seem to take your changes, close editor and Rebuild project.
  • How to found BP nodes? Put your mouse over the node, see target and try to lookup for the file and lastly search for some keyword on the function name. For example:

    UE4 find Blueprint nodes on C++

Useful tools

To clone your Azure repos with Github Desktop follow this guide.

Struct template

Sample UE4 C++ Struct (note F prefix):

// MyStruct.h
#pragma once
#include "MyStruct.generated.h"

USTRUCT(BlueprintType)
struct FMyStruct
{
	GENERATED_BODY()
	
	UPROPERTY(BlueprintReadOnly)
        AActor* Character;	

	FMyStruct();
};

// MyStruct.cpp
FMyStruct::FMyStruct()
{
	Character = nullptr;
}

Enum template

Sample UE4 C++ enum.

#pragma once
#include "Enums.generated.h"

UENUM(BlueprintType)
enum class EDirection : uint8
{
    Left UMETA(DisplayName = "Left"),
    Right UMETA(DisplayName = "Right"),
    Front UMETA(DisplayName = "Front"),
    Back UMETA(DisplayName = "Back")
};

// You can add more enums here...

Interfaces

Sample interface:

#pragma once

#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "MyInterface.generated.h"

// This class does not need to be modified.
UINTERFACE()
class UMyInterface : public UInterface
{
	GENERATED_BODY()
};

/**
 * 
 */
class YOURPROJECT_API IMyInterface
{
	GENERATED_BODY()

public:
	UFUNCTION(BlueprintNativeEvent)
	void YourMethod();
};

To use it:

// Class that implements the interface
UCLASS()
class YOURPROJECT_API AMyCharacter : public AActor, public IMyInterface
{
    GENERATED_BODY()
public:
    virtual void YourMethod_Implementation() override;
}


// To use the interface from another function
if (AnActor->Implements<UMyInterface>())
{
    IOHActionEntity::Execute_YourMethod(AnActor);
}

More info here.

Delegate samples

/* DECLARATION */
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FCompletedQuestSignature, int32, index)

UPROPERTY(BlueprintAssignable, BlueprintCallable)
FCompletedQuestSignature CompletedQuest;

/* BROADCAST */
CompletedQuest.Broadcast(parameter);

/* SUBSCRIBE */
UFUNCTION() // Required for dynamic
void FunctionHandler(int32 index)

CompletedQuest.AddDynamic(this, &Class::FunctionHandler);
CompletedQuest.Add // For non dynamic version

NOTE: Dynamic delegates can be serialized, their functions can be found by name, and they are slower than regular delegates. More info

Vector samples

Forward unit vector from a given rotation.

GetComponentRotation().Vector()

Calculate vector of size MaxDistance starting at actor/component location on the same rotation as the actor/component.

FVector UClass::GetMaxGrabLocation() const
{
        // GetComponentLocation or GetLocation depending if you're on an Actor or Component
        // same with Rotation
	return GetComponentLocation() + GetComponentRotation().Vector() * MaxDistance;
}

Linetracing samples

Complete custom sample:

// Single by channel
FHitResult HitResult;
if (GetWorld()->LineTraceSingleByChannel(HitResult, Start, End, ECC_Visibility))
{
    // Handle hit!
}

// Linetrace for ECC_PhysicsBody or ECC_WorldDynamic
FHitResult OutHit;
if(GetWorld()->LineTraceSingleByObjectType(
   OutHit, Start, End, FCollisionObjectQueryParams(ECC_TO_BITFIELD(ECollisionChannel::ECC_PhysicsBody) | ECC_TO_BITFIELD(ECollisionChannel::ECC_WorldDynamic)))) {
    // Handle hit!
}

Using Kismet (you can open its implementation to see more samples):

// LineTraceSingle or LineTraceMulti
if (UKismetSystemLibrary::LineTraceSingle(
    WorldContextObject, StartLocation, EndLocation,
    UEngineTypes::ConvertToTraceType(ECC_Visibility), false, TArray<AActor*>(),
    EDrawDebugTrace::ForOneFrame, OutHitResult, true))
{
    // Handle hit(s)!
}

Sweep samples

Complete custom sample:

// Params with ignore self
FCollisionQueryParams TraceParams(FName("SphereTrace"), false, GetOwner());
FHitResult OutHit;

// Sweep for ECC_PhysicsBody or ECC_WorldDynamic (SweepSingle or SweepMulti)
if (GetWorld()->SweepSingleByObjectType(
    OutHit, GetComponentLocation(), GetMaxGrabLocation(), FQuat::Identity,
    FCollisionObjectQueryParams(ECC_TO_BITFIELD(ECollisionChannel::ECC_PhysicsBody) | ECC_TO_BITFIELD(ECollisionChannel::ECC_WorldDynamic)), 
    FCollisionShape::MakeSphere(GrabRadius), TraceParams)) 
{
    // Handle hit!
}

Using Kismet (you can open its implementation to see more samples):

// SphereTraceSingle or SphereTraceMulti 
if (UKismetSystemLibrary::SphereTraceMulti(this, CameraComponent->GetComponentLocation(), GetActorLocation(),
    Radius, UEngineTypes::ConvertToTraceType(ECC_Visibility), false,
    TArray<AActor*>(), EDrawDebugTrace::ForOneFrame, OutHits, true)
{
    // Handle hit(s)!
}

Anim notifiers C++

 UCLASS()
 class YOURPROJECT_API UAnimNotify_Name : public UAnimNotify
 {
     GENERATED_BODY()
        
 protected:

     virtual void Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation) override;        
 };
    
 void UAnimNotify_Name::Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation)
 {
     Super::Notify(MeshComp, Animation);

     // YOUR CODE GOES HERE
 }

More info.

Anim instance C++

  • UE4 Animation system:
UCLASS()
class YOURPROJECT_API UCharacterAnimInstance : public UAnimInstance
{
	GENERATED_BODY()

public:
	UCharacterAnimInstance();

	UPROPERTY(EditDefaultsOnly)
	float MinWalkSpeed;
}
  • Pixel2d:
UCLASS()
class YOURPROJECT_API UCharacterAnimInstance : public UPixel2DAnimInstance
{
	GENERATED_BODY()

public:
	UCharacterAnimInstance();

	UPROPERTY(EditDefaultsOnly)
	float MinWalkSpeed;
}

BoxCollider

// .h
class CLASS_API AMyClass : public AActor
{
....
private:
	UPROPERTY(BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
	UBoxComponent* BoxCollider;
protected:
        virtual void BeginPlay() override;
public:
        UFUNCTION()
        void BeginOverlapBoxCollider(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult);

	UFUNCTION()
        void EndOverlapBoxCollider(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);

...
}

// .cpp
AMyClass::AMyClass()
{
	BoxCollider= CreateDefaultSubobject<UBoxComponent>(TEXT("BoxCollider"));
	BoxCollider->SetCollisionProfileName(TEXT("Custom"));
	// TODO: Set channel (if nedeed): BoxCollision->SetCollisionObjectType(ECC_Visibility);
        // TODO: Set size:
	BoxCollider->SetBoxExtent(FVector(10, 10, 10));
	BoxCollider->SetRelativeTransform(FTransform(FRotator::ZeroRotator, FVector(0, 0, 10), FVector(1, 1, 1)));
        // TODO: Customize collision config
	BoxCollider->SetCollisionResponseToAllChannels(ECR_Ignore);
	BoxCollider->SetCollisionEnabled(ECollisionEnabled::NoCollision);
	BoxCollider->SetCollisionResponseToChannel(ECC_Pawn, ECR_Overlap);
	BoxCollider->SetCollisionResponseToChannel(ECC_Visibility, ECR_Overlap);
	BoxCollider->SetGenerateOverlapEvents(true);
	BoxCollider->SetupAttachment(RootComponent);
}

void AMyClass::BeginPlay()
{
	Super::BeginPlay();

	BoxCollider->OnComponentBeginOverlap.AddDynamic(this, &AMyClass::BeginOverlapBoxCollider);
	BoxCollider->OnComponentEndOverlap.AddDynamic(this, &AMyClass::EndOverlapBoxCollider);
}

void AMyClass::BeginOverlapBoxCollider(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
	UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	// YOUR CODE GOES HERE
}

void AMyClass::EndOverlapBoxCollider(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
	UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
	// YOUR CODE GOES HERE
}

Billboards (editor icons)

// .h
class CLASS_API AMyClass : public AActor
{
....
private:
#if WITH_EDITORONLY_DATA
	/** Editor Billboard */
	UPROPERTY()
	UBillboardComponent* BillboardComponent;
#endif
....

// .cpp
AMyClass::AMyClass()
{
  USceneComponent* SceneComponent = CreateDefaultSubobject<USceneComponent>(TEXT("SceneComp"));
  RootComponent = SceneComponent;
  RootComponent->Mobility = EComponentMobility::Static; // Or movable

  #if WITH_EDITORONLY_DATA
  BillboardComponent = CreateEditorOnlyDefaultSubobject<UBillboardComponent>(TEXT("Sprite"));
  if (BillboardComponent)
  {
	BillboardComponent->SetWorldTransform(
		FTransform(FRotator::ZeroRotator, FVector::ZeroVector, FVector::OneVector * 4)
	);
	BillboardComponent->Sprite = ConstructorHelpers::FObjectFinderOptional<UTexture2D>(TEXT("/PATH/TO-TEXTURE")).Get();
		BillboardComponent->SetupAttachment(RootComponent);
  }
  #endif
}

UE4 Plugins

UE4 Audio

Reverb

To activate the reverb, add the following line to your project /Config/DefaultEngine.ini:

[Audio] 
UseAudioMixer=true

Create a Sound > Sound Attenuation asset and configure it on your Cue as the attenuation preset. Add an Audio Volume to your level, set it big enough to cover your playable area and set the following properties:

  • Settings -> Apply Reverb: True.
  • Settings -> Reverb effect: select one from the dropdown.

  • For more info check this video Reverb Tutorial. Note that if you added the configuration to your project .ini, you won’t need to execute additional commands on the UE4 console.

UE4 Animation

Documentation: Animation

UE4 AI

Official docs

  • To enable the debugger set a key binding in Project Settings > Engine - Gameplay Debbuger > Activation Key. If you’re using a non default US keyboard or a keyboard with international bindings, it is recommended to set a plain key as Asterisk (*) or Minus (-), instead of something like an Apostrophe (‘) that won’t be triggered by a single key-press on a US-International setup.
  • RecastNavMesh: update some navmesh settings on the scene. Also update-able from the project settings window searching for the option Agent (you can add support for multiple types of agents from here).

  • Navmesh modifier volume: Adds additional information to the navmesh. Exmample: high cost areas, not allowed areas, etc.

  • To disable Auto-updates: Editor Preferences -> Level Editor -> Misc -> Update Navigation Automatically.

  • More info: Official docs

AI Perception

Official docs

Behavior trees

Official docs

  • Quick Start Guide

  • Nodes: Official reference

    • Composite Nodes: These are the nodes that define the root of a branch and the base rules for how that branch is executed.
    • Task Nodes: These are the leaves of the Behavior Tree, these nodes are the actionable things to do and don’t have an output connection.
    • Decorator Nodes: Also known as conditionals. These attach to another node and make decisions on whether or not a branch in the tree, or even a single node, can be executed.
    • Service Nodes: These attach to Composite nodes, and will execute at their defined frequency as long as their branch is being executed. These are often used to make checks and to update the Blackboard. These take the place of traditional Parallel nodes in other Behavior Tree systems.

Environment Query System (EQS)

Official Docs

UE4 AI movement C++

See this tutorial: https://www.vikram.codes/blog/ai/01-basic-navigation Improved and updated code to seek for a Random Reachable Location in the Navmesh:

  • MovementAIController.h
  • MovementAIController.cpp
  • Don’t forget to add the NavigationSystem and AIModule modules in your {project}.Build.cs. More info: it would be suffice to add “NavigationSystem” and “AIModule” strings to the PublicDependencyModuleNames.AddRange(…) parameters.

How to do it?

  • Convert Mouse Location to World Space: Interact with 3D objects using players’ mouse. See video
  • Reducing Packaged Game Size: See here

Equilaterus (CC-BY) 2018 - 2022.