sexta-feira, 23 de abril de 2021

Static functions and the UGameplayStatics class

The static keyword in C++ can be used with variables, functions, and objects. In this article, we will focus on the use of static when declaring functions in a class.

When a function is declared as static in a C++ class, it has a class scope. This means that it is independent of the instances of the class and can be called using only the name of the class and the :: operator.

Consequently, a static function does not have access to the instance variables. The only variables it can access are the variables that have also been declared as static.

The code below shows a simple example of a static function that squares a number.

static float Square(float value)
{
  return value * value;
}

You do not need to create an instance of the class in order to be able to call the static function. Assuming that the function was created in a class named ATestStatic, the call to the Square() function can be done as follows:

float result = ATestStatic::Square(4.5f);

The keyword static is widely used in the creation of gameplay utility functions. An example of this is the UGameplayStatics class which contains several static functions that can be called in C++ and Blueprint.

UGameplayStatics is a Blueprint Function Library. In another article, we will see how to create a Blueprint Function Library.

The code below shows the declarations of five functions of the UGameplayStatics class that are frequently used.

UFUNCTION(BlueprintPure, Category="Game", 
          meta=(WorldContext="WorldContextObject", 
                UnsafeDuringActorConstruction="true"))
static class APawn* GetPlayerPawn(const UObject* WorldContextObject, 
                                  int32 PlayerIndex);

UFUNCTION(BlueprintPure, Category="Game", 
          meta=(WorldContext="WorldContextObject", 
                UnsafeDuringActorConstruction="true"))
static class APlayerController* GetPlayerController(
                                   const UObject* WorldContextObject, 
                                   int32 PlayerIndex);

UFUNCTION(BlueprintCallable, 
          meta=(WorldContext="WorldContextObject", 
                AdvancedDisplay = "2", 
                DisplayName = "Open Level (by Name)"), 
          Category="Game")
static void OpenLevel(const UObject* WorldContextObject, FName LevelName, 
               bool bAbsolute = true, FString Options = FString(TEXT("")));

UFUNCTION(BlueprintCallable, Category="Audio", 
          meta=(WorldContext="WorldContextObject", 
                AdvancedDisplay = "3", 
                UnsafeDuringActorConstruction = "true", 
                Keywords = "play"))
static void PlaySoundAtLocation(const UObject* WorldContextObject, 
               USoundBase* Sound, FVector Location, FRotator Rotation, 
               float VolumeMultiplier = 1.f, float PitchMultiplier = 1.f, 
               float StartTime = 0.f, 
               class USoundAttenuation* AttenuationSettings = nullptr, 
               USoundConcurrency* ConcurrencySettings = nullptr, 
               AActor* OwningActor = nullptr);

UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category="Game|Damage")
static float ApplyDamage(AActor* DamagedActor, float BaseDamage, 
               AController* EventInstigator, AActor* DamageCauser, 
               TSubclassOf<class UDamageType> DamageTypeClass);

The images below show the Blueprint nodes equivalent to the above functions.



Note that some functions have a UObject* WorldContextObject as their first parameter and that this parameter does not appear in Blueprint nodes. The WorldContextObject will be the topic of the next article.


Table of Contents C++