[45. Spawn Volume #1]

 

어떤 액터들을 맵에 직접 배치하기 보다는 스폰 볼륨을 통해 자동적으로 생성되게 하면 좀 더 좋을 것이다.

 

전의 실습에서 트리거 박스를 이용한것처럼 보이지 않는 박스를 만들어서 해당 범위 내의 랜덤한 위치에 액터를 스폰하게 만들 예정이다.

 

우선 Actor를 상속받는 SpawnVolume C++ 클래스를 만든다.

 

 

// SpawnVolume.h
public:
    // ≒const
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Spawning")
    class UBoxComponent* SpawningBox;

    UFUNCTION(BlueprintPure, Category = "Spawning")
    FVector GetSpawnPoint();
    
// SpawnVolume.cpp
#include "Kismet/KismetMathLibrary.h"

ASpawnVolume::ASpawnVolume()
{
    // 늘 하던 초기화
    SpawningBox = CreateDefaultSubobject<UBoxComponent>(TEXT("SpawningBox"));
}

FVector ASpawnVolume::GetSpawnPoint()
{
    // 박스의 크기를 반환받는다
    FVector Extent = SpawningBox->GetScaledBoxExtent();
    // 박스의 원점을 반환받는다
    FVector Origin = SpawningBox->GetComponentLocation();

    // 원점, 크기를 인자로 넘겨줘서 해당 범위 내의 랜덤한 좌표를 반환한다
    FVector Point = UKismetMathLibrary::RandomPointInBoundingBox(Origin, Extent);

    return Point;
}

 

UFUNCTION의 BlueprintPure는 const와 같은 개념이다. 해당 함수를 호출해도 객체에 아무런 영향도 미치지 못한다. 그래서 주로 위와 같이 getter에 사용한다.

 

 

// SpawnVolume.h
public:
    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Spawning")
    TSubclassOf<class ACritter> PawnToSpawn;

 

TSubclassOf 템플릿은 UClass 타입에 대한 안정성을 제공하는 템플릿 클래스이다.

받을 수 있는 타입을 한정짓는다.

 

만약 TSubclassOf가 아닌 UClass*라면 드롭다운 메뉴에서 모든 클래스가 다 나오게 된다. 그러다가 잘못된 클래스를 선택해서 사용하게 되면 런타임 도중 오류가 발생하게 된다.

 

하지만 TSubclassOf로 타입을 한정 지어주면 해당 타입만 표시되고 사용할 수 있다. 설령 잘못 선택했다 하더라도 타입은 맞기때문에 런타임 오류가 발생하지 않는다.

 

 

UClass* ClassA = UDamageType::StaticClass();
TSubclassOf<UDamageType> ClassB;
ClassB = ClassA; // 런타임 중에 체크
TSubclassOf<UDamageType_Lava> ClassC;
ClassB = ClassC; // 컴파일 중에 체크

 

블루프린트에서의 문제 방지 뿐만 아니라 C++ 작업시에도 서로 호환되지 않는 타입을 할당할 때, 오류를 검출하는 단계가 다르다.

 

 

이벤트그래프를 작성하고 SpawnVolume을 월드에 배치하면 플레이 할 때마다 박스 범위 내의 랜덤한 위치에 거미가 스폰된다. 

 

가운데 오브젝트를 다 날리고 적당히 배치하면 된다.

 

[46. Spawn Volume #2]

 

스폰 볼륨을 블루프린트가 아닌 C++에서 구현하는 것으로 변경해본다.

 

// SpawnVolume.h
public:	
    UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Spawning")
    void SpawnOurPawn(UClass* ToSpawn, const FVector& Location);
    
// SpawnVolume.cpp
void ASpawnVolume::SpawnOurPawn_Implementation(UClass* ToSpawn, const FVector& Location)
{
    if (ToSpawn)
    {
        UWorld* World = GetWorld();
        FActorSpawnParameters SpawnParams;

        if (World)
        {
            ACritter* CritterSpawned = World->SpawnActor<ACritter>(ToSpawn, Location, FRotator(0.f), SpawnParams);
        }
    }
}

 

UFUNCTION의 속성이 BlueprintNativeEvent라면 SpawnOurPawn을 구현하는것이 아니라 _Implimentation을 구현해야 한다.

블루프린트에서 해당 함수를 사용 시 재정의가 되지 않았다면 Implementation이 실행 될 것이다.

하지만 재정의가 된다면 해당 이벤트가 실행이 된다.

 

아래쪽에 있는 SpawnOurPawn 이벤트가 없다면 C++에서 구현한 것만 실행이 될 것이고 재정의를 했다면 해당 내용이 실행 될 것이다.

 

실습에서는 크리터가 생성되는 위치에 파티클을 하나 생성하는 것 뿐이므로 중간에 파티클 생성만 끼워넣었다.

 

이런 식으로 작동하게 된다.

 

 

[정리]

 

  • TSubclassOf는 UClass 타입의 안정성을 보장해 주는 템플릿 클래스이다.
    특정 UObject/UClass의 하위 클래스로 한정 짓고 런타임 에러를 방지한다.
    http://egloos.zum.com/sweeper/v/3225016
  • BlueprintNativeEvent는 블루프린트에서 오버라이딩 가능하게 해준다.

'언리얼 엔진 > UE4 C++' 카테고리의 다른 글

[UE C++] Gameplay Mechanics #4  (0) 2022.09.08
[UE C++] Gameplay Mechanics #3  (0) 2022.09.07
[UE C++] Gameplay Mechanics #1  (0) 2022.09.06
[UE C++] The Character Class #2  (0) 2022.09.06
[UE C++] The Character Class #1  (0) 2022.09.05

+ Recent posts