0. 개요

TargetPoint 액터를 상속받는 클래스와 액터를 상속받는 몬스터 소환 볼륨을 이용하여, 특정 위치에서 몬스터가 소환되도록 한다.

 

 

1. 몬스터 소환
(1) C++ 클래스 생성

TargetPoint 액터를 상속받는 AuraEnemySpawnPoint 클래스와, 액터를 상속받는 AuraEnemySpawnVolume 클래스를 생성한다.

 

(2) AuraCharacterBase에서 캐릭터 클래스 Setter 선언

void SetCharacterClass(ECharacterClass InClass) {CharacterClass = InClass;}

SpawnActorDeffered로 소환된 적의 클래스를 변경할 수 있도록 Setter를 선언한다.

 

(3) AuraEnemy에서 몬스터 레벨 Setter 선언

void SetLevel(int32 InLevel) {Level = InLevel;}

 

 

(3) AuraEnemySpawnPoint 클래스

#pragma once

#include "CoreMinimal.h"
#include "AbilitySystem/Data/CharacterClassInfo.h"
#include "Engine/TargetPoint.h"
#include "AuraEnemySpawnPoint.generated.h"

class AAuraEnemy;

UCLASS()
class AURA_API AAuraEnemySpawnPoint : public ATargetPoint
{
	GENERATED_BODY()

public:
	UFUNCTION(BlueprintCallable)
	void SpawnEnemy();

public:
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Enemy Class")
	TSubclassOf<AAuraEnemy> EnemyClass;
	
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Enemy Class")
	int32 EnemyLevel = 1;

	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Enemy Class")
	ECharacterClass CharacterClass = ECharacterClass::Warrior;
	
};

 

void AAuraEnemySpawnPoint::SpawnEnemy()
{
	// 액터 스폰 파리미터
	FActorSpawnParameters SpawnParams;
	SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn;

	AAuraEnemy* Enemy = GetWorld()->SpawnActorDeferred<AAuraEnemy>(EnemyClass, GetActorTransform());
	Enemy->SetLevel(EnemyLevel);
	Enemy->SetCharacterClass(CharacterClass);
	Enemy->FinishSpawning(GetActorTransform());
	Enemy->SpawnDefaultController();
}

- Spawn Collision Handling Override = Adjust If Possible But Always Spawn

액터 스폰 시 해당 위치에 맞게 조정 가능하다면 조정하고, 불가능 하더라도 일단 소환하도록 하는 옵션이다.

 

- SpawnDefaultController

적에게 AI 관련 기능(블랙 보드, 비헤이비어 트리)를 사용할 수 있도록 게임모드의 기본 컨트롤러를 부여한다.

 

 

(4) AuraEnemySpawnVolume

플레이어 캐릭터가 해당 볼륨에 닿으면 적을 소환한다.

캐릭터가 볼륨에 닿은 것은 불리언으로 관리되어, 레벨을 왔다갔다해도 다시 몬스터를 소환하지 않도록 한다.

#pragma once

#include "CoreMinimal.h"
#include "AuraEnemySpawnPoint.h"
#include "GameFramework/Actor.h"
#include "Interaction/SaveInterface.h"
#include "AuraEnemySpawnVolume.generated.h"

class UBoxComponent;

UCLASS()
class AURA_API AAuraEnemySpawnVolume : public AActor, public ISaveInterface
{
	GENERATED_BODY()
	
public:	
	AAuraEnemySpawnVolume();

public:
	/* 저장 인터페이스 시작*/
	virtual void LoadActor_Implementation() override;	
	/* 저장 인터페이스 끝*/

	UPROPERTY(BlueprintReadOnly, SaveGame)
	bool bReached = false;

protected:
	virtual void BeginPlay() override;

	UFUNCTION()
	virtual void OnSphereOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);

	UPROPERTY(EditAnywhere)
	TArray<AAuraEnemySpawnPoint*> SpawnPoints;
private:
	UPROPERTY(VisibleAnywhere)
	TObjectPtr<UBoxComponent> Box;
};

 

 

(4-1) 생성자

AAuraEnemySpawnVolume::AAuraEnemySpawnVolume()
{
	PrimaryActorTick.bCanEverTick = false;

	Box = CreateDefaultSubobject<UBoxComponent>("Box");
	SetRootComponent(Box);
	Box->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
	Box->SetCollisionObjectType(ECC_WorldStatic);
	Box->SetCollisionResponseToChannels(ECR_Ignore);
	Box->SetCollisionResponseToChannel(ECC_Pawn, ECR_Overlap);
}

박스 컴포넌트를 생성하고, 캐릭터와의 충돌을 감지할 것이다.

모든 채널에 대해 무시하고, Pawn 클래스에 대해 겹침을 판정한다.

 

 

(4-2) BeginPlay에서 콜리전 콜백 함수 바인딩

void AAuraEnemySpawnVolume::BeginPlay()
{
	Super::BeginPlay();

	Box->OnComponentBeginOverlap.AddDynamic(this, &AAuraEnemySpawnVolume::OnSphereOverlap);
}

 

 

(4-3) 콜리전 콜백 함수

void AAuraEnemySpawnVolume::OnSphereOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
	UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	// 부딫힌 액터가 플레이어가 아니면 리턴
	if (OtherActor->Implements<UPlayerInterface>() == false)
		return;
	
	bReached = true;

	for (AAuraEnemySpawnPoint* Point : SpawnPoints)
	{
		if (IsValid(Point))
		{
			Point->SpawnEnemy();
		}
	}
	Box->SetCollisionEnabled(ECollisionEnabled::NoCollision);
}

- OtherActor를 체크하여 Aura 플레이어가 아니면 리턴한다.

- 제공된 SpawnPoints 배열에 대해 적을 소환한다.

- 종료 후, 콜백 함수가 다시 호출되지 않도록 콜리전을 비활성화한다.

게임을 다시 로드할 때에는 bReached 변수로 인해 이 액터가 재생성되지 않을 것이다.

 

(4-4) SaveInterface의 LoadActor 오버라이드

void AAuraEnemySpawnVolume::LoadActor_Implementation()
{
    if (bReached)
    {
       Destroy();
    }
}

이미 이 볼륨 액터에 도달한 적이 있다면 파괴한다.

 

 

(5) 볼륨에 닿으면 특정 위치에 적이 소환되게 하기

(5-1) BP_SpawnPoints 클래스 디폴트 지정 후 배치

 

 

(5-2) BP_SpawnVolume 클래스 디폴트에 스폰 포인트 추가