AActor class in Unreal Engine

Actor is the base class for an Object that can be placed or spawned in a level. It has visual representation and many useful functions defined. How to use it?

AActor:
  • Can be placed in the world
  • Can have a visual representation (Mesh, ...)
  • Has function for spawning to the world
  • Has functions for processing movement
  • All classes inherited from AActor has an A prefix at the start of class name

Inheritance Hierarchy

Spawn an Actor (and any its inherited class) to the world in runtime

There's a template TSubclassOf<ClassType> that allows to store a variable that represents a class of a UClass type (and all its derived classes). UClass has built in functionality that allows reflection to work between C++ and Blueprint.

Class information from TSubclassOf is then used as the parameter for UWorld::SpawnActor, respectively with its template SpawnActor<Type>(UClass*, Location, Rotation) that actually spawn actors to the world in runtime.

UPROPERTY(EditDefaultsOnly)
TSubclassOf<class ASpawnedObjectClass> SpawnedObjectClass;
GetWorld()->SpawnActor<ASpawnedObject>(ASpawnedObjectClass, spawnLocation, spawnRotation);

Of course, the class reference can be made right in the C++ class without the need to use Blueprint derived class, just refer to something like auto SpawnedObjectClass = ASpawnedObjectClass::StaticClass(); in such case.

Attach an actor into another actor

By spawning an actor into the world, regardless by what class it's being processed in the runtime, the actor acts independently based on own configuration. If the actor represents e.g. a tool, that should be tide to another AActor, e.g. ACharacter, the "Tool" AActor must be attached into its parent Actor, e.g. ACharacter.

Attaching to Meshes via Sockets

How to attach e.g. "Screwdriver" AActor into a hand of ACharacter?

If the "Screwdriver" or any other tool or even a gun or so (It really doesn't matter what kind of tool it is) is the part of the Skeleton, there's necessary to hide it first. It will be later replaced by the AActor for tools, for which actually we need to define a point where the tool actor has to be attached. This can be done through a socket. Socket is a pointer into which any Actor can be plugged. On Skeleton, the socket can be placed by clicking at a bone by right mouse button and selecting Add socket. If we hide some tool, because it's already a part of the Skeleton, we can add the socket as a child of the bone (tool) that we hid. If we did not, we must find an ideal location for placong the socket - probably a hand.

#include "Screwdriver.h"
void AExampleCharacter::BeginPlay()
{
    // Spawn the tool
    Screwdriver = GetWorld()->SpawnActor(AScrewdriver)(ScrewdriverClass);
    // Hide the tool that is part of the Skeleton
    GetMesh()->HideBoneByName(TEXT("Screwdriver_R"), EPhysBodyOp::PBO_None);
    // Attach Screwdriver into the socket point added to Skeleton
    Screwdriver->AttachToComponent(GetMesh(), FAttachmentTransformRules::KeepRelativeTransform, TEXT("SocketName"));
    Screwdriver->SetOwner(this);
}

Spawn an Actor (and any its inherited class) to the world in editor

As we work right in the editor, out of runtime, we use UBlueprintFunctionLibrary inherited class.

/**
 * Editor Only - Will not work in packaged build.
 *
 * Spawn an actor into a world
 *
 * @param ActorClassPath	Path of the actor class: "/Game/Folder/MyActor"
 * @param WorldPath		Path of the world: "/Game/Folder/MyWorld"
 * @param bUseEditorWorld	If true, will use the world currently open in the editor instead of the WorldPath
 * @param bOutSuccess	If the action was a success or not
 * @param OutInfoMsg	More information about the action's result
 *
 * @return The spawned actor
 */
UFUNCTION(BlueprintCallable, Category = "Spawn Actors In World")
static AActor* SpawnActorInWorld(FString ActorClassPath, FString WorldPath, bool bUseEditorWorld, bool& bOutSuccess, FString& OutInfoMsg);
#include "Engine/Blueprint.h" // Engine
#include "Engine/World.h" // Engine
#include "Editor/EditorEngine.h" // UnrealEd

AActor* UExampleClass::SpawnActorInWorld(FString ActorClassPath, FString WorldPath, bool bUseEditorWorld, bool& bOutSuccess, FString& OutInfoMsg)
{
	// Load blueprint asset
	UBlueprint* BlueprintActor = Cast<UBlueprint>(StaticLoadObject(UBlueprint::StaticClass(), nullptr, *ActorClassPath));
	if (BlueprintActor == nullptr || !BlueprintActor->GeneratedClass->IsChildOf(AActor::StaticClass()))
	{
		bOutSuccess = false;
		OutInfoMsg = FString::Printf(TEXT("Spawn Actor In World Failed - Path doesn't lead to a valid Actor. '%s'"), *ActorClassPath);
		return nullptr;
	}

  // Find world
  UWorld* World = nullptr;
  if (bUseEditorWorld){
  	World = GEditor->GetEditorWorldContext().World();
  } else {
  	World = Cast<UWorld>(StaticLoadObject(UWorld::StaticClass(), nullptr, *WorldPath));
    if (World == nullptr)
    {
    	bOutSuccess = false;
    	OutInfoMsg = FString::Printf(TEXT("Spawn Actor In World Failed - Path doesn't lead to a valid World. '%s'"), *WorldPath);
    	return nullptr;
    }
  }

  // Spawn actor
  AActor* SpawnedActor = World->SpawnActor(BlueprintActor->GeneratedClass);

  // Success
  bOutSuccess = true;
  OutInfoMsg = FString::Printf(TEXT("Spawn Actor In World Succeeded '%s'"), *ActorClassPath);

  if (World != GEditor->GetEditorWorldContext().World())
  {
  	OutInfoMsg += "\n--- Warning ---";
  	OutInfoMsg += "\nThe world used isn't the same as the world opened in the editor.";
  	OutInfoMsg += "\nIf you try to open it without saving it first, Unreal will crash.";
  }

  // Return the actor
  return SpawnedActor;
}
PrivateDependencyModuleNames.AddRange
(
  new string[] 
  { 
    // Default Modules
    "Core", 
    "CoreUObject", 
    "Engine", 

    // New Modules - Editor Only
    "UnrealEd",
  }
);

    Relative path to assets:

    • /Game/Path/To/Asset - access an asset in the Content folder of the game
    • /PluginName/Path/To/Asset - access an asset in the Content folder of selected plugin

Iterating over all Actors in a given level

Functions below are usable for all Run-Time instances of actors. Iterators in Unreal Engine are always accurate. More info about Iterators in the Iterators handbook

It may be made with TActorRange class which is part of the "EngineUtils.h".

#include "EngineUtils.h"
#include "GameFramework/Controller.h"
void AExampleProject::EndGame(bool bIsPlayerWinner)
{
	// foor loop through every controller in the world
	for(AController* Controller : TActorRange<AController>(GetWorld()))
	{
		bool bIsWinner = Controller->IsPlayerController() == bIsPlayerWinner;
		Controller->GameHasEnded(Controller->GetPawn(), bIsWinner);
	}
}

Iterating over all AI characters to check whether there is still any alive. If not, end the game with Winner state..

// ExampleAIControlller.cpp
#include "ExampleCharacter.h"
bool AExampleAIController::IsDead() const
{
	AExampleCharacter* ControlledCharacter = Cast<AExampleCharacter>(GetPawn());
	if(ControlledCharacter != nullptr){
		return ControlledCharacter->IsDead();
	}

	return true;
}

// ExampleGameMode.cpp
#include "ExampleAIController.h"
void AExampleGameMode::PawnKilled(APawn* PawnKilled)
{
  Super::PawnKilled(PawnKilled);

  for(AExampleAIController* Controller : TActorRange<AController>(GetWorld()))
  {
    if(!Controller->IsDead()) return;
  }

  EndGame(true);
}

General Actor Iterator

void AYourControllerClass::PrintAllActorsLocations()
{
  //EngineUtils.h
  for (TActorIterator<AActor> ActorItr(GetWorld()); ActorItr; ++ActorItr )
  {
    ClientMessage(ActorItr->GetName());
    ClientMessage(ActorItr->GetActorLocation().ToString());
  }
}

On Hit trigger

 //.h file
UPROPERTY(VisibleAnywhere, Category = "Movement")
class UProjectileMovementComponent* ProjectileMC;
	
// .cpp file
#include "GameFramework/ProjectileMovementComponent.h"
AProjectile::BeginPlay()
{
    ProjectileMesh->OnComponentHit.AddDynamic(this, &AProjectile::OnHit); //Collision Presets must be Enabled (Query and Physics) for handling Hit events
}
void AProjectile::OnHit(UPrimitiveComponent* HitComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit)
{
   if(!GetOwner() || OtherActor && OtherActor != this && OtherActor != GetOwner())
   {
      Destroy();
      return;
   }
   // Apply Damage  
   // Spawn sound & particle effect
   // Play Sound
   Destroy();
}