언리얼 아이템 테이블을 이용한 아이템 스폰 및 오버랩시 아이템 사라지는 액션 구현
- ItemInterface
- BaseItem
- BigCoinItem
- SmallCoinItem
- HealingItem
- MineItem
- BaseItem
베이스 아이템을 통해 아이템에 오버랩시 사라지고 아이템 타입마다의 수치 적용
+ MineItem은 오버랩시 5.5초뒤에 광역 데미지를 구현
// 아이템 인터페이스
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "ItemInterface.generated.h"
// This class does not need to be modified.
UINTERFACE(MinimalAPI)
class UItemInterface : public UInterface
{
GENERATED_BODY()
};
class SPARTAPROJRCT_API IItemInterface
{
GENERATED_BODY()
public:
// 플레이어가 이 아이템의 범위에 들어왔을 때 호출
UFUNCTION()
virtual void OnItemOverlap(
UPrimitiveComponent* OverLappedComp, // 오버랩된 자기자신
AActor* OtherActor, // 오버랩한 액터
UPrimitiveComponent* OtherComp, // 콜리젼
int32 OtherBodyIndex,
bool bFromSweep,
const FHitResult& SweepResult) = 0;
// 플레이어가 이 아이템의 범위를 벗어났을 때 호출
UFUNCTION()
virtual void OnItemEndOverlap(
UPrimitiveComponent* OverLappedComp, // 오버랩된 자기자신
AActor* OtherActor, // 오버랩한 액터
UPrimitiveComponent* OtherComp, // 콜리젼
int32 OtherBodyIndex) = 0;
// 아이템이 사용되었을 때 호출
virtual void ActivateItem(AActor* Activator) = 0;
// 이 아이템의 유형(타입)을 반환 (예 : coin, mine 등)
virtual FName GetItemType() const = 0;
};
// ======================== < 베이스 아이템 cpp/h > =================================
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "ItemInterface.h"
#include "BaseItem.generated.h"
class USphereComponent;
UCLASS()
class SPARTAPROJRCT_API ABaseItem : public AActor, public IItemInterface
{
GENERATED_BODY()
public:
ABaseItem();
protected:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item")
FName ItemType;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item|Component")
USceneComponent* Scene;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item|Component")
USphereComponent* Collision;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item|Component")
UStaticMeshComponent* StaticMesh;
virtual void OnItemOverlap(
UPrimitiveComponent* OverLappedComp, // 오버랩된 자기자신
AActor* OtherActor, // 오버랩한 액터
UPrimitiveComponent* OtherComp, // 콜리젼
int32 OtherBodyIndex,
bool bFromSweep,
const FHitResult& SweepResult) override;
virtual void OnItemEndOverlap(
UPrimitiveComponent* OverLappedComp, // 오버랩된 자기자신
AActor* OtherActor, // 오버랩한 액터
UPrimitiveComponent* OtherComp, // 콜리젼
int32 OtherBodyIndex) override;
virtual void ActivateItem(AActor* Activator) override;
virtual FName GetItemType() const override;
// 아이템을 제거하는 공통 함수 (추가 이펙트나 로직을 넣을 수 있음)
virtual void DestroyItem();
};
#include "BaseItem.h"
#include "Components/SphereComponent.h"
ABaseItem::ABaseItem()
{
PrimaryActorTick.bCanEverTick = false;
Scene = CreateDefaultSubobject<USceneComponent>(TEXT("Scene"));
SetRootComponent(Scene);
Collision = CreateDefaultSubobject<USphereComponent>(TEXT("Collision"));
Collision->SetCollisionProfileName(TEXT("OverLapAllDynamic"));
Collision->SetupAttachment(Scene);
StaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMesh"));
StaticMesh->SetupAttachment(Collision);
// 이벤트 바인딩
Collision->OnComponentBeginOverlap.AddDynamic(this, &ABaseItem::OnItemOverlap);
Collision->OnComponentEndOverlap.AddDynamic(this, &ABaseItem::OnItemEndOverlap);
}
void ABaseItem::OnItemOverlap(UPrimitiveComponent* OverLappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
if (OtherActor && OtherActor->ActorHasTag("Player"))
{
GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Green, FString::Printf(TEXT("Overlap")));
ActivateItem(OtherActor);
}
}
void ABaseItem::OnItemEndOverlap(UPrimitiveComponent* OverLappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
}
void ABaseItem::ActivateItem(AActor* Activator)
{
}
FName ABaseItem::GetItemType() const
{
return ItemType;
}
void ABaseItem::DestroyItem()
{
Destroy();
}
아이템은 로직이 다른 MineItem만 작성
#pragma once
#include "CoreMinimal.h"
#include "BaseItem.h"
#include "MineItem.generated.h"
UCLASS()
class SPARTAPROJRCT_API AMineItem : public ABaseItem
{
GENERATED_BODY()
public:
AMineItem();
protected:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Mine")
USphereComponent* ExplosionCollision;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Mine")
float ExplosionDelay;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Mine")
float ExplosionRadius;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Mine")
int32 ExplosionDamage;
virtual void ActivateItem(AActor* Activator) override;
FTimerHandle ExplosionTimerHandle;
void Explode();
};
#include "MineItem.h"
#include "Components/SphereComponent.h"
AMineItem::AMineItem()
{
ExplosionDelay = 5.5f;
ExplosionRadius = 300.0f;
ExplosionDamage = 35;
ItemType = "Mine";
ExplosionCollision = CreateDefaultSubobject<USphereComponent>(TEXT("ExplosionCollision"));
ExplosionCollision->InitSphereRadius(ExplosionRadius);
ExplosionCollision->SetCollisionProfileName(TEXT("OverlapAllDynamic"));
ExplosionCollision->SetupAttachment(Scene);
}
void AMineItem::ActivateItem(AActor* Activator)
{
GetWorld()->GetTimerManager().SetTimer(ExplosionTimerHandle, this, &AMineItem::Explode, ExplosionDelay, false);
}
void AMineItem::Explode()
{
TArray<AActor*> OverlappingActors;
ExplosionCollision->GetOverlappingActors(OverlappingActors);
for (AActor* Actor : OverlappingActors)
{
if (Actor && Actor->ActorHasTag("Player"))
{
GEngine->AddOnScreenDebugMessage(
-1,
2.0f,
FColor::Red,
FString::Printf(TEXT("Player damaged %d by mine!"), ExplosionDamage));
}
}
DestroyItem();
}
ItemTable
ItemSpawnRow(데이터 테이블)
#pragma once
#include "CoreMinimal.h"
#include "Engine/DataTable.h"
#include "ItemSpawnRow.generated.h"
USTRUCT(BlueprintType)
struct FItemSpawnRow : public FTableRowBase
{
GENERATED_BODY()
public:
// 아이템 이름
UPROPERTY(EditAnywhere, BlueprintReadOnly)
FName ItemName;
// 어떤 아이템 클래스를 스폰할지
UPROPERTY(EditAnywhere, BlueprintReadOnly)
TSubclassOf<AActor> ItemClass;
// 이 아이템의 스폰 확률
UPROPERTY(EditAnywhere, BlueprintReadOnly)
float SpawnChance;
};
SpawnVolume
#pragma once
#include "CoreMinimal.h"
#include "ItemSpawnRow.h"
#include "GameFramework/Actor.h"
#include "SpawnVolume.generated.h"
class UBoxComponent;
UCLASS()
class SPARTAPROJRCT_API ASpawnVolume : public AActor
{
GENERATED_BODY()
public:
ASpawnVolume();
UFUNCTION(BlueprintCallable, Category = "Spawning")
void SpawnRandomItem();
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Spawning")
USceneComponent* Scene;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Spawning")
UBoxComponent* SpawningBox;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Spawning")
UDataTable* ItemDataTable;
FVector GetRandomPointInVolume() const;
FItemSpawnRow* GetRandomItem() const;
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);
ItemDataTable = nullptr;
}
void ASpawnVolume::SpawnRandomItem()
{
if (FItemSpawnRow* SelectedRow = GetRandomItem())
{
if (UClass* ActualClass = SelectedRow->ItemClass.Get())
{
SpawnItem(ActualClass);
}
}
}
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)
);
}
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;
}
void ASpawnVolume::SpawnItem(TSubclassOf<AActor> ItemClass)
{
if (!ItemClass) return;
GetWorld()->SpawnActor<AActor>(
ItemClass,
GetRandomPointInVolume(),
FRotator::ZeroRotator
);
}'언리얼' 카테고리의 다른 글
| Unreal_7기 | 챕터 3. C++과 Unreal Engine으로 3D 게임 개발 (0) | 2026.01.30 |
|---|---|
| [2025.01.26] Unreal_7기 | 챕터 3. C++과 Unreal Engine으로 3D 게임 개발 (0) | 2026.01.26 |
| [2025.01.22] Unreal_7기 | 챕터 3. C++과 Unreal Engine으로 3D 게임 개발 (0) | 2026.01.22 |
| [2025.01.21] Unreal_7기 | 챕터 3. C++과 Unreal Engine으로 3D 게임 개발 (0) | 2026.01.21 |
| [2025.01.20] Unreal_7기 | 챕터 3. C++과 Unreal Engine으로 3D 게임 개발 (0) | 2026.01.20 |
