랜덤 위치에 아이템 스폰
콜리전 컴포넌트로 스폰 영역 지정
콜리전 컴포넌트 내부에 임의의 좌표를 뽑아 액터를 스폰할 수 있다.
Actor 클래스를 상속한 `SpawnVolume` 클래스를 생성
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "SpawnVolume.generated.h"
class UBoxComponent;
UCLASS()
class SPARTAPROJECT_API ASpawnVolume : public AActor
{
GENERATED_BODY()
public:
ASpawnVolume();
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Spawning")
USceneComponent* Scene;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Spawning")
UBoxComponent* SpawningBox;
UFUNCTION(BlueprintCallable, Category = "Spawning")
FVector GetRandomPointInVolume() const;
UFUNCTION(BlueprintCallable, Category = "Spawning")
void SpawnItem(TSubclassOf<AActor> ItemClass);
};
#include "SpawnVolume.h"
#include "Components/BoxComponent.h"
#include "Engine/World.h"
#include "GameFramework/Actor.h"
ASpawnVolume::ASpawnVolume()
{
PrimaryActorTick.bCanEverTick = false;
Scene = CreateDefaultSubobject<USceneComponent>(TEXT("Scene"));
SetRootComponent(Scene);
SpawningBox = CreateDefaultSubobject<UBoxComponent>(TEXT("SpawningBox"));
SpawningBox->SetupAttachment(Scene);
}
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)
);
}
void ASpawnVolume::SpawnItem(TSubclassOf<AActor> ItemClass)
{
if (!ItemClass) return;
GetWorld()->SpawnActor<AActor>(
ItemClass,
GetRandomPointInVolume(),
FRotator::ZeroRotator
);
}
랜덤 스폰
`BP_SpawnVolume` 생성 후 Level에 배치하고 위치와 스케일을 조정한다.
아이템 스폰을 위해서 노드 추가.
지속적인 스폰은 Tick 이벤트나 타이머를 사용
아이템 스폰 확률 데이터 테이블 생성
Item Data 구조체 생성
스폰 확률을 하드코딩하면 수정할 때마다 빌드를 다시 해야 한다.
데이터 테이블을 사용해서 이를 관리하기 위해 구조체 파일을 생성한다.
#pragma once
#include "CoreMinimal.h"
#include "Engine/DataTable.h"
#include "ItemSpawnRow.generated.h"
USTRUCT(BlueprintType)
struct FItemSpawnRow : public FTableRowBase
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FName ItemName;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TSubclassOf<AActor> ItemClass;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float SpawnChance;
};
언리얼 에디터를 켜서 Content Browser에서 아래와 같이 Data Table을 만든다.
생성한 Data Table에서 아래와 같이 Row를 추가하고 편집한다.
데이터 테이블을 사용해 스폰 확률 적용
...
#include "ItemSpawnRow.h"
...
UCLASS()
class SPARTAPROJECT_API ASpawnVolume : public AActor
{
...
public:
...
UFUNCTION(BlueprintCallable, Category = "Spawning")
void SpawnRandomItem();
protected:
...
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Spawning")
UDataTable* ItemDataTable;
...
FItemSpawnRow* GetRandomItem() const;
...
};
...
void ASpawnVolume::SpawnRandomItem()
{
if (FItemSpawnRow* SelectedRow = GetRandomItem())
{
if (UClass* ActualClass = SelectedRow->ItemClass.Get())
{
SpawnItem(ActualClass);
}
}
}
...
FItemSpawnRow* ASpawnVolume::GetRandomItem() const
{
if (!ItemDataTable) return nullptr;
TArray<FItemSpawnRow*> AllRows;
static const FString ContextString(TEXT("ItemSpawnContext"));
ItemDataTable->GetAllRows(ContextString, AllRows);
if (AllRows.IsEmpty()) return nullptr;
float TotalChance = 0.0f;
for (const FItemSpawnRow* Row : AllRows)
{
if (Row)
{
TotalChance += Row->SpawnChance;
}
}
const float RandValue = FMath::FRandRange(0.0f, TotalChance);
float AccumulateChance = 0.0f;
for (FItemSpawnRow* Row : AllRows)
{
AccumulateChance += Row->SpawnChance;
if (RandValue <= AccumulateChance)
{
return Row;
}
}
return nullptr;
}
...
`BP_SpawnVolume`에서 아래와 같이 세팅한다
레벨 별 다른 확률
레벨 별 다른 확률은 2가지 방법이 있다.
- 레벨 별 Data Table 적용
- Data Table에 레벨 구분 컬럼 추가
'본 캠프 > Note' 카테고리의 다른 글
[C++과 Unreal Engine으로 3D 게임 개발] 게임 루프 설계를 통한 게임 흐름 제어 (0) | 2025.09.30 |
---|---|
[C++과 Unreal Engine으로 3D 게임 개발] 캐릭터 체력 및 점수 관리 시스템 (0) | 2025.09.30 |
[C++과 Unreal Engine으로 3D 게임 개발] 충돌 이벤트와 아이템 획득 (0) | 2025.09.29 |
[C++과 Unreal Engine으로 3D 게임 개발] 인터페이스 기반 아이템 클래스 설계 (0) | 2025.09.29 |
[C++과 Unreal Engine으로 3D 게임 개발] State Machine 설계를 통한 캐릭터 동작 애니메이션 적용 (0) | 2025.09.19 |