Here you'll find anything from defining classes or doing things within classes (classes for Actors & Components).
Here you'll find various pointer types that you can use in Unreal Engine.
If you need a TMap to be initialized with certain values, here is how to do it:
TMap <int32, FString> StringMap
{
{1, "Name 1"},
{2, "Name 2"},
{3, "Name 3"}
};
Bonus: if you use a Struct as Value, here a small example:
TMap <FString, FMyStruct> StructMap // FMyStruct contains: Enemy Max Health, Basic Damage, Attack Speed (all int32).
{
{"Enemy 1", {25, 4, 7}},
{"Enemy 2", {30, 2, 9}},
{"Enemy 3", {100, 3, 3}},
};
As a point of reference, the difference between Unreals' TMap and std::map in C++ are:
TMap uses a hash table to store and retrieve the elements, while std::map uses a balanced binary search tree (usually a red-black tree).
TMap does not preserve the order of the elements, while std::map sorts the elements by their keys according to a comparison function.
TMap requires the elements to be hashable and comparable, while std::map only requires the keys to be comparable.
TMap has faster lookup and membership testing, while std::map has faster traversal and iteration.
TMap has a template parameter for the allocator, which controls the memory allocation behavior, while std::map has a template parameter for the key comparison function, which defines the order of the elements.
TMap is NOT a linked list, as in: it does not store the address for the previous and or next entry.
To loop through a TMap, here an example:
TMap <int32, FVector> MyTmap;
for (const auto& MapElement : MyTmap)
{
const int32 NewInt = MapElement.Key; // access Key and assign
const FVector NewVector = Map.Value; // acces Value and assign
}
The const part doesn't really do anything, it just shows how to access the Key and Value of the TMap with MapElement.Key und MapElement.Value.
Not yet fully tested!
In order to create TArrays from a TMap, use the following:
TMap <AActor*, int32> MyTmap; // TMap to be used
TArray<AACtor*> KeyArray; // Inizialized array
MyTmap.GenerateKeyArray(ActorArray); // Uses KeyArray Reference to fill
TArray<int32> ValueArray;
MyTmap.GenerateValueArray(ValueArray);
If you need a TSet to be initialized with certain values, here is how to do it:
TSet<int64*> PowerOfTwos {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192};
As you can see it's identical to a TArray.
As a good point of reference, the differences between a TSet and a std::list in C++ are:
TSet does not allow duplicate elements, while std::list does.
TSet does not preserve the order of the elements, while std::list does.
TSet requires the elements to be hashable and comparable, while std::list does not.
TSet has faster lookup and membership testing, while std::list has faster traversal and iteration.
It's as simple as a for loop for a regular TArray:
TSet<AActor*> ActorSet {...}; // define Set
for (auto Actor : ActorSet) // instead of auto, AActor* would also work just fine (this example)
{
Actor->GetName(); // anything you want to do
}
An example for a function that converts a TSet to an Array:
static TArray<AActor*> ConvertSetToArray(TSet<AActor*> Set)
{
TArray<AActor*> Array = Set.Array(); //alternatively auto can be used as a variable type (untested)
return Array;
}
If using some Unreal Enums like for example "EDrawDebugTrace", simply using them as a variable type does not work (source).
If you get an error, the following example will work properly:
TEnumAsByte<EDrawDebugTrace::Type> EnumVariableName;
If you have a C++ Enum as an input for a function, to get its name use:
FString EnumName = UEnum::GetValueAsString(EnumInput);
Important: this will return the full string, for example:" EValue::String1"!
To fix this, you can use the following AS AN EXAMPLE:
const FString StringValueRaw = UEnum::GetValueAsString(ViewMode);
FString Left;
FString Right;
StringValueRaw.Split("::", &Left, &Right, ESearchCase::IgnoreCase, ESearchDir::FromStart);
Now Right is the value itself.
As an example on how to create a UStruct, simply create a new source file (.h) and copy-paste the following as an example:
#pragma once
#include "FMyVectorInt4D.generated.h"
USTRUCT(BlueprintType, Category = "MyCategory")
struct FMyVectorInt4D
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadWrite) int64 X;
UPROPERTY(BlueprintReadWrite) int64 Y;
UPROPERTY(BlueprintReadWrite) int64 Z;
UPROPERTY(BlueprintReadWrite) int64 W;
};
This example is used to create a 4D Vector based on 4 64 bit integers. It can be used on C++ and Blueprints.
A simple caviat: If you want to use it as an exposed value for a Blueprint, you need to add "EditAnywhere" besides "BlueprintReadWrite".
Now the above is working okay, but we can't simply just say something like MyVectorInt4D = FMyVectorInt4D(1,2,3,4).
To make that possible, we need to create two constructors in general: one that uses default values, and one that can easily be filled with values.
Use the above, but add the following lines of code before the variable definitions
FMyVectorInt4D() // Default constructor
{
X = 0;
Y = 0;
Z = 0;
W = 0;
}
FMyVectorInt4D(int64 InX, int64 InY, int64 InZ, int64 InW) // Constructor with all values
{
X = InX;
Y = InY;
Z = InZ;
W = InW;
}
As a bonus, you could also create a constructor to take in one value and assign it to all variables:
FMyVectorInt4D(int64 InXYZW)
{
X = InXYZW;
Y = InXYZW;
Z = InXYZW;
W = InXYZW;
}
Also: you don't need to use FORCEINLINE or explicit FORCEINLINE to make it work. UStruct seems to handle that on its own.
Strong Object Pointers (TStrongObjectPtr<> Name) are perfect for UObjects not flagged by UPROPERTY() to be handled automatically by the Unreal Engine garbage collection. Or in other words: if you want to simply use a pointer without UPROPERTY() or make a fixed sized array, use TStrongObjectPtr to let Unreal handle the garbage collection of UObjects. For regular types like int, float etc. TSharedPtr are the better option.
Examples:
// New ptr managed by Unreal, C++ only.
TStrongObjectPtr<USceneComponent> MyStrongObjectPtr;
// Fixed sized Array that can't use "UPROPERTY()",
// but still needs to be garbage collected when out of scope.
TArray<TStrongObjectPtr<USceneComponent>, TInlineAllocator<16>> MyStrongObjectFixedSizeArray;
// Adding to a fixed size Array with TStrongObjectPtr
USceneComponent* MyRawPointer {};
MyStrongObjectFixedSizeArray.Add(TStrongObjectPtr(MyRawPointer)); // using Constructor
Unique Pointers (TUniquePtr<> Name) are awesome to make sure, that a memory address to for example an Object can only be owned by one pointer. This can help making sure there is, for example, only one Actor who can currently own a component.
Here are the basics:
They cannot easily be shared or be used as a function input.
They can not be made a UPROPERTY().
They can be initialized to {nullptr} / = nullptr
To male another TUniquePtr on an address, they ownership has to be switched
If .Reset() is used to take ownership of another pointer, the pointer won't automatically be set to a nullptr!
Once out of scope, the TUniquePtr will destroy what points to (Actor etc.).
Extremely important: make use of Release, also on EndPlay, cause some destructors may otherwise crash the game/engine!
Examples:
TUniquePtr<UWorld> MyWorldUnique (GEngine->GameViewport->GetWorld()); // UniquePtr from a RawPtr
TUniquePtr<int64> MyUniquePtr1 = MakeUnique<int64>(65); // UniquePtr from a value
TUniquePtr<int64> MyUniquePtr2 = MoveTemp(MyUniquePtr1); // Moving Ownership from Ptr1 to Ptr2, // Ptr1 now nullptr
TUniquePtr<AActor> MyUnuiqueActor {}; // Define a UniquePointer to store another pointer in.
MyUnuiqueActor.Reset(OtherActor); // Move other Actor to the Unique Pointer.
// Other Pointer will be set to nullptr.
MyUniqueActor.Reset(); // Destroy AActor if withing scope.
MyUniqueActor.Release(); // Release Ownership ans set MyUniqueActor to nullptr.
MyUniqueActor.Get(); // Get pointer to the Object without moving ownership.
How to safely use TUniquePtr.:
1a. If used as a object-variable: TUniquePtr<AActor> MyActor;
1b: If used within scope: same as above.
2: Transfering ownership of another Pointer MyActor.Reset(OtherActor);
3: Now you can make use of it however you see fit (some actions may require MyActor.Get())
4: You could also move ownership to another TUniquePointer using MoveTemp(MyActor)
5a: If using a TUniquePtr to a Component attached to an AActor, use MyActor.Release() before using any Destroy command!
5b: To avoid crashing the editor when exiting the game, make sure to add MyActor.Release() to the EndPlay Event!
A few examples of the usage. Also, a great tutorial on C++ Unique, Shared and Weak Pointers.
TSharedPtr<UWorld> MyWorldShared (GEngine->GameViewport->GetWorld()); // SharedPtr from a RawPtr
TSharedPtr<int64> MySharedPtr1 = MakeShared<int64>(64); // SharedPtr from a value
TWeakPtr<UWorld> MyWorldWeak = MyWorldShared; // WeakPtr from SharedPtr
TWeakPtr<int64> MyWeakPtr1 = MySharedPtr1; // WeakPtr from SharedPtr
int64* MyInt64Ptr1 = MySharedPtr1.Get(); // Get RawPtr from SharedPtr
int64* MyInt64Ptr2 = MyUniquePtr2.Get(); // Get RawPtr from UniquePtr MyUniquePtr2.Release(); // Release memory of the UniquePtr
// MyUniquePtr2 now nullptr
TObjectPtr<UWorld> MyWorldObject = GEngine->GameViewport->GetWorld(); // Get ObjectPtr from RawPtr
To make sure, an Object is only loaded into memory, when needed, TSoftPtr are the best solution. By either loading them synchronously or asynchronously the will only be loaded when required. Hint: you can load them as often as you want, because if they're already in memory, Unreal will just return the already loaded object.
Example: We will try to get the location of an Actor in the World.
// Hard Reference/Hard Pointer
AActor* LocationActorRef;
// Soft Reference/Soft Pointer
TSoftObjectReference<AActor> LocationActorSoftRef;
// Function for Hard Reference
FVector GetActorLocationHardRef()
{
return LocationActorRef->GetActorLocation();
}
// Function for Sync Soft Reference
FVector GetActorLocationSoftRefSync()
{
AActor* LocationActorRef = LocationActorRef.LoadSynchronous();
return LocationActorRef->GetActorLocation();
}
// Function for Async Soft Reference (WORK IN PROGRESS)
void GetActorLocationSoftRefAsync()
{
auto Handle1 = UAssetManager::GetStreamableManager().RequestAsyncLoad(
LocationActorSoftRef.ToSoftObjectPath(),
FStreamableDelegate::CreateUObject(this, &ThisClass::UseAsyncLocation));
}
void UseAsyncLocation(FVector Location)
{
AActor* LocationActorRef = LocationActorSoftRef.Get();
FVector Location = LocationActorRef->GetActorLocation();
// Do something with the Location...
}
Now imagine, you want to set a Soft Object Reference from a Hard Reference, the following is a good example on how to achieve this:
AActor* HardObjectPtr = this;
TSoftObjectPtr<AActor> SoftObjectPtr(HardObjectPtr);