< [이득우의 언리얼 프로그래밍 Part1 필기] 9. 설계 : 델리게이트

언리얼엔진5/[Part1] 이득우의 언리얼 프로그래밍

[이득우의 언리얼 프로그래밍 Part1 필기] 9. 설계 : 델리게이트

Rocketbabydolls 2024. 2. 19. 17:03

강한 결합

  • 클래스들이 서로 의존성을 가지는 경우.
  • 이전에 예시에서 사용한 Card를 Person이 가지고 있다고 가정했을 때, Card가 없는 경우 Person이 만들어질 수 없다. 
  • 이때 Person은 Card 에 대한 의존성을 가진다고 한다.

 

느슨한 결합

  • 실물에 의존하지 말고 추상적 설계에 의존하라.(DIP 원칙)
  • Person 이 Card 가 필요한 이유는 출입 확인 때문
  • 출입에 관련된 추상적인 설계에 의존하면 ICheck 를 상속받은 카드 인터페이스를 선언해서 해결
  • 유지 보수를 쉽게 만들어 준다.

 

※ DIP원칙 : 의존 역전 원칙 - DIP (Dependency Inversion Principle) DIP 원칙이란 객체에서 어떤 Class를 참조해서 사용해야하는 상황이 생긴다면, 그 Class를 직접 참조하는 것이 아니라 그 대상의 상위 요소(추상 클래스 or 인터페이스)로 참조하라는 원칙이다.

발행 구독 디자인 패턴

발행자가 관리해주는 것이 좋다.

 

언리얼 델리게이트 선언시 고려사항

 

어떤 데이터를 전달하고 받을 것인가? 인자의 수와 각각의 타입을 설계

  • 몇 개의 인자를 전달할 것인가?
  • 어떤 방식으로 전달할 것인가?
  • 일대일로 전달 / 일대다로 전달

프로그래밍 환경 설정

  • C++ 프로그래밍에서만 사용할 것인가?
  • UFUCNTION으로 지정된 블루프린트 함수와 사용할 것인가?

어떤 함수와 연결할 것인가?

  • 클래스 외부에 설계된 C++ 함수와 연결
  • 전역에 설계된 정적 함수와 연결
  • 언리얼 오브젝트의 멤버 함수와 연결 (대부분의 경우 이 방식을 사용)

 

DECLARE_{델리게이트유형}DELEGATE{함수정보}

 

DECLARE_DELEGATE

  • 일대일 형태로 C++ 만 지원  

DECLARE_MULTICAST

  • 일대다 형태로 C++만 지원

DECLARE_DYNAMIC

  • 일대일 형태로 블루프린트를 지원

DECLARE_DYNAMIC_MULTICAST

  • 일대다 형태로 블루프린트 지원

인자가 있을 때는 마지막에 Params 수를 지정해준다. (최대 9개)

 

 

예제 프리뷰

 

CourseInfo.h

#CourseInfo.h
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "CourseInfo.generated.h"

DECLARE_MULTICAST_DELEGATE_TwoParams(FCourseInfoOnChangedSignature, const FString&, const FString&); # 델리게이트 이름 지정과 인자 지정

/**
 * 
 */
UCLASS()
class UNREALDELEGATE_API UCourseInfo : public UObject
{
	GENERATED_BODY()
	
public:
	UCourseInfo();

	FCourseInfoOnChangedSignature OnChanged; # 멤버 변수로 델리게이트 선언

	void ChangeCourseInfo(const FString& InSchoolName, const FString& InNewContents); # 인자를 맞춰 함수 지정 (연결은 추후)
private:
	FString Contents;
};

 

CourseInfo.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "CourseInfo.h"

UCourseInfo::UCourseInfo()
{
	Contents = TEXT("기존 학사 정보");
}

void UCourseInfo::ChangeCourseInfo(const FString& InSchoolName, const FString& InNewContents)
{
	Contents = InNewContents;

	UE_LOG(LogTemp, Log, TEXT("[CourseInfo] 학사 정보가 변경되어 알림을 발송합니다."));
	OnChanged.Broadcast(InSchoolName, Contents); # 연결된 함수에 전부 브로드캐스팅
}

 

Student.h 

UCLASS()
class UNREALDELEGATE_API UStudent : public UPerson, public ILessonInterface
{
	GENERATED_BODY()
	
public:
	UStudent();

	virtual void DoLesson() override;

	void GetNotification(const FString& School, const FString& NewCourseInfo);
};

 

Student.cpp

void UStudent::GetNotification(const FString& School, const FString& NewCourseInfo)
{
	UE_LOG(LogTemp, Log, TEXT("[Student] %s님이 %s로부터 받은 메시지 : %s"), *Name, *School, *NewCourseInfo);
}

 

MyGameInstance.h

UCLASS()
class UNREALDELEGATE_API UMyGameInstance : public UGameInstance
{
	GENERATED_BODY()
	
public:
	UMyGameInstance();

	virtual void Init() override;

private:
	UPROPERTY()
	TObjectPtr<class UCourseInfo> CourseInfo;  # 포인터로 전방선언

	UPROPERTY()
	FString SchoolName;
	
};

 

MyGameInstance.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "MyGameInstance.h"
#include "Student.h"
#include "Teacher.h"
#include "Staff.h"
#include "Card.h"
#include "CourseInfo.h"

UMyGameInstance::UMyGameInstance()
{
	SchoolName = TEXT("학교");
}

void UMyGameInstance::Init()
{
	Super::Init();

	CourseInfo = NewObject<UCourseInfo>(this); # 실행중에 학사정보를 계속 유지할 것이기 때문에 Outer 는 this

	UE_LOG(LogTemp, Log, TEXT("============================"));

	UStudent* Student1 = NewObject<UStudent>();
	Student1->SetName(TEXT("학생1"));
	UStudent* Student2 = NewObject<UStudent>();
	Student2->SetName(TEXT("학생2"));
	UStudent* Student3 = NewObject<UStudent>();
	Student3->SetName(TEXT("학생3"));

	CourseInfo->OnChanged.AddUObject(Student1, &UStudent::GetNotification); # 클래스 멤버 함수를 레퍼런스로 지정 (델리게이트 연결 완료)
	CourseInfo->OnChanged.AddUObject(Student2, &UStudent::GetNotification);
	CourseInfo->OnChanged.AddUObject(Student3, &UStudent::GetNotification);

	CourseInfo->ChangeCourseInfo(SchoolName, TEXT("변경된 학사 정보"));

	UE_LOG(LogTemp, Log, TEXT("============================"));
}

 

UStudent* Student1 = NewObject<UStudent>();
Student1->SetName(TEXT("학생1"));
UStudent* Student2 = NewObject<UStudent>();
Student2->SetName(TEXT("학생2"));
UStudent* Student3 = NewObject<UStudent>();
Student3->SetName(TEXT("학생3"));

 

이렇게 선언한 오브젝트들은 더 이상 참조되지 않을 때 가비지 컬렉터가 Destroy 한다. 

공식 문서의 설명

 

 

오브젝트

기본적인 게임플레이 요소인 액터와 오브젝트에 대한 설명입니다.

docs.unrealengine.com

정리하기