종종 게임에서 게임플레이 도중 동적으로 레벨에 아이템을 추가시키고 싶을 때가 있습니다. 그런 것을 액터 를 스폰 시킨다고 합니다. 스폰하고자 하는 아이템은 다른 플레이어나 적에서부터 생명력, 무기, 보상과 같은 픽업이 될 수도 있습니다. 여기서는 블루프린트 를 통해 액터 를 스폰시키는 법에 대한 정보를 알아보겠습니다.
구현 안내
제작중인 게임 유형과 관계 없시 종종 원래 레벨에 배치하지는 않았지만 실행시간에 무언가 나타나게 하고 싶은 경우가 있습니다. 월드에 오브젝트를 "스폰"(spawn)시킨다는 개념은 물론 게임플레이 도중(이든 아니든) 스폰된 오브젝트를 "소멸"(destroy)시킨다는 개념 역시 블루프린트 비주얼 스크립트 로 가능합니다.
여기서는 버튼을 누르면 액터 를 스폰시키고, 캐릭터에 붙인 다음, 버튼을 두 번째 누르면 변수 레퍼런스를 사용하여 소멸시킵니다.

단계
여기서는 블루프린트 삼인칭 템플릿 에 시작용 콘텐츠 를 포함시켜 사용하고 있습니다.
-
프로젝트 안의 메인 툴바 에서 블루프린트 버튼을 클릭하고 레벨 블루프린트 열기 를 선택합니다.
레벨 블루프린트 는 각 레벨에 고유한 특수 블루프린트 유형으로, 레벨 전반적인 글로벌 그래프 역할을 합니다.
-
그래프에 우클릭하고 Spawn Actor from Class 노드를 검색 추가합니다.
그러면 스폰시키고자 하는 클래스( 또는 오브젝트 유형 따위)를 지정할 수 있습니다.
-
SpawnActor 노드의 Class 섹션에서 Blueprint_Effect_Fire 클래스를 선택합니다.
프로젝트를 생성할 때 포함시킨 시작용 콘텐츠 의 일부분으로 생성된 블루프린트 클래스입니다.
-
그래프에 우클릭하고 F Keyboard Event 를 검색 추가합니다.
화염 이펙트의 스폰과 소멸에 이 키를 사용합니다.
-
그래프에 다시 우클릭하고 Flip Flop 노드를 검색 추가합니다.
이 노드는 처음 들어설 때 A 핀을 실행하고 두 번째 들어설 때 B 핀을 실행하는 스위치 역할을 합니다. B 핀을 실행한 이후, 다음 번 들어설 때 다시 A 핀을 실행하는 식으로, "flip-flop" 은 A 와 B 핀을 번갈아 선택합니다.
-
F 노드의 Pressed 핀을 좌클릭으로 끌어 Flip Flop 및 Spawn Actor 노드에 연결합니다.
이렇게 하면 (F 를 눌렀을 때) Blueprint Fire 이펙트를 스폰시키는 Spawn Actor 노드 호출을 실행할 수 있습니다.
-
그래프에 우클릭하고 Destroy Actor 노드를 검색 추가합니다.
이 노드로 소멸시킬 액터를 지정할 수 있습니다.
-
Flip Flop 노드의 B 핀을 Destroy Actor 노드에 연결합니다.
F 를 두 번째 누르면, Flip Flop 의 B 핀이 호출되어 Destroy Actor 노드를 실행합니다. Destroy Actor 에는 Target 입력 핀이 있어, 노드에게 무엇을 소멸시킬지 알려줍니다. 기본적으로 Self 설정되어 있으며 이 경우 널 포인터, 즉 레벨 블루프린트 자체는 소멸시킬 수 없으니 무엇을 소멸시킬지 명확하지 않다는 뜻입니다. 이 Destroy Actor 노드가 캐릭터 블루프린트 안에 있고 타깃을 Self 로 한다면, 캐릭터가 소멸될 것입니다.
이 경우 Destroy Actor 노드에게 무엇을 소멸시킬지 알려줘야 합니다 (우리 Blueprint Fire 이펙트입니다). 그러기 위해 스폰했던 Blueprint Fire 이펙트로의 레퍼런스를 만들어야 합니다.
-
Spawn Actor 노드의 Return Value 에 우클릭하고 변수로 승격 을 선택합니다.
Return Value 가 여기서 바로 "스폰하고자 하는 것" 이며 이에 대한 레퍼런스를 저장하여 나중에 소멸시키고자 하는 것입니다.
-
변수의 디테일 패널에서 이름을 CurrentFlames 처럼 짓습니다.
-
내 블루프린트 패널에서 변수 아래 Ctrl 키를 누른 상태로 CurrentFlames 변수를 그래프에 끌어 놓고 Destroy Actor 의 Target 에 연결합니다.
이제 Destroy Actor 노드더러 우리 변수 레퍼런스가 앞서 만든 Blueprint Fire 이펙트를 타깃으로 삼으라 하는 것입니다.
-
그래프에 우클릭하고 Get Player Character 노드를 검색 추가합니다.
이렇게 하면 지정된 플레이어 캐릭터 위치를 찾아 그에 관한 정보에 접근하여 얻을 수 있게 됩니다.
-
Get Player Character 의 Return Value 를 끌어 놓고 Get Actor Transform 노드를 검색 추가합니다.
그러면 플레이어 캐릭터의 위치, 회전, 스케일 정보를 알 수 있고, 이를 사용하여 Blueprint Fire 이펙트의 스폰 위치를 정할 수 있습니다.
-
Get Actor Transform 의 Return Value 를 Spawn Actor 의 Spawn Transform 에 연결합니다.
이미지를 클릭하면 원본을 확인합니다.
이 시점에서 그래프가 거의 완성되어 F 키를 누르면 플레이어 위치를 변수에 저장하고 거기에 Blueprint Fire 를 스폰하도록 지정했습니다. F 를 두 번째 누르면, 생성했던 변수(, 즉 화염 이펙트)를 소멸시킵니다. 마지막으로 할 작업은 화염 이펙트를 플레이어에 붙이는 것입니다. 현재 화염 이펙트는 플레이어 위치에 스폰되지만, 플레이어가 이동해도 화염은 스폰된 자리에 머무릅니다.
-
Set 노드의 레퍼런스 핀을 좌클릭으로 끌어 놓고 AttachToActor 노드를 추가합니다.
이 노드를 통해 화염 이펙트를 다른 액터, 이 경우 플레이어 캐릭터에 붙일 수 있습니다.
-
Get Player Character 노드를 사용하여 아래와 같이 붙이고, Location Rule 및 Rotation Rule 을 Snape to Target 으로 설정합니다.
이미지를 클릭하면 원본을 확인합니다.
여기서 화염 이펙트에 대한 레퍼런스 변수를 플레이어 캐릭터에 붙이는데, 그 위치와 회전은 플레이어 캐릭터에 끌어 붙이도록 하고 있습니다.
-
컴파일 버튼을 눌러 블루프린트를 컴파일합니다.
-
메인 레벨 에디터 창으로 돌아와 메인 툴바 에서 플레이 버튼을 클릭하여 에디터 안에서 플레이합니다.
최종 결과
에디터에서 플레이할 때, F 키를 누르면 화염 이펙트가 스폰되어 플레이어 캐릭터에 붙습니다. 화염이 플레이어에 붙어있는 동안 F 키를 누르면 이펙트가 소멸되고, F 키를 다시 누르면 다시 스폰됩니다.
다른 접근법 한 가지는 Blueprint Fire 이펙트 안에 들어있는 파티클 이펙트를 Activate / Deactivate 시키는 것입니다.
이미지를 클릭하면 원본을 확인합니다.
위 예제에서, Event BeginPlay 노드를 사용하여 게임 시작 시 Blueprint Fire 를 스폰하고 플레이어 캐릭터에 붙입니다. 또 게임 시작 시 파티클 이펙트 비활성화 및 그에 연관된 사운드를 페이드 아웃 시킵니다. F 를 누르면, Blueprint Fire 이펙트가 이미 (활성화만 안되었다 뿐) 스폰되어 있기 때문에, 그냥 활성화만 시켜주고 오디오 페이드 인을 해주면 됩니다. F 를 두 번째 누르면, 이펙트를 소멸시키는 대신 비활성화 및 사운드 페이드 아웃을 해줍니다.
Creating the Actor to Spawn
-
Begin by creating a new Third Person C++ games project with Starter Content enabled. Name your project SpawnDestroy.
-
From the C++ class wizard create a new Actor class named ActorToSpawn.
-
In the Class defaults of ActorToSpawn.h implement the following.
protected: UPROPERTY(EditAnywhere, BlueprintReadWrite) class USphereComponent* SphereComp; UPROPERTY(EditAnywhere, BlueprintReadWrite) UStaticMeshComponent* StaticMeshComp; UPROPERTY(EditAnywhere, BlueprintReadWrite) class UParticleSystemComponent* ParticleComp;
-
Navigate to ActorToSpawn.cpp and declare the following class libraries.
#include "Components/SphereComponent.h" #include "Particles/ParticleSystemComponent.h"
-
Within the AActorToSpawn::AActorToSpawn constructor, implement the following code.
AActorToSpawn::AActorToSpawn() { // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it. PrimaryActorTick.bCanEverTick = true; //Creating our Default Components SphereComp = CreateDefaultSubobject<USphereComponent>(TEXT("Sphere")); StaticMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MeshComp")); ParticleComp = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("ParticleComp")); //Attaching the Components and setting physics SphereComp->SetupAttachment(RootComponent); SphereComp->SetSimulatePhysics(true); SphereComp->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics); StaticMeshComp->AttachToComponent(SphereComp,FAttachmentTransformRules::KeepRelativeTransform); ParticleComp->AttachToComponent(StaticMeshComp,FAttachmentTransformRules::KeepRelativeTransform); //Setting the Sphere radius to be of a smaller size in line with the Static Mesh. SphereComp->SetSphereRadius(16.0f); //Setting the Static Mesh Scale and Location to fit the radius of the Sphere. StaticMeshComp->SetRelativeLocation(FVector(0.0, 0.0, -12.0f)); StaticMeshComp->SetRelativeScale3D(FVector(0.25, 0.25, 0.25)); //Using Constructor Helpers to set our Static Mesh Comp with a Sphere Shape. static ConstructorHelpers::FObjectFinder<UStaticMesh>SphereMeshAsset(TEXT("StaticMesh'/Game/StarterContent/Shapes/Shape_Sphere.Shape_Sphere'")); StaticMeshComp->SetStaticMesh(SphereMeshAsset.Object); //Using Constructor Helpers to set our Particle Comp with our Fire Particle Comp. static ConstructorHelpers::FObjectFinder<UParticleSystem>ParticleCompAsset(TEXT("ParticleSystem'/Game/StarterContent/Particles/P_Fire.P_Fire'")); ParticleComp->SetTemplate(ParticleCompAsset.Object); }
-
Compile your code.
-
In the editor, navigate to the C++ classes folder, and right-click your ActorToSpawn. From the context menu, select Create Blueprint class based on ActorToSpawn.
Your completed Bp_ActorToSpawn will look similar to the image below.
Finished Code
ActorToSpawn.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "ActorToSpawn.generated.h"
UCLASS()
class SPAWNDESTROYCPP_API AActorToSpawn : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AActorToSpawn();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
class USphereComponent* SphereComp;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
UStaticMeshComponent* StaticMeshComp;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
class UParticleSystemComponent* ParticleComp;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
};
ActorToSpawn.cpp
#include "ActorToSpawn.h"
#include "Components/SphereComponent.h"
#include "Particles/ParticleSystemComponent.h"
// Sets default values
AActorToSpawn::AActorToSpawn()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
//Creating our Default Components
SphereComp = CreateDefaultSubobject<USphereComponent>(TEXT("Sphere"));
StaticMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MeshComp"));
ParticleComp = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("ParticleComp"));
//Attaching the Components and setting physics
SphereComp->SetupAttachment(RootComponent);
SphereComp->SetSimulatePhysics(true);
SphereComp->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
StaticMeshComp->AttachToComponent(SphereComp,FAttachmentTransformRules::KeepRelativeTransform);
ParticleComp->AttachToComponent(StaticMeshComp,FAttachmentTransformRules::KeepRelativeTransform);
//Setting the Sphere radius to be of a smaller size in line with the Static Mesh.
SphereComp->SetSphereRadius(16.0f);
//Setting the Static Mesh Scale and Location to fit the radius of the Sphere.
StaticMeshComp->SetRelativeLocation(FVector(0.0, 0.0, -12.0f));
StaticMeshComp->SetRelativeScale3D(FVector(0.25, 0.25, 0.25));
}
// Called when the game starts or when spawned
void AActorToSpawn::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void AActorToSpawn::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
Creating the Actor Spawner
Now that you have created an Actor to Spawn, you will create an Actor spawner which uses a custom function to spawn your new Actor.
-
From the C++ class wizard create a new Actor class named ActorSpawner.
-
In the class defaults of your ActorSpawner.h implement the following code
public: UFUNCTION() void SpawnActor(); protected: UPROPERTY(EditAnywhere,BlueprintReadWrite) class UBoxComponent* SpawnVolume;
-
Navigate to the ActorSpawner.cpp and include the following class libraries
#include "Components/BoxComponent.h" #include "ActorToSpawn.h"
-
Inside the AActorSpawner::AActorSpawner constructor implement the following code.
AActorSpawner::AActorSpawner() { RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("DefaultSceneRoot")); SpawnVolume = CreateDefaultSubobject<UBoxComponent>(TEXT("SpawnVolume")); SpawnVolume->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepRelativeTransform); }
-
Implement the following code for the AActorSpawner::SpawnActor class method.
void AActorSpawner::SpawnActor() { FVector SpawnLocation = GetActorLocation(); FRotator SpawnRotation = GetActorRotation(); GetWorld()->SpawnActor<AActorToSpawn>(SpawnLocation,SpawnRotation); }
-
Compile your code.
-
From the Content Browser, navigate to your C++ classes folder, and right-click your ActorSpawner class, from the C++ Class Actions context menu, select Create Blueprint class based on ActorSpawner named Bp_ActorSpawner.
Your completed Blueprint will look like the image below.
Finished Code
ActorSpawner.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "ActorSpawner.generated.h"
UCLASS()
class SPAWNDESTROYCPP_API AActorSpawner : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AActorSpawner();
UFUNCTION()
void SpawnActor();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
UPROPERTY(EditAnywhere,BlueprintReadWrite)
class UBoxComponent* SpawnVolume;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
};
ActorSpawner.cpp
#include "ActorSpawner.h"
#include "Components/BoxComponent.h"
#include "ActorToSpawn.h"
// Sets default values
AActorSpawner::AActorSpawner()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("DefaultSceneRoot"));
SpawnVolume = CreateDefaultSubobject<UBoxComponent>(TEXT("SpawnVolume"));
SpawnVolume->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepRelativeTransform);
}
// Called when the game starts or when spawned
void AActorSpawner::BeginPlay()
{
Super::BeginPlay();
}
void AActorSpawner::SpawnActor()
{
FVector SpawnLocation = GetActorLocation();
FRotator SpawnRotation = GetActorRotation();
GetWorld()->SpawnActor<AActorToSpawn>(SpawnLocation,SpawnRotation);
}
// Called every frame
void AActorSpawner::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
Setting Up Additional Character Action Commands
With both your Actor and Actor spawner classes set up, you will now set up the Third Person Character with the functionality to call the Actor spawner’s Spawn Actor function. You will also need to map your input keys mappings for the Player Character to provide your player the ability to call the Actor spawner’s Spawn Actor function.
-
Navigate to Edit > Project Settings > Engine > Input, then from the Bindings > Action mappings category, click the + button to add two additional mappings named SpawnActors and DestroyActors.
-
Set the SpawnActors Action key mapping to numeric 1 key, and the DestroyActors Action key mapping to the numeric 2 key.
-
Open your ThirdPersonCharacter.h file and declare the following class declarations.
protected: void SpawnActors(); void DestroyActors();
-
Navigate to your ThirdPersonCharacter.cpp and include the following class libraries.
#include "Kismet/GameplayStatics.h" #include "ActorSpawner.h" #include "ActorToSpawn.h"
GameplayStatics contains useful gameplay utility functions that can be called from both Blueprint and C++. For additional information see the following API documentation for GameplayStatics.
-
Implement the following class implementation for your ASpawnDestroyCppCharacter::SpawnActors and ASpawnDestroyCppCharacter::DestroyActors methods.
void ASpawnDestroyCppCharacter::SpawnActors() { //Find the Actor Spawner in the world, and invoke it's Spawn Actor function AActor* ActorSpawnerTofind = UGameplayStatics::GetActorOfClass(GetWorld(),AActorSpawner::StaticClass()); AActorSpawner* ActorSpawnerReference = Cast<AActorSpawner>(ActorSpawnerTofind); if (ActorSpawnerReference) { ActorSpawnerReference->SpawnActor(); } } void ASpawnDestroyCppCharacter::DestroyActors() { //Get every Actor to Spawn in the world and invoke Destroy Actor TArray<AActor*> FoundActors; UGameplayStatics::GetAllActorsOfClass(GetWorld(), AActorToSpawn::StaticClass(), FoundActors); for (AActor* ActorFound :FoundActors) { ActorFound->Destroy(); } }
-
Navigate to your ASpawnDestroyCppCharacter::SetupPlayerInputComponent method and add the following code.
void ASpawnDestroyCppCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) { PlayerInputComponent->BindAction("SpawnActors", IE_Pressed, this, &ASpawnDestroyCppCharacter::SpawnActors); PlayerInputComponent->BindAction("DestroyActors", IE_Pressed, this, &ASpawnDestroyCppCharacter::DestroyActors); }
Finished Code
SpawnDestroyCppCharacter.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "SpawnDestroyCppCharacter.generated.h"
UCLASS(config=Game)
class ASpawnDestroyCppCharacter : public ACharacter
{
GENERATED_BODY()
/** Camera boom positioning the camera behind the character */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
class USpringArmComponent* CameraBoom;
/** Follow camera */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
class UCameraComponent* FollowCamera;
public:
ASpawnDestroyCppCharacter();
/** Base turn rate, in deg/sec. Other scaling may affect final turn rate. */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
float BaseTurnRate;
/** Base look up/down rate, in deg/sec. Other scaling may affect final rate. */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
float BaseLookUpRate;
protected:
/*Calls Actor Spawner in Level to Spawn their Actor to Spawn*/
void SpawnActors();
/*Gets all ActorToSpawn Actors and call their Destroy function */
void DestroyActors();
/** Resets HMD orientation in VR. */
void OnResetVR();
/** Called for forwards/backward input */
void MoveForward(float Value);
/** Called for side to side input */
void MoveRight(float Value);
/**
* Called via input to turn at a given rate.
* @param Rate This is a normalized rate, i.e. 1.0 means 100% of desired turn rate
*/
void TurnAtRate(float Rate);
/**
* Called via input to turn look up/down at a given rate.
* @param Rate This is a normalized rate, i.e. 1.0 means 100% of desired turn rate
*/
void LookUpAtRate(float Rate);
/** Handler for when a touch input begins. */
void TouchStarted(ETouchIndex::Type FingerIndex, FVector Location);
/** Handler for when a touch input stops. */
void TouchStopped(ETouchIndex::Type FingerIndex, FVector Location);
protected:
// APawn interface
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
// End of APawn interface
public:
/** Returns CameraBoom subobject **/
FORCEINLINE class USpringArmComponent* GetCameraBoom() const { return CameraBoom; }
/** Returns FollowCamera subobject **/
FORCEINLINE class UCameraComponent* GetFollowCamera() const { return FollowCamera; }
};
SpawnDestroyCppCharacter.cpp
#include "SpawnDestroyCppCharacter.h"
#include "HeadMountedDisplayFunctionLibrary.h"
#include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h"
#include "Components/InputComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "GameFramework/Controller.h"
#include "GameFramework/SpringArmComponent.h"
#include "Kismet/GameplayStatics.h"
#include "ActorSpawner.h"
#include "ActorToSpawn.h"
//////////////////////////////////////////////////////////////////////////
// ASpawnDestroyCppCharacter
ASpawnDestroyCppCharacter::ASpawnDestroyCppCharacter()
{
// Set size for collision capsule
GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f);
// set our turn rates for input
BaseTurnRate = 45.f;
BaseLookUpRate = 45.f;
// Don't rotate when the controller rotates. Let that just affect the camera.
bUseControllerRotationPitch = false;
bUseControllerRotationYaw = false;
bUseControllerRotationRoll = false;
// Configure character movement
GetCharacterMovement()->bOrientRotationToMovement = true; // Character moves in the direction of input...
GetCharacterMovement()->RotationRate = FRotator(0.0f, 540.0f, 0.0f); // ...at this rotation rate
GetCharacterMovement()->JumpZVelocity = 600.f;
GetCharacterMovement()->AirControl = 0.2f;
// Create a camera boom (pulls in towards the player if there is a collision)
CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
CameraBoom->SetupAttachment(RootComponent);
CameraBoom->TargetArmLength = 300.0f; // The camera follows at this distance behind the character
CameraBoom->bUsePawnControlRotation = true; // Rotate the arm based on the controller
// Create a follow camera
FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName); // Attach the camera to the end of the boom and let the boom adjust to match the controller orientation
FollowCamera->bUsePawnControlRotation = false; // Camera does not rotate relative to arm
// Note: The skeletal mesh and anim blueprint references on the Mesh component (inherited from Character)
// are set in the derived blueprint asset named MyCharacter (to avoid direct content references in C++)
}
//////////////////////////////////////////////////////////////////////////
// Input
void ASpawnDestroyCppCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
// Set up gameplay key bindings
check(PlayerInputComponent);
PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);
PlayerInputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping);
PlayerInputComponent->BindAction("SpawnActors", IE_Pressed, this, &ASpawnDestroyCppCharacter::SpawnActors);
PlayerInputComponent->BindAction("DestroyActors", IE_Pressed, this, &ASpawnDestroyCppCharacter::DestroyActors);
PlayerInputComponent->BindAxis("MoveForward", this, &ASpawnDestroyCppCharacter::MoveForward);
PlayerInputComponent->BindAxis("MoveRight", this, &ASpawnDestroyCppCharacter::MoveRight);
// We have 2 versions of the rotation bindings to handle different kinds of devices differently
// "turn" handles devices that provide an absolute delta, such as a mouse.
// "turnrate" is for devices that we choose to treat as a rate of change, such as an analog joystick
PlayerInputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput);
PlayerInputComponent->BindAxis("TurnRate", this, &ASpawnDestroyCppCharacter::TurnAtRate);
PlayerInputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput);
PlayerInputComponent->BindAxis("LookUpRate", this, &ASpawnDestroyCppCharacter::LookUpAtRate);
// handle touch devices
PlayerInputComponent->BindTouch(IE_Pressed, this, &ASpawnDestroyCppCharacter::TouchStarted);
PlayerInputComponent->BindTouch(IE_Released, this, &ASpawnDestroyCppCharacter::TouchStopped);
// VR headset functionality
PlayerInputComponent->BindAction("ResetVR", IE_Pressed, this, &ASpawnDestroyCppCharacter::OnResetVR);
}
void ASpawnDestroyCppCharacter::SpawnActors()
{
//Find the Actor Spawner in the Level, and invoke it's Spawn Actor function
AActor* ActorSpawnerTofind = UGameplayStatics::GetActorOfClass(GetWorld(),AActorSpawner::StaticClass());
AActorSpawner* ActorSpawnerReference = Cast<AActorSpawner>(ActorSpawnerTofind);
if (ActorSpawnerReference)
{
ActorSpawnerReference->SpawnActor();
}
}
void ASpawnDestroyCppCharacter::DestroyActors()
{
TArray<AActor*> FoundActors;
UGameplayStatics::GetAllActorsOfClass(GetWorld(), AActorToSpawn::StaticClass(), FoundActors);
for (AActor* ActorFound :FoundActors)
{
ActorFound->Destroy();
}
}
void ASpawnDestroyCppCharacter::OnResetVR()
{
// If SpawnDestroyCpp is added to a project via 'Add Feature' in the Unreal Editor the dependency on HeadMountedDisplay in SpawnDestroyCpp.Build.cs is not automatically propagated
// and a linker error will result.
// You will need to either:
// Add "HeadMountedDisplay" to [YourProject].Build.cs PublicDependencyModuleNames in order to build successfully (appropriate if supporting VR).
// or:
// Comment or delete the call to ResetOrientationAndPosition below (appropriate if not supporting VR)
UHeadMountedDisplayFunctionLibrary::ResetOrientationAndPosition();
}
void ASpawnDestroyCppCharacter::TouchStarted(ETouchIndex::Type FingerIndex, FVector Location)
{
Jump();
}
void ASpawnDestroyCppCharacter::TouchStopped(ETouchIndex::Type FingerIndex, FVector Location)
{
StopJumping();
}
void ASpawnDestroyCppCharacter::TurnAtRate(float Rate)
{
// calculate delta for this frame from the rate information
AddControllerYawInput(Rate * BaseTurnRate * GetWorld()->GetDeltaSeconds());
}
void ASpawnDestroyCppCharacter::LookUpAtRate(float Rate)
{
// calculate delta for this frame from the rate information
AddControllerPitchInput(Rate * BaseLookUpRate * GetWorld()->GetDeltaSeconds());
}
void ASpawnDestroyCppCharacter::MoveForward(float Value)
{
if ((Controller != nullptr) && (Value != 0.0f))
{
// find out which way is forward
const FRotator Rotation = Controller->GetControlRotation();
const FRotator YawRotation(0, Rotation.Yaw, 0);
// get forward vector
const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
AddMovementInput(Direction, Value);
}
}
void ASpawnDestroyCppCharacter::MoveRight(float Value)
{
if ( (Controller != nullptr) && (Value != 0.0f) )
{
// find out which way is right
const FRotator Rotation = Controller->GetControlRotation();
const FRotator YawRotation(0, Rotation.Yaw, 0);
// get right vector
const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
// add movement in that direction
AddMovementInput(Direction, Value);
}
}
Setting Up the Scene
Now that you have finished creating the functionality necessary for the Player Character to call the Bp_Spawner’s SpawnActor function, you will need to set up the location of the Bp_Spawner in the Level.
-
From the Content Browser, click and drag an instance of your Bp_ Spawner into the Level.
-
Select PIE (Play-In Editor) to test your spawner.
End Result
When testing in the Editor, if you press the 1 key, then the Actor Spawner class will spawn its Actor to spawn into the Level. If you decide to press the 2 key, then all ActorsToSpawn within the Level will be destroyed.
