개요
오늘은 언리얼 엔진에서 아이템을 랜덤한 위치에 스폰하는 방법을 공부했다. 특히, 단순 랜덤 스폰이 아니라, 스폰 확률을 적용하는 방법까지 배우면서, 한층 더 게임 개발자다운 로직을 짜볼 수 있었다.
랜덤 위치에 아이템 스폰하기
Resources/Maps 폴더에는 3개의 레벨이 존재한다.BasicLevel → Intermediate Level → Advanced Level 순으로 맵 크기가 커진다.MainLevel을 삭제하고, BasicLevel을 기본 레벨로 설정했다.Edit → Project Settings → Maps & Modes → Default Maps 변경랜덤한 위치에 아이템을 스폰하려면?
UBoxComponent)를 이용하면 특정 영역 내에서 랜덤 좌표를 생성할 수 있다!C++로 SpawnVolume 클래스 만들기
UBoxComponent를 활용하여 스폰 영역을 설정GetRandomPointInVolume() 함수로 박스 내부 랜덤 좌표 얻기SpawnItem() 함수로 특정 아이템을 해당 위치에 스폰// 1) 박스 내 랜덤한 좌표 얻기
FVector ASpawnVolume::GetRandomPointInVolume() const
{
FVector BoxExtent = SpawningBox->GetScaledBoxExtent();
FVector BoxOrigin = SpawningBox->GetComponentLocation();
return BoxOrigin + FVector(
FMath::FRandRange(-BoxExtent.X, BoxExtent.X),
FMath::FRandRange(-BoxExtent.Y, BoxExtent.Y),
FMath::FRandRange(-BoxExtent.Z, BoxExtent.Z)
);
}
// 2) 특정 아이템을 랜덤한 위치에 스폰하기
void ASpawnVolume::SpawnItem(TSubclassOf<AActor> ItemClass)
{
if (!ItemClass) return;
GetWorld()->SpawnActor<AActor>(
ItemClass,
GetRandomPointInVolume(),
FRotator::ZeroRotator
);
}
아이템 랜덤 스폰 테스트하기
BP_SpawnVolume 블루프린트 생성BP_SpawnVolume을 배치BeginPlay 이벤트에 SpawnItem() 함수 연결반복적으로 스폰하고 싶다면?
Tick 이벤트에 연결하거나타이머를 활용해 주기적으로 SpawnItem()을 호출하면 된다.FItemSpawnRow 구조체 만들기USTRUCT(BlueprintType)
struct FItemSpawnRow : public FTableRowBase
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FName ItemName;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TSubclassOf<AActor> ItemClass;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float SpawnChance; // 아이템의 스폰 확률
};
DataTable로 임포트ItemDataTable을 활용하여 확률 기반 스폰 구현GetRandomItem())FItemSpawnRow* ASpawnVolume::GetRandomItem() const
{
if (!ItemDataTable) return nullptr;
// 1) 데이터 테이블에서 모든 행을 가져오기
TArray<FItemSpawnRow*> AllRows;
static const FString ContextString(TEXT("ItemSpawnContext"));
ItemDataTable->GetAllRows(ContextString, AllRows);
if (AllRows.IsEmpty()) return nullptr;
// 2) 전체 확률 합 구하기
float TotalChance = 0.0f;
for (const FItemSpawnRow* Row : AllRows)
{
if (Row)
{
TotalChance += Row->SpawnChance;
}
}
// 3) 랜덤 값 생성 (0 ~ TotalChance 사이)
float RandValue = FMath::FRandRange(0.0f, TotalChance);
float AccumulateChance = 0.0f;
// 4) 확률에 따라 아이템 선택
for (FItemSpawnRow* Row : AllRows)
{
AccumulateChance += Row->SpawnChance;
if (RandValue <= AccumulateChance)
{
return Row;
}
}
return nullptr;
}
먼저 데이터 테이블에서 모든 아이템과 확률 정보를 가져온다.
각 아이템의 SpawnChance를 누적하여 랜덤 값과 비교 → 확률적으로 아이템 선택!
SpawnRandomItem())void ASpawnVolume::SpawnRandomItem()
{
if (FItemSpawnRow* SelectedRow = GetRandomItem())
{
if (UClass* ActualClass = SelectedRow->ItemClass.Get())
{
SpawnItem(ActualClass);
}
}
}
GetRandomItem()을 호출해 확률적으로 선택된 아이템을 스폰.레벨마다 확률을 다르게 적용하는 방법
DataTable을 사용BP_SpawnVolume에서 ItemSpawnTable_Level1, ItemSpawnTable_Level2 등 개별적으로 설정DataTable에 LevelIndex 컬럼 추가하여 필터링DataTable에서 레벨별 데이터를 관리오늘의 배운 점 정리
UBoxComponent를 활용해 랜덤 위치에서 아이템을 스폰할 수 있다.
DataTable을 활용하면 아이템 스폰 확률을 손쉽게 관리할 수 있다.
확률 기반 랜덤 스폰 로직은,
레벨마다 다른 확률을 적용하려면, 개별 DataTable을 사용하거나, 레벨별 필터링을 활용할 수 있다.
오늘 배운 개념을 활용하면 적절한 확률로 다양한 아이템을 자연스럽게 스폰할 수 있다.