domingo, 8 de novembro de 2020

The AActor class

The AActor class is a subclass of UObject and represents the gameplay objects that can be added to the level. Classes inheriting from AActor are prefixed with A.

Some of the functionality of an AActor is achieved through the use of components. The translation, rotation, and scale information of an AActor are obtained from its RootComponent. Therefore, an AActor must have at least one USceneComponent that is defined as its RootComponent.

You can use the level editor to add Actors and they can be created at run time using the SpawnActor() function. There are several versions of the SpawnActor() function, the example below shows one of them, assuming that the AActorChild class is a subclass of AActor:

FVector SpawnLocation = FVector(0.0f, 0.0f, 0.0f);
    
FRotator SpawnRotation = FRotator(0.0f, 0.0f, 0.0f);    
	
GetWorld()->SpawnActor<AActorChild>(AActorChild::StaticClass(),
                                    SpawnLocation, SpawnRotation );

When you want to destroy an AActor instance, you can use the Destroy() function of the AActor class. You can also use the SetLifeSpan() function to indicate the time in seconds that an AActor should stay alive. When this time is up, the AActor will be destroyed automatically.


Example usage:

For this example, you need a project with the Starter Content

We are going to create two Actors: CannonActor and BulletActor. CannonActor will create one instance of BulletActor per second. BulletActor will move forward and will be destroyed after 15 seconds.

Create a C++ class with the name BulletActor using the Actor class as the parent class. The BulletActor.h file must have this content: 

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "BulletActor.generated.h"

UCLASS()
class TUTOPROJECT_API ABulletActor : public AActor
{
  GENERATED_BODY()
	
public:	
  // Sets default values for this actor's properties
  ABulletActor();

  // Called every frame
  virtual void Tick(float DeltaTime) override;

  virtual void NotifyActorBeginOverlap(AActor* OtherActor) override;

  UPROPERTY(VisibleAnywhere)
  USceneComponent* RootScene;

  UPROPERTY(VisibleAnywhere)
  UStaticMeshComponent* StaticMesh;
	
  UPROPERTY(VisibleAnywhere)
  class UProjectileMovementComponent* ProjectileMovement;


protected:
  // Called when the game starts or when spawned
  virtual void BeginPlay() override;

}; 

The BulletActor class has three components: 

  • USceneComponentIt has a Transform and will be used as the Root component.
  • UStaticMeshComponent: Contains the Static Mesh that will visually represent the Actor.
  • UProjectileMovementComponent: Component used to move the Actor. Note that the keyword class was placed before the definition of the variable. You will need to add the #include of this class in the cpp file.

In the BulletActor.cpp file, the definition of the constructor looks like this:

#include "BulletActor.h"
#include "GameFramework/ProjectileMovementComponent.h"

// Sets default values
ABulletActor::ABulletActor()
{

  // Set this actor to call Tick() every frame.  
  PrimaryActorTick.bCanEverTick = true;

  RootScene = CreateDefaultSubobject<USceneComponent>(TEXT("RootScene"));
  RootComponent = RootScene;

  StaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMesh"));
  StaticMesh->SetupAttachment(RootScene);
  StaticMesh->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Overlap);

  ConstructorHelpers::FObjectFinder<UStaticMesh> MeshFile(
    TEXT("/Game/StarterContent/Shapes/Shape_Sphere.Shape_Sphere"));

  if (MeshFile.Succeeded())
  {
    StaticMesh->SetStaticMesh(MeshFile.Object);
  }
	
  ProjectileMovement = CreateDefaultSubobject<UProjectileMovementComponent>( 
                                             TEXT("ProjectileMovementComp") );
  ProjectileMovement->UpdatedComponent = StaticMesh;
  ProjectileMovement->InitialSpeed = 500.f;
  ProjectileMovement->MaxSpeed = 500.f;
  ProjectileMovement->ProjectileGravityScale = 0.f;

}

The three components are initialized in the constructor. BulletActor uses the Static Mesh of a sphere and will move at a speed of 500 units per second without gravity.

The other functions that need to be implemented in BulletActor.cpp are these:

void ABulletActor::BeginPlay()
{
  Super::BeginPlay();		
	
  SetLifeSpan(15.f);
}

void ABulletActor::NotifyActorBeginOverlap(AActor* OtherActor)
{
  Super::NotifyActorBeginOverlap(OtherActor);

  Destroy();
}

In the BeginPlay() function it is defined that the ABulletActor instance will be destroyed after 15 seconds. The NotifyActorBeginOverlap() function is called when the instance overlaps another Actor. In our example, the ABulletActor instance is destroyed if that happens.

Now create a C++ class with the name CannonActor using the Actor class as the parent class. The CannonActor.h file must have this content:

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "CannonActor.generated.h"

UCLASS()
class TUTOPROJECT_API ACannonActor : public AActor
{
  GENERATED_BODY()
	
public:	
  // Sets default values for this actor's properties
  ACannonActor();

  // Called every frame
  virtual void Tick(float DeltaTime) override;

  UPROPERTY(VisibleAnywhere)
  USceneComponent* RootScene;

  UPROPERTY(VisibleAnywhere)
  UStaticMeshComponent* StaticMesh;
	
  FTimerHandle ShotTimerHandle;
	
  void ShootCannon();	

protected:
  // Called when the game starts or when spawned
  virtual void BeginPlay() override;
  
};

The ACannonActor class has a Timer that calls the ShootCannon function once a second to create an instance of ABulletActor.

This is the constructor that is in the CannonActor.cpp file:

#include "CannonActor.h"
#include "BulletActor.h"

// Sets default values
ACannonActor::ACannonActor()
{
  // Set this actor to call Tick() every frame.
  PrimaryActorTick.bCanEverTick = true;

  RootScene = CreateDefaultSubobject<USceneComponent>(TEXT("RootScene"));
  RootComponent = RootScene;

  StaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMesh"));
  StaticMesh->SetupAttachment(RootScene);
	
  ConstructorHelpers::FObjectFinder<UStaticMesh> MeshFile(
    TEXT("/Game/StarterContent/Props/SM_MatPreviewMesh_02.SM_MatPreviewMesh_02"));

  if (MeshFile.Succeeded())
  {
    StaticMesh->SetStaticMesh(MeshFile.Object);
  }
		
}

The Timer is configured in the BeginPlay() function. The ShootCannon() function uses the SpawnActor() function to create an ABulletActor instance in a position and a rotation based on the cannon:

void ACannonActor::BeginPlay()
{
  Super::BeginPlay();
	
  GetWorldTimerManager().SetTimer(ShotTimerHandle, this,  
                                  &ACannonActor::ShootCannon, 1.f, true);	
}

void ACannonActor::ShootCannon()
{
  FRotator SpawnRotation = GetActorRotation();
	
  FVector SpawnLocation = GetActorLocation() 
                        + SpawnRotation.RotateVector(FVector(180.0f, 0.0f, 180.0f));
	
	
  GetWorld()->SpawnActor<ABulletActor>(ABulletActor::StaticClass(),
                                       SpawnLocation, SpawnRotation );
}

Compile the C++ code and add an instance of CannonActor at the level. Start the game and watch the cannon firing the bullets: 


Table of Contents C++