프로그래밍 공부
작성일
2024. 4. 1. 12:11
작성자
WDmil
728x90

https://docs.unrealengine.com/4.27/ko/ProgrammingAndScripting/ProgrammingWithCPP/UnrealArchitecture/Delegates/

 

델리게이트

C++ 오브젝트 상의 멤버 함수를 가리키고 실행시키는 데이터 유형입니다.

docs.unrealengine.com

 

델리게이트를 활용해서 간단한 라이트 스위치를 구현한다.


델리게이트란?

 

델리게이트는 함수포인터를 옵저버 패턴처럼 사용하는 것 으로써, 함수의 위치값을 전역으로 가진다.

 

함수의 호출을 호출자가 하는것 이 아닌, 호출자가 호출했을 때, 해당 호출상황을 체크하는 다른 임의의 객체가 호출 이후에 다른 함수를 실행하는 걸 이야기 한다.

 

즉, 호출자가 타 객체를 알고있지 않아도 된다는 의미이다.


델리게이트 스위치

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

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "C09_1_DELEGATE.generated.h"

// Single Delegate
DECLARE_DELEGATE(FSingleDelegate) // 자료형 이름 / 접두사가 F로 시작해야 한다.


class UBoxComponent;
class UTextRenderComponent;

UCLASS()
class SUBPROJECT_API AC09_1_DELEGATE : public AActor
{
	GENERATED_BODY()

	UPROPERTY(VisibleDefaultsOnly)
	USceneComponent* Scene;

	UPROPERTY(VisibleDefaultsOnly)
	UBoxComponent* Box;

	UPROPERTY(VisibleDefaultsOnly)
	UTextRenderComponent* Text;
	
public:	
	AC09_1_DELEGATE();

public:
	FSingleDelegate SingleDelegate;

protected:
	virtual void BeginPlay() override;

private:
	UFUNCTION()
	void OnBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);

};

델리게이트를 시작시 선언하여 객체를 정의해준다.

 

객체의 자료형 에 대한 델리게이트는 여러가지 종류가 있으며, 현재 사용하는 델리게이트는 싱글 델리게이트 이다.

(다양한 델리게이트 정보는 위 델리게이트 언리얼 링크를 참조)

델리게이트에서 신 과 Box 그리고 Text를 선언해준다. 객체의 이름을 Text로 알려주고, BoxCollision에 충돌했을 때 델리게이트가 동작하게 할 것 이다.

 

beginOverlap은 함수임으로, UFunction()을 함수를 선언해준다.

 

델리게이트는 임의의 함수에 연결하여 사용하는것 임으로, public으로 SingleDelegate를 선언하여 사용할 수 있도록 정의해준다.

 

CPP

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

#include "Utillites/Helper.h"
#include "Components/BoxComponent.h"
#include "Components/TextRenderComponent.h"


// Sets default values
AC09_1_DELEGATE::AC09_1_DELEGATE()
{
	Scene = Helper::CreateSceneComponent<USceneComponent>(this, "Scene");
	Text = Helper::CreateSceneComponent<UTextRenderComponent>(this, "Text", Scene);

	// 블루프린트에서 위치값 조정해서 확인하고 만드시는 과정이 있어야 합니다.

	Text->SetRelativeRotation(FRotator(0, 180, 0));
	Text->SetRelativeLocation(FVector(0, 0, 120));
	Text->SetHorizontalAlignment(EHorizTextAligment::EHTA_Center);
	Text->SetVerticalAlignment(EVerticalTextAligment::EVRTA_TextCenter);
	Text->Text = FText::FromString(GetName().Replace(L"Default__", L""));
	Text->SetTextRenderColor(FColor::Yellow);

	Box = Helper::CreateSceneComponent<UBoxComponent>(this, "Box", Scene);
	Box->SetRelativeScale3D(FVector(3));
	Box->SetHiddenInGame(false);
}

void AC09_1_DELEGATE::BeginPlay()
{
	Super::BeginPlay();

	Box->OnComponentBeginOverlap.AddDynamic(this, &AC09_1_DELEGATE::OnBeginOverlap);;

}

void AC09_1_DELEGATE::OnBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	// 안전검사 -> 실행
	if (SingleDelegate.IsBound())
		SingleDelegate.Execute();
}

 

CPP에서는 사용하는 값에 대한 정의를 선언해준다. Collision과 Text를 할당한다.

 

BeginPlay()를 통해, OnCOmponentBeginOverlap에 대한, 기본정의된 COllision함수의 beginOverlap 동작에 대해 연결해준다.

 

OnBeginOverlap에 대한 함수로 현재 정의된 Delegate에 접근하여, OnBeginOverlap이 실행되었을 때, SingleDelegate를 Execute하여 호출해준다.

 

이로써, SingeDelegate는, OnBeginOverlap이 실행되었을 때 호출되게 된다.

 


C09_2_SingleDelegate_A

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "C09_2_SingleDelegate_A.generated.h"

class UTextRenderComponent;
class USpotLightComponent;

UCLASS()
class SUBPROJECT_API AC09_2_SingleDelegate_A : public AActor
{
	GENERATED_BODY()
	
	UPROPERTY(VisibleDefaultsOnly)
	USceneComponent* Scene;

	UPROPERTY(VisibleDefaultsOnly)
	UTextRenderComponent* Text;

	UPROPERTY(VisibleDefaultsOnly)
	UParticleSystem* Particles[3];

	UPROPERTY(VisibleDefaultsOnly)
	USpotLightComponent* SpotLight;


public:	
	AC09_2_SingleDelegate_A();

protected:
	virtual void BeginPlay() override;

private:
	UFUNCTION()
	void SwitchSpotLight();

	UFUNCTION()
	void OnExplosion(int32 index);


};

 

델리게이트가 실행되었을때, 임의의 함수를 실행할 수 있도록, 델리게이트를 추적하는 객체를 생성한다.

 

델리게이트가 실행되면, SwitchSpotLight가 실행되어, 라이트가 꺼졌다가 켜질것 이다.

#include "C09_2_SingleDelegate_A.h"
#include "C09_1_DELEGATE.h"

#include "Components/TextRenderComponent.h"
#include "Components/SpotLightComponent.h"
#include "Particles/ParticleSystem.h"
#include "Kismet/GameplayStatics.h"
#include "Utillites/Helper.h"

AC09_2_SingleDelegate_A::AC09_2_SingleDelegate_A()
{
	Scene = Helper::CreateSceneComponent<USceneComponent>(this, "Scene");
	Text = Helper::CreateSceneComponent<UTextRenderComponent>(this, "Text");
	SpotLight = Helper::CreateSceneComponent<USpotLightComponent>(this, "Spot");

	// 블루프린트에서 위치값 조정해서 확인하고 만드시는 과정이 있어야 합니다.

	Text->SetRelativeRotation(FRotator(0, 180, 0));
	Text->SetRelativeLocation(FVector(0, 0, 120));
	Text->SetHorizontalAlignment(EHorizTextAligment::EHTA_Center);
	Text->SetVerticalAlignment(EVerticalTextAligment::EVRTA_TextCenter);
	Text->Text = FText::FromString(GetName().Replace(L"Default__", L""));
	Text->SetTextRenderColor(FColor::Yellow);


	Particles[0] = Helper::GetAsset<UParticleSystem>("/Script/Engine.ParticleSystem'/Game/Particles/P_Explosion.P_Explosion'");
	Particles[0] = Helper::GetAsset<UParticleSystem>("/Script/Engine.ParticleSystem'/Game/Particles/P_Explosion1.P_Explosion1'");
	Particles[0] = Helper::GetAsset<UParticleSystem>("/Script/Engine.ParticleSystem'/Game/Particles/P_Explosion2.P_Explosion2'");

	SpotLight->SetRelativeLocation(FVector(0, 0, 350));
	SpotLight->SetRelativeRotation(FRotator(-90, 0, 0));
	SpotLight->SetLightColor(FColor::Purple);
	SpotLight->SetIntensity(10000);
	SpotLight->SetVisibility(true);
}

void AC09_2_SingleDelegate_A::BeginPlay()
{
	Super::BeginPlay();

	AC09_1_DELEGATE* Switch = Helper::GetActor<AC09_1_DELEGATE>(GetWorld());

	if (Switch)
	{
		Switch->SingleDelegate.BindUFunction(this, "SwitchSpotLight");
	}
}

void AC09_2_SingleDelegate_A::SwitchSpotLight()
{
	SpotLight->SetVisibility(!SpotLight->GetVisibleFlag());
}

void AC09_2_SingleDelegate_A::OnExplosion(int32 index)
{
}

 

생성자에서 객체의 초기값을 세팅해준다.

 

스포트라이트와 Text 그리고 파티클을 정의해준다.

 

BeginPlay에서 현재 정의된 델리게이트를 가져오기 위해, World상에 존재하는 AC09_1_Delegate를 참조한다.

 

참조된 Switch가 존재할 경우, SingleDelegate의 BindFunction을 통해 현재 정의된 SwitchSpotLight를 바인드 해준다.

 

그럼으로써, SingleDelegate가 실행되면, SpotLight가 실행되어 현재 라이트가 꺼졌다가 켜지는 행동이 발생할 것 이다.


테스트

728x90