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 into the Scene (Level)

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.

#if WITH_EDITOR
/**
 * 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);
#endif
#if WITH_EDITOR
#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;
}
#endif
if (Target.bBuildEditor == true)
{
	PrivateDependencyModuleNames.AddRange
	(
		new string[] 
		{ 
			// 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

Get All Actors Of Class Examples

Get the names of all actors in the current editor world

#include "Kismet/BlueprintFunctionLibrary.h" // Engine
/**
 * Get the names of all actors in the current editor world
 *
 * @param bUseGameplayStatics	If want to use the function from GameplayStatics
 * @param bOutSuccess			If the action was a success or not
 * @param OutInfoMsg			More information about the action's result
 * 
 * @return Names of all the actors
 */
UFUNCTION(BlueprintCallable, Category = "Alex Quevillon - Get All Actors Of Class")
static TArray<FString> GetNamesOfAllActors(bool bUseGameplayStatics, bool& bOutSuccess, FString& OutInfoMsg);
#include "Kismet/GameplayStatics.h" // Engine
#include "EngineUtils.h" // Engine
#include "Engine/StaticMeshActor.h" // Engine

TArray<FString> UExampleClass::GetNamesOfAllActors(bool bUseGameplayStatics, bool& bOutSuccess, FString& OutInfoMsg)
{
	// Get the world from somewhere. In this case, we take the editor world.
	// But you can also get it from somewhere else. e.g. from any Actor or by loading the world asset with StaticLoadObject
	UWorld* World = GEditor ? GEditor->GetEditorWorldContext().World() : nullptr;
	if (World == nullptr)
	{
		bOutSuccess = false;
		OutInfoMsg = FString::Printf(TEXT("Get Names Of All Actors Failed - World is not valid"));
		return TArray<FString>();
	}

	// New list of names
	TArray<FString> Names = TArray<FString>();

	if (bUseGameplayStatics)
	{
		// List that'll receive the actors
		TArray<AActor*> Actors = TArray<AActor*>();

		// Get the actors
		UGameplayStatics::GetAllActorsOfClass(World, AActor::StaticClass(), Actors);

		// Loop through all the actors
		for (AActor* Actor : Actors)
		{
			// Get the Actor's name
			Names.Add(Actor->GetName());
		}
	}
	else
	{
		// Directly loop through all the actors using TActorIterator
		// The class in <> is used as filter when getting the actors. This can be any class you want (as long as it's an Actor)
		// In this case, we simply use the AActor class directly to get all the possible actors.
		for (TActorIterator<AActor> It(World); It; ++It)
		{
			// Get the real Actor from the Iterator
			AActor* Actor = *It;

			// Get the Actor's name
			Names.Add(Actor->GetName());
		}
	}

	// Return the names
	bOutSuccess = true;
	OutInfoMsg = FString::Printf(TEXT("Get Names Of All Actors Succeeded"));
	return Names;
}

Get the Mesh names of all static mesh actors in the current editor world

#include "Kismet/BlueprintFunctionLibrary.h" // Engine
/**
 * Get the Mesh names of all static mesh actors in the current editor world
 *
 * @param bUseGameplayStatics	If want to use the function from GameplayStatics
 * @param bOutSuccess			If the action was a success or not
 * @param OutInfoMsg		More information about the action's result
 *
 * @return Names of all the actors
 */
UFUNCTION(BlueprintCallable, Category = "Alex Quevillon - Get All Actors Of Class")
static TArray<FString> GetMeshNamesOfAllStaticMeshActors(bool bUseGameplayStatics, bool& bOutSuccess, FString& OutInfoMsg);
#include "Kismet/GameplayStatics.h" // Engine
#include "EngineUtils.h" // Engine
#include "Engine/StaticMeshActor.h" // Engine
	
TArray<FString> UExampleClass::GetMeshNamesOfAllStaticMeshActors(bool bUseGameplayStatics, bool& bOutSuccess, FString& OutInfoMsg)
{
	// Get the world
	UWorld* World = GEditor ? GEditor->GetEditorWorldContext().World() : nullptr;
	if (World == nullptr)
	{
		bOutSuccess = false;
		OutInfoMsg = FString::Printf(TEXT("Get Mesh Names Of All Static Mesh Actors Failed - World is not valid"));
		return TArray<FString>();
	}

	// New list of names
	TArray<FString> Names = TArray<FString>();

	if (bUseGameplayStatics)
	{
		// Get Actors
		TArray<AActor*> Actors = TArray<AActor*>();
		UGameplayStatics::GetAllActorsOfClass(World, AStaticMeshActor::StaticClass(), Actors);

		// Loop through all static mesh actors and get static mesh names
		for (AActor* Actor : Actors)
		{
			AStaticMeshActor* StaticMeshActor = Cast<AStaticMeshActor>(Actor);
			Names.Add(StaticMeshActor->GetStaticMeshComponent()->GetStaticMesh()->GetName());
		}
	}
	else
	{
		// Loop through all static mesh actors and get static mesh names
		for (TActorIterator<AStaticMeshActor> It(World); It; ++It)
		{
			Names.Add(*It->GetStaticMeshComponent()->GetStaticMesh()->GetName());
		}
	}

	// Return the names
	bOutSuccess = true;
	OutInfoMsg = FString::Printf(TEXT("Get Mesh Names Of All Static Mesh Actors Succeeded"));
	return Names;
}

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();
}

Merge Actors With C++

The function below shows an example of merging all actors in a scene into a single merged actor.

#include "Kismet/BlueprintFunctionLibrary.h" // Engine
#if WITH_EDITOR
/**
 * Editor Only - Will not work in packaged build.
 * 
 * Merge Static Mesh Actors
 *
 * @param Actors			The actors to merge
 * @param DestinationPath	The path of the merged StaticMesh asset: "/Game/Folder/MyStaticMesh"
 * @param bOutSuccess		If the action was a success or not
 * @param OutInfoMsg		More information about the action's result
 * 
 * @return The merged StaticMesh
 */
UFUNCTION(BlueprintCallable, Category = "Alex Quevillon - Merge actors")
static class UStaticMesh* MergeActors(TArray<class AStaticMeshActor*> Actors, FString DestinationPath, bool& bOutSuccess, FString& OutInfoMsg);
#endif
#if WITH_EDITOR
#include "StaticMeshEditorSubsystem.h" // StaticMeshEditor (Editor Only)
#include "StaticMeshEditorSubsystemHelpers.h" // StaticMeshEditor (Editor Only)
#include "UnrealEdGlobals.h" // UnrealEd (Editor Only)

UStaticMesh* UExampleClass::MergeActors(TArray<AStaticMeshActor*> Actors, FString DestinationPath, bool& bOutSuccess, FString& OutInfoMsg)
{
	// Make sure there are actors to merge
	if (Actors.Num() == 0)
	{
		bOutSuccess = false;
		OutInfoMsg = FString::Printf(TEXT("Merge Actors Failed - Actors list is empty. '%s'"), *DestinationPath);
		return nullptr;
	}

	// Get Subsystem
	UStaticMeshEditorSubsystem* StaticMeshEditorSubsystem = GEditor->GetEditorSubsystem<UStaticMeshEditorSubsystem>();
	if (StaticMeshEditorSubsystem == nullptr)
	{
		bOutSuccess = false;
		OutInfoMsg = FString::Printf(TEXT("Merge Actors Failed - Static Mesh Editor Subsystem is not valid. '%s'"), *DestinationPath);
		return nullptr;
	}

	// Options
	FMergeStaticMeshActorsOptions Options;
	Options.bSpawnMergedActor = false;
	Options.BasePackageName = DestinationPath;
	// FJoinStaticMeshActorsOptions
	Options.bDestroySourceActors = false;
	Options.NewActorLabel = "";
	Options.bRenameComponentsFromSource = true;
	// FMeshMergingSettings
	Options.MeshMergingSettings.TargetLightMapResolution = 256;
	Options.MeshMergingSettings.GutterSize = 2;
	Options.MeshMergingSettings.LODSelectionType = EMeshLODSelectionType::CalculateLOD;
	Options.MeshMergingSettings.SpecificLOD = 0;
	Options.MeshMergingSettings.bGenerateLightMapUV = true;
	Options.MeshMergingSettings.bComputedLightMapResolution = false;
	Options.MeshMergingSettings.bPivotPointAtZero = true;
	Options.MeshMergingSettings.bMergePhysicsData = false;
	Options.MeshMergingSettings.bMergeMeshSockets = false;
	Options.MeshMergingSettings.bMergeMaterials = false;
	Options.MeshMergingSettings.bCreateMergedMaterial = false;
	Options.MeshMergingSettings.bBakeVertexDataToMesh = false;
	Options.MeshMergingSettings.bUseVertexDataForBakingMaterial = true;
	Options.MeshMergingSettings.bUseTextureBinning = false;
	Options.MeshMergingSettings.bReuseMeshLightmapUVs = true;
	Options.MeshMergingSettings.bMergeEquivalentMaterials = true;
	Options.MeshMergingSettings.bUseLandscapeCulling = false;
	Options.MeshMergingSettings.bIncludeImposters = true;
	Options.MeshMergingSettings.bSupportRayTracing = true;
	Options.MeshMergingSettings.bAllowDistanceField = false;

	// Merge Actors
	AStaticMeshActor* MergedActor = nullptr;
	bOutSuccess = StaticMeshEditorSubsystem->MergeStaticMeshActors(Actors, Options, MergedActor);

	if (!bOutSuccess)
	{
		OutInfoMsg = FString::Printf(TEXT("Merge Actors Failed - Merge Failed. '%s'"), *DestinationPath);
		return nullptr;
	}

	// Load the merged static mesh and return it
	bOutSuccess = true;
	OutInfoMsg = FString::Printf(TEXT("Merge Actors Succeeded - '%s'"), *DestinationPath);
	return Cast<UStaticMesh>(StaticLoadObject(UStaticMesh::StaticClass(), nullptr, *DestinationPath));
}
#endif
if (Target.bBuildEditor == true)
{
	PrivateDependencyModuleNames.AddRange
	(
		new string[] 
		{ 
			// Required Modules
			"UnrealEd",
			"StaticMeshEditor",
		}
	);
}

Lock / unlock actor transform

#include "Kismet/BlueprintFunctionLibrary.h" // Engine
 /**
 * Lock or unlock an actor transform
 *
 * @param Actor					Actor to lock or unlock
 * @param bLockTransform		If true, will lock the transform. Otherwise unlock
 * @param bOutSuccess			If the action was a success or not
 * @param OutInfoMsg		More information about the action's result
 */
UFUNCTION(BlueprintCallable, Category = "Alex Quevillon - Lock Actor And Level")
static void LockActorTransform(AActor* Actor, bool bLockTransform, bool& bOutSuccess, FString& OutInfoMsg);
#include "EngineUtils.h" // Engine

void UExampleClass::LockActorTransform(AActor* Actor, bool bLockTransform, bool& bOutSuccess, FString& OutInfoMsg)
{
	// Validate the actor
	if (Actor == nullptr)
	{
		bOutSuccess = false;
		OutInfoMsg = FString::Printf(TEXT("Lock Actor Transform Failed - Actor is not valid"));
		return;
	}

	// Already right state?
	if (Actor->IsLockLocation() != bLockTransform)
	{
		// Set new lock state
		Actor->SetLockLocation(bLockTransform);

		// Mark package dirty so the user knows something changed
		Actor->GetWorld()->MarkPackageDirty();
	}

	bOutSuccess = true;
	OutInfoMsg = FString::Printf(TEXT("Lock Actor Transform Succeeded"));
}