interface
에서 명시한 함수를 통해서 호출할 수 있음.UInterface
를 상속받아 IItemInterface
같은 인터페이스를 만들 수 있음.상속은 부모의 실제 구현을 가져다 씀.
인터페이스는 함수의 틀만 빌려쓰고 그 안에 담길 코드는 직접 작성.
TArray<IInterface*> Somethings
과 같이 인터페이스 포인터 배열로 관리해서interface
를 정의하여 아이템 사용을 통일화UInterface
: 인터페이스를 만들어 함수의 원형들을 정의 (가상함수 형태)OnItemOverlap()
구현할 것interface
를 사용하지 않는다면?#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "IItemInterface.generated.h"
// 인터페이스를 UObject 시스템에서 사용하기 위한 기본 매크로
UINTERFACE(MinimalAPI)
class UItemInterface : public UInterface
{
GENERATED_BODY()
};
// 실제 C++ 레벨에서 사용할 함수 원형(시그니처)를 정의
class CHAPTER2_API IItemInterface
{
GENERATED_BODY()
public:
// 플레이어가 이 아이템의 범위에 들어왔을 때 호출
// Collision Component에 바인딩할 것.
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) = 0;
// 이 아이템의 유형(타입)을 반환 (예: "Coin", "Mine" 등)
virtual FName GetItemType() const = 0;
};
UINTERFACE(MinimalAPI)
class UItemInterface : public UInterface
IItemInterface
와 구분해서 사용.class CHAPTER2_API IItemInterface
.cpp
도 같이 생성됨..cpp
가 같이 생성되는 이유는 UE 자체적으로 .h
와 .cpp
매칭을 강조하고 있기 때문.IItemInterface
를 상속하는 BaseItem
을 작성할 것.//.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "ItemInterface.h"
#include "BaseItem.generated.h"
class USphereComponent;
UCLASS()
class CHAPTER2_API ABaseItem : public AActor, public IItemInterface
{
GENERATED_BODY()
public:
ABaseItem();
virtual FName GetItemType() const override;
protected:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item")
FName ItemType;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Item|Component")
USceneComponent* Scene;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Item|Component")
USphereComponent* Collision;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, 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 void DestroyItem();
};
//.cpp
#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->SetupAttachment(Scene);
Collision->SetCollisionProfileName(TEXT("OverlapAllDynamic"));
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, 5.f, FColor::Blue, FString::Printf(TEXT("Item activated")));
ActivateItem(OtherActor);
}
}
void ABaseItem::OnItemEndOverlap(
UPrimitiveComponent* OverlappedComp,
AActor* OtherActor,
UPrimitiveComponent* OtherComp,
int32 OtherBodyIndex)
{
}
FName ABaseItem::GetItemType() const
{
return ItemType;
}
void ABaseItem::ActivateItem(AActor* Activator)
{
}
void ABaseItem::DestroyItem()
{
Destroy(); // 사용 시 파괴
}
AItemBase
Collision
Collision Volume
SphereComponent
, BoxComponent
같은 충돌 컴포넌트를 붙여서 사용.Collision Component
컴포넌트와 겹치거나 통과할 때 발생Trigger
Collision
Collision Component
를 만들어서 제어함.Custom
으로 프리셋을 선택하면 이를 더 디테일하게 설정할 수 있음.NoCollision
: 충돌 비활성화Query Only
: Overlap, Hit 등 충돌 이벤트는 감지하지만, 물리적으로 튕기거나 밀리는 반응은 없음.Physics Only
: 물리 반응만 일어나고, 이벤트 (Overlap/Hit)는 발생하지 않음.Query and Physics
: 충돌 이벤트 + 물리 반응 모두 활성화Tag
를 이용.if(OtherActor->ActorHasTag("Player"))
{
// 플레이어 태그를 갖고 있음
}
Collision Component
를 설정했다면 이 충돌에 대한 이벤트를 바인딩해줘야함.OnTrigger~~
, OnCollision~~
충돌 관련 함수를 컴포넌트에서 구현OnComponentBeginOverlap
과 같은 델리게이트에 이벤트를 바인딩BaseItem
의 생성자에 구현#include "BaseItem.h"
#include "Components/SphereComponent.h"
// Sets default values
ABaseItem::ABaseItem()
{
PrimaryActorTick.bCanEverTick = false;
Scene = CreateDefaultSubobject<USceneComponent>(TEXT("Scene"));
SetRootComponent(Scene);
Collision = CreateDefaultSubobject<USphereComponent>(TEXT("Collision"));
Collision->SetupAttachment(Scene);
Collision->SetCollisionProfileName(TEXT("OverlapAllDynamic"));
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, 5.f, FColor::Blue, FString::Printf(TEXT("Item activated")));
ActivateItem(OtherActor);
}
}
void ABaseItem::OnItemEndOverlap(
UPrimitiveComponent* OverlappedComp,
AActor* OtherActor,
UPrimitiveComponent* OtherComp,
int32 OtherBodyIndex)
{
}
Collision->OnComponentBeginOverlap.AddDynamic(this, &ABaseItem::OnItemOverlap);
Collision->OnComponentEndOverlap.AddDynamic(this, &ABaseItem::OnItemEndOverlap);
AddDynamic
으로 이벤트 등록AddDynamic(Object, Func)
.h
에서 UFUNCTION()
을 붙여줘야함.// ItemInterface.h
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "ItemInterface.generated.h"
UINTERFACE(MinimalAPI)
class UItemInterface : public UInterface
{
GENERATED_BODY()
};
class CHAPTER2_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 FName GetItemType() const = 0;
// 아이템이 실질적으로 사용됐을때
virtual void ActivateItem(AActor* Activator) = 0;
};