Usage of Asynchronous and Threaded Functions in Unreal C++.
Takes a while to get used to and can be rather frustrating without any prior knowledge.
The two important things for Logging are:
UE_LOG(LogTemp, Warning, TEXT("Message")); // logs to the console
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("Message"))); // prints message on screen
A good ressource (not including all edge cases) can be found HERE.
This is an example on how to get a Scene Component and than cast to it (cause we know it's a camera) to get its information.
In this case: we are a Scene Component attached to another Scene Component, which we know is a camera.
USceneComponent* ParentComponent = this->GetAttachParent();
const UCameraComponent* ParentCamera = Cast<UCameraComponent>(ParentComponent);
Additionally, the regular C++ style casting works as well. Here an example to go from a float to an int.
float FloatValue = 42.f;
int32 IntegerValue = static_cast<int32>(FloatValue);
Sometimes a static function requires a UWorld reference, like for example printing text to the screen, line-traces etc.
UWorld* World = GEngine->GameViewport->GetWorld();
If you need to get Components from an Actor, use the following:
TArray<USceneComponents*> Components;
this->GetComponents(Components);
The GetComponents() function will automatically get the correct Class and filter by it.
If in the World you need to find a single Actor by Class, use the following:
ACPPA_Unit* SingleUnit =
Cast<ACPPA_Unit>(UGameplayStatics::GetActorOfClass(GetWorld(), ACPPA_Unit::StaticClass()));
Since the GetActorOfClass function already directly returns an AActor*, we can cast directly to our desired class.
If in the World you need to find all Actors by Class, use the following:
TArray<AActor*> FoundActors;
UGameplayStatics::GetAllActorsOfClass(GetWorld(), ACPPA_Unit::StaticClass(), FoundActors);
for (auto &Unit : FoundActors)
Cast<ACPPA_Unit>(Unit)->AlignSplineToFloor(); // do stuff with the unit, the cast is required for direct access
The downside here is that you first get all actors as AActor, hence you do have to cast to the desired actor to access them directly.
If you need an array of the correct type, you have to loop through the AActor array and cast to your type and then add them...
Hence: it's okay in some regars, but the method below is the better solution in general.
The fastest and best way however to get all actors of a class is to make use of the "TActorIterator".
TArray<ACPPA_Unit*> Units;
for (TActorIterator<ACPPA_Unit> Unit(GetWorld()); Unit; ++Unit)
{
ACPPA_Unit* UnitPtr = *Unit; // this is required to get the actor from the iterator
Units.Add(UnitPtr); // fill your array if needed
// do stuff with UnitPtr
}
This is fast and you directly get the required actor without any casting.
Idea: you could use this for GetActorOfClass, by just saving the first actor of the loop and then break it (untested, give it a shot 😉)
How to get the GameTime in seconds since BeginPlay:
double CurrentGameTime = GEngine->GameViewport->GetWorld()->GetTimeSeconds(); // get the game time
To start an executable within the Project/Game folder:
const FString RelativePath = FPaths::GameSourceDir() + "MyExecutable.exe";
const bool FileExists = FPaths::FileExists(RelativePath);
FString FullPath = IFileManager::Get().ConvertToAbsolutePathForExternalAppForRead(*RelativePath);
const TCHAR* ProcPath = *RelativePath;
if (FileExists)
{
auto CommProc = FPlatformProcess::CreateProc
(
(ProcPath),
TEXT(""),
true,
false,
false,
nullptr,
0,
nullptr,
nullptr
);
}
To quit the executable (may not work, not yet sure why):
TerminateProc(CommProc);
If you want to edit values of variables directly in C++ using references from Blueprint, use the following as an example:
UFunction(BlueprintCallable)
static void EditInt(UPARAM(ref) int& EditorInt);
Now if you change the variable in C++, it'll also change the variable in Blueprint, because it's using a reference as input.
The important part here is:
UPARAM(ref)
before the Variable Reference.
If you use it without that line, it'll be shown as an output-line in Blueprint.
If you want to declare one of your UFunctions as deprecated, use the following metadata specifiers:
UFunction(
meta = (DeprecatedFunction, DeprecationMessage = "Insert reason why it's deprecated and what to do."))
Info: BlueprintCallable, Tooltip etc. have been left out in this example. Please do not forget about them. ;-)
If you want the return value within a function to be named, instead of it just being displayed as return value:
UFunction(
meta = (ReturnDisplayName = "Delay"))
Now your return value will be displayed as "Delay" for the output pin. Important: really only does work for functions with an actual return value, that are not void!
There is a pretty nifty way to add a true and false exec pin to any UFUNCTION.
In this example we put in a pointer to an AActor and check, if it is valid and does not point to a nullptr.
Now to add the exec pins:
//.h
UFUNCTION(BlueprintCallable, meta = (ExpandBoolAsExecs = "IsValid"))
static void IsActorValid(AActor* Actor, bool& IsValid);
Now for the cpp file:
//.cpp
void AYourClass::IsActorValid(AActor* Actor, bool& IsValid)
{
if (Actor != nullptr)
IsValid = true;
else IsValid = false;
}
As soon as you define the IsValid, the execution pin in Blueprint will be triggered. This way you don't need to use a Branch or any other comparison, since it's already in here.
Example:
// .h
UFUNCTION((BlueprintImplementableEvent, BlueprintCallable, Category = "MyCategory")
void DoStuff();
This type of event/function is basically the same, as if you were to add a Custom Event via Blueprint.
To use it within Blueprint, simply right click and search for it. Voila!
But why use this instead? Well, in C++ it can easier be handled, categorized and called via C++ as well.
Example, if you want a Custom event to use a Variable.
UFUNCTION((BlueprintImplementableEvent, BlueprintCallable, Category = "MyCategory")
void DoStuff(int32);
Compared to other Variables, FString won't work out of the box. Long story short: to make it work, use the following:
UFUNCTION((BlueprintImplementableEvent, BlueprintCallable, Category = "MyCategory")
void DoStuff(const FString &MyString);
Example:
// .h
FLinearColor RandomColor; // Define Random Color
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, CallInEditor, Category = "MyCategory")
void RandomColor();
// .cpp
void AMyClass::RandomColor_Implementation()
{
RandomColor = FLinearColor(
UKismetMathLibrary::RandomFloat(),
UKismetMathLibrary::RandomFloat(),
UKismetMathLibrary::RandomFloat(),
1.f);
}
This type of event/function will be displayed as a Button in the Details Panel of the Actor.
On click, it will do something: here create a random color (not used in this example).
Important: BlueprintNativeEvent will require it to be defined in C++, as of what to do when pressed (hence the .cpp file above).
If however you want it to be a Custom Event that can be used in Blueprint Graphs, use "BlueprintImplementableEvent" instead of "BlueprintNativeEvent". It then also won't require a definition in the .cpp file.
virtual void OnConstruction(const FTransform& Transform) override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
In your .h file, right click anywhere: "Show Context Actions"/"Generate Code..."/"Overriding Members".
With "Ctrl + F" search for what you need (or scroll down), select box and click "OK".
What templates are in C++ is a bit too much to cover here, but as an example on how to use typename templates, here's a good example.
Lets say, you created a fixed size TArray and want to call a function, that returns its length, that should then be printed to the screen:
TArray<TObjectPtr<AActor>, TFixedAllocator<16>> MyFixedArray {nullptr, nullptr, nullptr};
GEngine->AddOnScreenDebugMessage(
-1, 10.f, FColor::Red, FString(
"Length: " + FString::FromInt(GetArrayLength(MyFixedArray))));
In the .h file, create the following function definition:
template <typename T>
static int32 GetArrayLength(TArray<TObjectPtr<AActor>, T> &Array);
In the .cpp file, create the function itself:
template <typename T>
int32 UCPPSC_Systems_Projectiles::GetArrayLength(TArray<TObjectPtr<AActor>, T> &Array)
{
return Array.Num();
}
Note: There is not .cpp required, a FORCEINLINE will also work, so that the function only lives within the header file.
Example:
float LoopDaly = 3.f;
bool LoopTimer = false;
FTimerHandle TimerHandle;
GetWorld()->GetTimerManager().SetTimer(TimerHandle, [&]()
{
UE_LOG(LogTemp, Warning, TEXT("This text will appear 3 seconds after execution and won't loop"));
}, LoopDaly, LoopTimer);
Here we use the Timer with a Lambda Function to display something after a certain amount of time.
A very good blog describes it in more detail: GeorgysBlog
Example for setting a Value for a Variable. The function itself is:
void GetAndSetActorTransform()
{
LastKnownVehicleLocation = this->GetActorTransform(); // LastKnownVehicleLocation is an FTransform stored somewhere else
}
Now to call the function after one Tick:
GetWorld()->GetTimerManager().SetTimerForNextTick(this, &ThisClass::GetAndSetActorTransform);