[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 |