Unreal Engine 4 /4.26버전으로 수업을 진행합니다. 해당 내용은 수업에 대한 내용과 함께
개인적인 생각 및 정보를 토대로 글을 씀을 알립니다.
본 내용에 대하여 상업적으로 이용 및 배포를 금합니다.
이전내용) https://ppatabox.tistory.com/131
노션에서 보기
https://ppatabox.notion.site/UEC-_12_Light_Collision-ba3c544faa624887abc0612d3e2a47a2
다른 델리게이트를 또하나 만들어 볼 것이다.
델리게이션 DECLARE_DELEGATE 부분 들어가서 보면
델리게이트 콤비네이션이라는 헤더가 열린다.
델리게이트 종류가 모여있다.
델리게이트 형식은 항상 디클레어 델리게이트로 시작한다.
DECLARE_DELEGATE
싱글델리게이트 : 델리게이트 하나가 함수 하나를 소유 하는 것
DECLARE_MULTICAST_DELEGATE
멀티캐스트 도 있다.
DECLARE_DYNAMIC_DELEGATE
다이나믹 델리게이트 :
DECLARE_EVENT
이벤트
이것들의 공통 적인 형식은 Parm이 안붙어있다. 파라미터를 갖지 않는 다는 것들
/** Declares a delegate that can only bind to one native function at a time */
#define DECLARE_DELEGATE( DelegateName ) FUNC_DECLARE_DELEGATE( DelegateName, void )
/** Declares a broadcast delegate that can bind to multiple native functions simultaneously */
#define DECLARE_MULTICAST_DELEGATE( DelegateName ) FUNC_DECLARE_MULTICAST_DELEGATE( DelegateName, void )
/**
* Declares a multicast delegate that is meant to only be activated from OwningType
* NOTE: This behavior is not enforced and this type should be considered deprecated for new delegates, use normal multicast instead
*/
#define DECLARE_EVENT( OwningType, EventName ) FUNC_DECLARE_EVENT( OwningType, EventName, void )
/** Declares a blueprint-accessible delegate that can only bind to one UFUNCTION at a time */
#define DECLARE_DYNAMIC_DELEGATE( DelegateName ) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_DELEGATE) FUNC_DECLARE_DYNAMIC_DELEGATE( FWeakObjectPtr, DelegateName, DelegateName##_DelegateWrapper, , FUNC_CONCAT( *this ), void )
/** Declares a blueprint-accessible broadcast delegate that can bind to multiple native UFUNCTIONs simultaneously */
#define DECLARE_DYNAMIC_MULTICAST_DELEGATE( DelegateName ) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_DELEGATE) FUNC_DECLARE_DYNAMIC_MULTICAST_DELEGATE( FWeakObjectPtr, DelegateName, DelegateName##_DelegateWrapper, , FUNC_CONCAT( *this ), void )
Return은 싱글 캐스트 에만 있다. 멀티 캐스트는 없다.
/** Declares a delegate with return value that can only bind to one native function at a time */
#define DECLARE_DELEGATE_RetVal( ReturnValueType, DelegateName ) FUNC_DECLARE_DELEGATE( DelegateName, ReturnValueType )
// 파라미터 없이 리턴만 하는 함수 연결 하는 것 ReturnValueType -> 순서 대로 DelegateName
/** Declares a blueprint-accessible delegate with return value that can only bind to one UNFUNCTION at a time */
#define DECLARE_DYNAMIC_DELEGATE_RetVal( ReturnValueType, DelegateName ) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_DELEGATE) FUNC_DECLARE_DYNAMIC_DELEGATE_RETVAL( FWeakObjectPtr, DelegateName, DelegateName##_DelegateWrapper, ReturnValueType, , FUNC_CONCAT( *this ), ReturnValueType )
OneParam 있는 것들 어떤 타입이든 상관 없이
#define DECLARE_DELEGATE_RetVal_OneParam( ReturnValueType, ReturnValueType, Param1Type ) FUNC_DECLARE_DELEGATE( DelegateName, ReturnValueType, Param1Type )
함수 ReturnValueType ReturnValueType Param1Type 순서대로 돌아간다.
일반적인 델리게이트 파라미터의 변수명을 일치 시킬 필요 없다. 타입만 일치 시키면 된다.
다이나믹 델리게이트는 무조건 파라미터 명 까지 일치해야 한다.
#define DECLARE_DYNAMIC_DELEGATE_OneParam( DelegateName, Param1Type, Param1Name ) BODY_MACRO_COMBINE(CURRENT_FILE_ID,_,__LINE__,_DELEGATE) FUNC_DECLARE_DYNAMIC_DELEGATE( FWeakObjectPtr, DelegateName, DelegateName##_DelegateWrapper, FUNC_CONCAT( Param1Type InParam1 ), FUNC_CONCAT( *this, InParam1 ), void, Param1Type )
//Param1Name 파라미터 명
C02_Trigger.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "C04_Trigger.generated.h"
DECLARE_DELEGATE(FBoxLightOverlap); //void ___()
DECLARE_DELEGATE_RetVal_OneParam(FString, FBoxLightColorOverlap, FLinearColor);
UCLASS()
class U2110_03_API AC04_Trigger : public AActor
{
GENERATED_BODY()
private:
UPROPERTY(VisibleDefaultsOnly)
class USceneComponent* Root;
UPROPERTY(VisibleDefaultsOnly)
class UBoxComponent* Box;
UPROPERTY(VisibleDefaultsOnly)
class UTextRenderComponent* Text;
public:
AC04_Trigger();
protected:
virtual void BeginPlay() override;
private:
UFUNCTION()
void OnComponentBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
UFUNCTION()
void OnComponentEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
public:
FBoxLightOverlap OnBoxLightBeginOverlap;
FBoxLightOverlap OnBoxLightEndOverlap;
FBoxLightColorOverlap OnBoxLightColorOverlap;
};
C02_Trigger.cpp
#include "C04_Trigger.h"
#include "Global.h"
#include "Components/BoxComponent.h"
#include "Components/TextRenderComponent.h"
AC04_Trigger::AC04_Trigger()
{
CHelpers::CreateComponent<USceneComponent>(this, &Root, "Root");
CHelpers::CreateComponent<UBoxComponent>(this, &Box, "Box", Root);
CHelpers::CreateComponent<UTextRenderComponent>(this, &Text, "Text", Root);
Box->SetRelativeScale3D(FVector(3));
Box->bHiddenInGame = false;
Text->SetRelativeLocation(FVector(0, 0, 100));
Text->SetRelativeRotation(FRotator(0, 180, 0));
Text->SetRelativeScale3D(FVector(2));
Text->TextRenderColor = FColor::Red;
Text->HorizontalAlignment = EHorizTextAligment::EHTA_Center;
Text->Text = FText::FromString(GetName().Replace(L"Default__", L""));
}
void AC04_Trigger::BeginPlay()
{
Super::BeginPlay();
Box->OnComponentBeginOverlap.AddDynamic(this, &AC04_Trigger::OnComponentBeginOverlap);
Box->OnComponentEndOverlap.AddDynamic(this, &AC04_Trigger::OnComponentEndOverlap);
}
void AC04_Trigger::OnComponentBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
if (OnBoxLightBeginOverlap.IsBound())
OnBoxLightBeginOverlap.Execute();
if (OnBoxLightColorOverlap.IsBound()) //파라미터도 있고 리턴 밸류도 있다.
{
FLinearColor color = FLinearColor::MakeRandomColor();
FString str = OnBoxLightColorOverlap.Execute(color);
CLog::Print(str);
} //
}
void AC04_Trigger::OnComponentEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
if (OnBoxLightEndOverlap.IsBound())
OnBoxLightEndOverlap.Execute();
}
FString str = OnBoxLightColorOverlap.Execute(color);
실행은 똑같은데 현재 연결되어있는 델리게이트를 함수로 호출 해주는 것이다. 파라미터를 이것이 넘겨 주는 것이다.
FString str 델리게이트 연결된 함수에 연결되어 있음
C04_Light.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "C04_Light.generated.h"
UCLASS()
class U2110_03_API AC04_Light : public AActor
{
GENERATED_BODY()
private:
UPROPERTY(VisibleDefaultsOnly)
class USceneComponent* Root;
UPROPERTY(VisibleDefaultsOnly)
class UPointLightComponent* PointLight;
UPROPERTY(VisibleDefaultsOnly)
class UPointLightComponent* PointLight2;
UPROPERTY(VisibleDefaultsOnly)
class UTextRenderComponent* Text;
public:
AC04_Light();
protected:
virtual void BeginPlay() override;
private:
UFUNCTION()
void OnLight();
UFUNCTION()
void OffLight();
UFUNCTION()
FString OnRandomLight(FLinearColor InColor);
};
C04_Light.cpp
#include "C04_Light.h"
#include "Global.h"
#include "Components/PointLightComponent.h"
#include "Components/TextRenderComponent.h"
#include "C04_Trigger.h"
AC04_Light::AC04_Light()
{ //Trigger에서 만듬 으로 PointLight2 생성
CHelpers::CreateComponent<USceneComponent>(this, &Root, "Root");
CHelpers::CreateComponent<UPointLightComponent>(this, &PointLight, "PointLight", Root);
CHelpers::CreateComponent<UPointLightComponent>(this, &PointLight2, "PointLight2", Root);
CHelpers::CreateComponent<UTextRenderComponent>(this, &Text, "Text", Root);
PointLight->SetRelativeLocation(FVector(0, -50, 0));
PointLight->LightColor = FColor::Red;
PointLight->Intensity = 1e+4f; //1 * 10 ^ 4
PointLight->AttenuationRadius = 200;
PointLight2->SetRelativeLocation(FVector(0, 50, 0));
PointLight2->LightColor = FColor::Red;
PointLight2->Intensity = 1e+4f; //1 * 10 ^ 4
PointLight2->AttenuationRadius = 200;
Text->SetRelativeLocation(FVector(0, 0, 100));
Text->SetRelativeRotation(FRotator(0, 180, 0));
Text->SetRelativeScale3D(FVector(2));
Text->TextRenderColor = FColor::Red;
Text->HorizontalAlignment = EHorizTextAligment::EHTA_Center;
Text->Text = FText::FromString(GetName().Replace(L"Default__", L""));
}
void AC04_Light::BeginPlay()
{
Super::BeginPlay();
PointLight->SetVisibility(false);
PointLight2->SetVisibility(false);
//for (AActor* actor : GetWorld()->GetCurrentLevel()->Actors)
//{
// if (!!actor && actor->IsA<AC04_Trigger>())
// CLog::Log(actor->GetName());
//}
AC04_Trigger* trigger = CHelpers::FindActor<AC04_Trigger>(GetWorld());
//CLog::Log(trigger);
if (!!trigger)
{
trigger->OnBoxLightBeginOverlap.BindUFunction(this, "OnLight");
trigger->OnBoxLightEndOverlap.BindUFunction(this, "OffLight");
trigger->OnBoxLightColorOverlap.BindUFunction(this, "OnRandomLight");
}
}
void AC04_Light::OnLight()
{
PointLight->SetVisibility(true);
}
void AC04_Light::OffLight()
{
PointLight->SetVisibility(false);
PointLight2->SetVisibility(false);
}
FString AC04_Light::OnRandomLight(FLinearColor InColor)
{
PointLight2->SetVisibility(true);
PointLight2->SetLightColor(InColor);
return InColor.ToString();
}
들어가서 촤라락 켜질때는이런 델리게이트는 멀티캐스트로 만든다. 그리고 싱글 캐스트는 정확히 1:1 로 맵핑 되어야 하는 UI같은 것들은 사용 하되 일반적으로 대부분 멀티캐스트를 사용한다
C05_MultiTrigger.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "C05_MultiTrigger.generated.h"
DECLARE_MULTICAST_DELEGATE_TwoParams(FMultiLightOverlap, int32, FLinearColor);
UCLASS()
class U2110_03_API AC05_MultiTrigger : public AActor
{
GENERATED_BODY()
private:
UPROPERTY(VisibleDefaultsOnly)
class USceneComponent* Root;
UPROPERTY(VisibleDefaultsOnly)
class UBoxComponent* Box;
UPROPERTY(VisibleDefaultsOnly)
class UTextRenderComponent* Text;
public:
AC05_MultiTrigger();
protected:
virtual void BeginPlay() override;
private:
UFUNCTION()
void OnComponentBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
public:
FMultiLightOverlap OnMultiLightOverlap;
};
멀티캐스트를 체크하면 이벤트와 리턴밸류가 사라진다. 멀티캐스트는 리턴밸류를 사용할 수 없다. 이곳에서는 여러 함수를 사용할 것인데. 어떠한 함수를 리턴 할지 모른다. 결정할 수 없으니 2개 이상 함수를 연결하는 것은 리턴이 존재 하지 않는다. 이벤트는 기본 리턴이여서 없음
DECLARE_MULTICAST_DELEGATE_TwoParams(FMultiLightOverlap, int32, FLinearColor);
C05_MultiTrigger.cpp
#include "C05_MultiTrigger.h"
#include "Global.h"
#include "Components/BoxComponent.h"
#include "Components/TextRenderComponent.h"
AC05_MultiTrigger::AC05_MultiTrigger()
{
CHelpers::CreateComponent<USceneComponent>(this, &Root, "Root");
CHelpers::CreateComponent<UBoxComponent>(this, &Box, "Box", Root);
CHelpers::CreateComponent<UTextRenderComponent>(this, &Text, "Text", Root);
Box->SetRelativeScale3D(FVector(3));
Box->bHiddenInGame = false;
Text->SetRelativeLocation(FVector(0, 0, 100));
Text->SetRelativeRotation(FRotator(0, 180, 0));
Text->SetRelativeScale3D(FVector(2));
Text->TextRenderColor = FColor::Red;
Text->HorizontalAlignment = EHorizTextAligment::EHTA_Center;
Text->Text = FText::FromString(GetName().Replace(L"Default__", L""));
}
void AC05_MultiTrigger::BeginPlay()
{
Super::BeginPlay();
Box->OnComponentBeginOverlap.AddDynamic(this, &AC05_MultiTrigger::OnComponentBeginOverlap);
}
void AC05_MultiTrigger::OnComponentBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
//if (OnMultiLightOverlap.IsBound() == false) return;
CheckFalse(OnMultiLightOverlap.IsBound()); //매크로 false면 Return
int32 index = UKismetMathLibrary::RandomIntegerInRange(0, 2);
FLinearColor color = FLinearColor::MakeRandomColor();
OnMultiLightOverlap.Broadcast(index, color); // 하나 이상 연결 되었을때 하나일때는 Execute , 모든것에 전파 한다는 개념 Broadcast
}
//if (OnMultiLightOverlap.IsBound() == false) return; 하나 이상 연결 되어있다면 true가 나온다.
C05_Box.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "C05_Box.generated.h"
UCLASS()
class U2110_03_API AC05_Box : public AActor
{
GENERATED_BODY()
private:
UPROPERTY(VisibleDefaultsOnly)
class USceneComponent* Root;
UPROPERTY(VisibleDefaultsOnly)
class UStaticMeshComponent* Meshes[3];
UPROPERTY(VisibleDefaultsOnly)
class UTextRenderComponent* Text;
public:
AC05_Box();
protected:
virtual void BeginPlay() override;
private:
UFUNCTION()
void OnPhysics(int32 InIndex, FLinearColor InColor);
private:
class UMaterialInstanceDynamic* Materials[3];
FVector WorldLocation[3];
};
C05_Box.cpp
#include "C05_Box.h"
#include "Global.h"
#include "C05_MultiTrigger.h"
#include "Components/StaticMeshComponent.h"
#include "Components/TextRenderComponent.h"
#include "Materials/MaterialInstanceConstant.h"
#include "Materials/MaterialInstanceDynamic.h"
AC05_Box::AC05_Box()
{
CHelpers::CreateComponent<USceneComponent>(this, &Root, "Root");
CHelpers::CreateComponent<UTextRenderComponent>(this, &Text, "Text", Root);
UStaticMesh* mesh;
//언리얼에서 cube에 대한 경로
CHelpers::GetAsset<UStaticMesh>(&mesh, "StaticMesh'/Game/Meshes/Cube.Cube'");
for (int32 i = 0; i < 3; i++)
{
FString str;
str.Append("Meshes");
str.Append(FString::FromInt(i + 1)); // 이름 번호
CHelpers::CreateComponent<UStaticMeshComponent>(this, &Meshes[i], FName(str), Root);
Meshes[i]->SetRelativeLocation(FVector(0, i * 150, 0));
Meshes[i]->SetStaticMesh(mesh);
Meshes[i]->SetSimulatePhysics(true);
}
Text->SetRelativeLocation(FVector(0, 0, 100));
Text->SetRelativeRotation(FRotator(0, 180, 0));
Text->SetRelativeScale3D(FVector(2));
Text->TextRenderColor = FColor::Red;
Text->HorizontalAlignment = EHorizTextAligment::EHTA_Center;
Text->Text = FText::FromString(GetName().Replace(L"Default__", L""));
}
void AC05_Box::BeginPlay()
{
Super::BeginPlay();
UMaterialInstanceConstant* material;
//실행때는 컨스트럭션?
CHelpers::GetAssetDynamic<UMaterialInstanceConstant>(&material, "MaterialInstanceConstant'/Game/Materials/M_Color_White.M_Color_White'");
for (int32 i = 0; i < 3; i++)
{
Materials[i] = UMaterialInstanceDynamic::Create(material, this);
Materials[i]->SetVectorParameterValue("Color", FLinearColor::White);
Meshes[i]->SetMaterial(0, Materials[i]);
Meshes[i]->SetSimulatePhysics(false);
FTransform transform = Meshes[i]->GetComponentToWorld(); //
WorldLocation[i] = transform.GetLocation();
}
AC05_MultiTrigger* trigger = CHelpers::FindActor<AC05_MultiTrigger>(GetWorld());
CheckNull(trigger);
trigger->OnMultiLightOverlap.AddUFunction(this, "OnPhysics");
}
void AC05_Box::OnPhysics(int32 InIndex, FLinearColor InColor)
{
//기본값으로 돌려놓기 위함
for (int32 i = 0; i < 3; i++)
{
Materials[i]->SetVectorParameterValue("Color", FLinearColor::White);
Meshes[i]->SetSimulatePhysics(false);
Meshes[i]->SetWorldLocation(WorldLocation[i]);//원래 위치로 돌리기
}
Materials[InIndex]->SetVectorParameterValue("Color", InColor);
Meshes[InIndex]->SetSimulatePhysics(true);
}
찾아서 사용할 헤더들을 체크 해준다.
GetComponentToWorld : Component공간을 World공간으로 바꿔줌. 해당 Component가 있는 World 공간 위치로 리턴해준다. → 위치를 기억 FVector WorldLocation[3];
멀티캐스트라 하나더 출력 - 스폿라이트도 비슷한 개념
C05_SpotLight.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "C05_SpotLight.generated.h"
UCLASS()
class U2110_03_API AC05_SpotLight : public AActor
{
GENERATED_BODY()
private:
UPROPERTY(VisibleDefaultsOnly)
class USceneComponent* Root;
UPROPERTY(VisibleDefaultsOnly)
class USpotLightComponent* SpotLights[3];
UPROPERTY(VisibleDefaultsOnly)
class UTextRenderComponent* Text;
public:
AC05_SpotLight();
protected:
virtual void BeginPlay() override;
private:
UFUNCTION()
void OnLight(int32 InIndex, FLinearColor InColor);
};
C05_SpotLight.cpp
#include "C05_SpotLight.h"
#include "Global.h"
#include "Global.h"
#include "C05_MultiTrigger.h"
#include "Components/SpotLightComponent.h"
#include "Components/TextRenderComponent.h"
AC05_SpotLight::AC05_SpotLight()
{
CHelpers::CreateComponent<USceneComponent>(this, &Root, "Root");
CHelpers::CreateComponent<UTextRenderComponent>(this, &Text, "Text", Root);
for (int32 i = 0; i < 3; i++)
{
FString str;
str.Append("SpotLight");
str.Append(FString::FromInt(i + 1));
CHelpers::CreateComponent<USpotLightComponent>(this, &SpotLights[i], FName(str), Root);
SpotLights[i]->SetRelativeLocation(FVector(0, i * 150, 0));
SpotLights[i]->SetRelativeRotation(FRotator(-90, 0, 0)); //회전값을 밑으로
SpotLights[i]->Intensity = 1e+5f;
SpotLights[i]->OuterConeAngle = 25; // 각도 조정
}
Text->SetRelativeLocation(FVector(0, 0, 100));
Text->SetRelativeRotation(FRotator(0, 180, 0));
Text->SetRelativeScale3D(FVector(2));
Text->TextRenderColor = FColor::Red;
Text->HorizontalAlignment = EHorizTextAligment::EHTA_Center;
Text->Text = FText::FromString(GetName().Replace(L"Default__", L""));
}
void AC05_SpotLight::BeginPlay()
{
Super::BeginPlay();
AC05_MultiTrigger* trigger = CHelpers::FindActor<AC05_MultiTrigger>(GetWorld());
CheckNull(trigger);
trigger->OnMultiLightOverlap.AddUFunction(this, "OnLight");
}
void AC05_SpotLight::OnLight(int32 InIndex, FLinearColor InColor)
{
for (int32 i = 0; i < 3; i++)
SpotLights[i]->SetLightColor(FLinearColor::White);
SpotLights[InIndex]->SetLightColor(InColor);
}
AddRaw는 UObject가 아니라 C순수한 함수일 때만 다룬다. (UI때 사용할 수 있다) - AddUFunction
'Programming > Unreal [C++]' 카테고리의 다른 글
[UnrealEngine] C++_13_Deligate_ExplosionParticle (0) | 2022.05.20 |
---|---|
[UnrealEngine] C++_11_Overlap_Collision_02 (0) | 2022.05.18 |
[UnrealEngine] C++_10 _ActorOverlap (0) | 2022.05.16 |