Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |
Tags
- 프메
- 데이터베이스
- 스터디
- 정글사관학교
- 프린세스메이커
- VUE
- Unseen
- 스마일게이트
- Ajax
- 언리얼프로그래머
- Enhanced Input System
- 언리얼
- 레베카
- 미니프로젝트
- 카렌
- 파이썬서버
- node
- flask
- Jinja2
- 언리얼뮤지컬
- R
- 마인크래프트뮤지컬
- JWT
- Bootstrap4
- 게임개발
- EnhancedInput
- 알고풀자
- 으
- Express
- 디자드
Archives
- Today
- Total
Today, I will
[Unreal 디자인 패턴] 컴포넌트 패턴 본문
언리얼에서는 이미 컴포넌트 패턴을 적용하고 있다.
개발자들 역시 이 컴포넌트 패턴을 이용해 자주 사용할 만한 컴포넌트를 만들어놓고 필요한 액터에 붙일 수 있다.
Unreal의 컴포넌트 패턴(inventory c++ 예제)
인벤토리 컴포넌트를 만들어서 캐릭터에 붙이는 예제를 살펴보도록 한다.
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "InventoryComponent.generated.h"
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class THIRDPERSONTEMPLATE_API UInventoryComponent : public UActorComponent
{
GENERATED_BODY()
public:
// Sets default values for this component's properties
UInventoryComponent();
// 아이템 추가하기
UFUNCTION(BlueprintCallable)
void AddItem(const FName& ItemName, int32 Quantity);
// 아이템 제거하기
UFUNCTION(BlueprintCallable)
void RemoveItem(const FName& ItemName, int32 Quantity);
// 해당 아이템 수량 가져오기 == Find
UFUNCTION(BlueprintPure)
int32 GetItemQuantity(const FName& ItemName) const;
protected:
// Called when the game starts
virtual void BeginPlay() override;
public:
// Called every frame
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
private: // 접근못하게 막고, 접근 함수만을 public으로 둔다.
TMap<FName, int32> InventoryMap;
};
참고로 인자와 함수에 const를 달면 좋은 이유는 아래와 같이 chat gpt로 확인해보았다.
void UInventoryComponent::AddItem(const FName& ItemName, int32 Quantity)
{
//Find로 나오는 주소
int32* recentQuantity = InventoryMap.Find(ItemName);
if (recentQuantity) {
// 이미 해당 아이템이 인벤토리에 있는 경우 수량 증가
*recentQuantity += Quantity;
}
else {
InventoryMap.Add("ItemName", Quantity);
}
}
void UInventoryComponent::RemoveItem(const FName& ItemName, int32 Quantity)
{
//Find로 나오는 주소
int32* recentQuantity = InventoryMap.Find(ItemName);
if (recentQuantity) {
// 이미 해당 아이템이 인벤토리에 있는 경우 수량 감소
*recentQuantity -= Quantity;
if (*recentQuantity <=0) {
InventoryMap.Remove(ItemName);
}
}
}
int32 UInventoryComponent::GetItemQuantity(const FName& ItemName) const
{
const int32* recentQuantity = InventoryMap.Find(ItemName);
return recentQuantity ? *recentQuantity : 0;
}
위와 같이 블루프린트에서 컴포넌트로 달고 만든 함수를 가져올 수 있다.
전체 코드
#include "InventoryComponent.h"
UInventoryComponent::UInventoryComponent()
{
PrimaryComponentTick.bCanEverTick = true;
}
void UInventoryComponent::AddItem(const FName& ItemName, int32 Quantity)
{
//Find로 나오는 주소
int32* recentQuantity = InventoryMap.Find(ItemName);
if (recentQuantity) {
// 이미 해당 아이템이 인벤토리에 있는 경우 수량 증가
*recentQuantity += Quantity;
}
else {
InventoryMap.Add("ItemName", Quantity);
}
}
void UInventoryComponent::RemoveItem(const FName& ItemName, int32 Quantity)
{
//Find로 나오는 주소
int32* recentQuantity = InventoryMap.Find(ItemName);
if (recentQuantity) {
// 이미 해당 아이템이 인벤토리에 있는 경우 수량 감소
*recentQuantity -= Quantity;
if (*recentQuantity <=0) {
InventoryMap.Remove(ItemName);
}
}
}
int32 UInventoryComponent::GetItemQuantity(const FName& ItemName) const
{
const int32* recentQuantity = InventoryMap.Find(ItemName);
return recentQuantity ? *recentQuantity : 0;
}
// Called when the game starts
void UInventoryComponent::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void UInventoryComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
}
라인트레이스 컴포넌트화 예제
라인트레이스 역시 컴포넌트화하여 여러 액터에 붙일 수 있다.
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "LineTraceDetector.generated.h"
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class THIRDPERSONTEMPLATE_API ULineTraceDetector : public UActorComponent
{
GENERATED_BODY()
public:
// Sets default values for this component's properties
ULineTraceDetector();
protected:
// Called when the game starts
virtual void BeginPlay() override;
public:
// Called every frame
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
UFUNCTION(BlueprintCallable)
void PerformLineTrace();
private:
UPROPERTY(EditAnywhere)
float TraceDistance = 1000.f; // 트레이스 거리
UPROPERTY(EditAnywhere)
TSubclassOf<AActor> ActorClassToTrace;// 찾고자 하는 액터 클래스
UFUNCTION(BlueprintCallable)
void OnLineTraceHit(FHitResult HitResult);
};
void ULineTraceDetector::OnLineTraceHit(FHitResult HitResult)
{
//HitResult.GetActor()->IsA(ActorClassToTrace)
//HitResult.GetActor()==ActorClassToTrace
if (HitResult.GetActor() && HitResult.GetActor()->IsA(ActorClassToTrace))
{
// 원하는 클래스의 액터를 찾은 경우
AActor* FoundActor = HitResult.GetActor();
// 여기서 원하는 작업 ex 싸운다, 죽인다
if (FoundActor) {
GEngine->AddOnScreenDebugMessage(-1,5.9f, FColor::Green,(TEXT("%s"), *FoundActor->GetName()));
}
}
}
void ULineTraceDetector::PerformLineTrace()
{
FHitResult _HitOut;
AActor* ownerActor = Cast<AActor>(GetOwner());
FVector _Start = ownerActor->GetActorLocation();
FVector _End = _Start + (ownerActor->GetActorForwardVector() * TraceDistance);
FCollisionQueryParams _TraceCollisionParams;
_TraceCollisionParams.AddIgnoredActor(ownerActor);
bool bHit = GetWorld()->LineTraceSingleByChannel(_HitOut, _Start, _End, ECollisionChannel::ECC_Visibility, _TraceCollisionParams);
if (bHit) //hit 가 있다면,
{
OnLineTraceHit(_HitOut);
}
}
owner가 pawn이면 IA를 달아주어서 아래와 같이 키보드나 마우스 인터랙션을 줄 수 있겠다.
// Fill out your copyright notice in the Description page of Project Settings.
#include "LineTraceDetector.h"
#include "DrawDebugHelpers.h"
// Sets default values for this component's properties
ULineTraceDetector::ULineTraceDetector()
{
PrimaryComponentTick.bCanEverTick = true;
}
// Called when the game starts
void ULineTraceDetector::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void ULineTraceDetector::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
}
void ULineTraceDetector::PerformLineTrace()
{
FHitResult _HitOut;
AActor* ownerActor = Cast<AActor>(GetOwner());
FVector _Start = ownerActor->GetActorLocation();
FVector _End = _Start + (ownerActor->GetActorForwardVector() * TraceDistance);
FCollisionQueryParams _TraceCollisionParams;
_TraceCollisionParams.AddIgnoredActor(ownerActor);
bool bHit = GetWorld()->LineTraceSingleByChannel(_HitOut, _Start, _End, ECollisionChannel::ECC_Visibility, _TraceCollisionParams);
DrawDebugLine(GetWorld(), _Start, _End, FColor::Black, true, 3.0f);
if (bHit) //hit 가 있다면,
{
OnLineTraceHit(_HitOut);
}
}
void ULineTraceDetector::OnLineTraceHit(FHitResult HitResult)
{
//HitResult.GetActor()->IsA(ActorClassToTrace)
//HitResult.GetActor()==ActorClassToTrace
if (HitResult.GetActor() && HitResult.GetActor()->IsA(ActorClassToTrace))
{
// 원하는 클래스의 액터를 찾은 경우
AActor* FoundActor = HitResult.GetActor();
// 여기서 원하는 작업 ex 싸운다, 죽인다
if (FoundActor) {
GEngine->AddOnScreenDebugMessage(-1,5.9f, FColor::Green,(TEXT("%s"), *FoundActor->GetName()));
}
}
}
'Design Pattern' 카테고리의 다른 글
[디자인 패턴] 옵저버 패턴 crowd 군중 시뮬레이션 (0) | 2023.12.12 |
---|---|
[디자인 패턴] 다양한 인터랙션을 위한 Unreal 인터페이스 활용 (0) | 2023.12.12 |
[디자인 패턴] 생태계 조성에 유리한 추상 팩토리 Abstract Factory (0) | 2023.12.11 |