구조
BP 샘플
코드 구성
부모 | 자식 | ||
부모.h | 부모(호출).cpp | 자식.h | 자식(실행).cpp |
DECLARE_MULTICAST_DELEGATE([Delegate 클래스명 선언]); UClass() { [Delegate 클래스명] [Delegate 객체]; } |
호출 [Delegate 객체].Broadcast(); ( multi일 경우 ) [Delegate 객체].ExcuteIfBound(); ( single일 경우 ) |
[부모class]->[Delegate 객체].AddUObject([자식](타겟 함수를 보유한 class의 객체), &[타겟 함수]); ( multi일 경우 ) ( single은 BindUObject // UObject 외에도 TsharedReference, Function 등 존재 ) |
|
BP에서 delegate에 Binding 하기
- static 함수로 BlueprintCallable함수를 만듬 ( delegate를 포함한 class의 생성 함수 )
- dynamic delegate는 BlueprintAssignable로 지정
상호참조 ( circular dependency )
- 문제 : Header 파일은 상호참조가 불가능함
- 예시
- A.h : # include B.h
- B.h : # include A.h
- 방법
- 한쪽에서는 소스파일에서 include
- 예시
- A.h : # include B.h
- B.cpp : # include A.h
전방선언 ( forward declaration )
- 문제 : 함수가 상호참조할 경우
- 같은 파일 내의 두 함수 중 하나는 상대방을 인식할 수 없음
- 다른 파일간의 두 함수 중 하나는 header에서 include를 못하므로, header에서 함수선언시 type을 정의할 수 없음
- 예시
- 본문의 경우, child.h에서 InitFunction 선언 시 argument로 dispatcherTest를 가질 수 없음
- 본문의 경우, child.h에서 InitFunction 선언 시 argument로 dispatcherTest를 가질 수 없음
- 방법
- 동일한 명칭의 가상(더미) 클래스를 만듬
- 헤더파일에서만 사용됨
- 소스파일에서는 #include가 되어있을 경우, 자동으로 대체되는걸로 보임
- DisPatchChild.h -
class ADispatcherTest;
- 동일한 명칭의 가상(더미) 클래스를 만듬
자신 클래스에 대한 참조 ( Self reference )
- 문제
- cpp에서 this는 const var* 형태 이므로 다른 class에 reference로 전달 시, 내부에 접근하지 못하는 문제
- cpp에서 this는 const var* 형태 이므로 다른 class에 reference로 전달 시, 내부에 접근하지 못하는 문제
- 예시
- this를 통해 얻은 pointer를 그대로 전달 시, 해당 객체가 보유한 [delegate] 객체를 call만 가능하고 bind는 불가능
- this를 통해 얻은 pointer를 그대로 전달 시, 해당 객체가 보유한 [delegate] 객체를 call만 가능하고 bind는 불가능
- 해결
- const_cast로 const 제거
- CustomClass* [var] = const_cast<CustomClass*>(this)
- CustomClass* [var] = const_cast<CustomClass*>(this)
- const_cast로 const 제거
- 추가정보
- const [Ptr] : 해당 ptr을 통해 내용물의 set 불가
- [Ptr] const : 해당 ptr의 참조 대상(메모리 주소) 변경 불가(재할당 불가)
- const [Ptr] const 가능
샘플 코드
부모.h
더보기
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Components/BoxComponent.h"
#include "Components/SceneComponent.h"
#include "Components/ArrowComponent.h"
#include "DisPatcherChild.h"
#include "GameFramework/Actor.h"
#include "DispatcherTest.generated.h"
DECLARE_MULTICAST_DELEGATE(TurnLightDelegate);
UCLASS()
class MYPROJECT_API ADispatcherTest final : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
ADispatcherTest();
UPROPERTY(EditAnywhere, blueprintReadWrite, Category = "Dispatcher")
USceneComponent* RootComp;
UPROPERTY(EditAnywhere, blueprintReadWrite, Category = "Dispatcher")
UBoxComponent* BoxComp;
UPROPERTY(EditAnywhere, blueprintReadWrite, Category = "Dispatcher")
UArrowComponent* ArrowComp;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dispatcher")
UStaticMeshComponent* BoxMesh;
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
bool bIsOn = false;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Dispatcher")
TArray<ADisPatcherChild*> MyChildren;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dispatcher")
int32 ChildCount=5;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dispatcher")
TSubclassOf<ADisPatcherChild> ChildClass;
UFUNCTION(BlueprintCallable, Category = "Dispatcher")
void CreateChildActor(int Count, TArray<ADisPatcherChild*>& ChildrenArr) const;
UFUNCTION()
void OnOverlapBegin(UPrimitiveComponent* OverlappedComp, AActor* OtherActor,
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep,
const FHitResult& SweepResult);
TurnLightDelegate TurnLightDelegatePtr; // 1. Declare a delegate pointer
};
부모.cpp
더보기
// Fill out your copyright notice in the Description page of Project Settings.
#include "DispatcherTest.h"
#include "ActorReferencesUtils.h"
// Sets default values
ADispatcherTest::ADispatcherTest()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
RootComp = CreateDefaultSubobject<USceneComponent>(TEXT("Root"));
RootComponent = RootComp;
BoxComp = CreateDefaultSubobject<UBoxComponent>(TEXT("BoxComp"));
BoxComp->SetupAttachment(RootComponent);
BoxComp->SetRelativeScale3D(FVector(2, 2, 2));
ArrowComp = CreateDefaultSubobject<UArrowComponent>(TEXT("ArrowComp"));
ArrowComp->SetRelativeRotation(FRotator(0, 90, 0));
ArrowComp->SetupAttachment(RootComponent);
BoxMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("BoxMesh"));
BoxMesh->SetRelativeScale3D(FVector(0.64, 0.64, 0.64));
BoxMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
BoxMesh->SetupAttachment(BoxComp);
BoxComp->OnComponentBeginOverlap.AddDynamic(this, &ADispatcherTest::OnOverlapBegin);
}
// Called when the game starts or when spawned
void ADispatcherTest::BeginPlay()
{
Super::BeginPlay();
CreateChildActor(ChildCount, MyChildren);
}
// Called every frame
void ADispatcherTest::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void ADispatcherTest::CreateChildActor(const int Count, TArray<ADisPatcherChild*>& ChildrenArr) const
{
for (int i = 0; i <= Count; i++)
{
FVector TargetLoc = GetActorLocation() + FVector(0, 100*i, 0);
TargetLoc -= this->GetActorLocation();
TargetLoc = FRotationMatrix(RootComponent->GetComponentTransform().Rotator()).TransformPosition(TargetLoc);
TargetLoc += this->GetActorLocation();
AActor* TempChild;
TempChild = GetWorld()->SpawnActorDeferred<AActor>(ChildClass, FTransform(TargetLoc), nullptr, nullptr, ESpawnActorCollisionHandlingMethod::AlwaysSpawn);
TempChild->FinishSpawning(FTransform(TargetLoc));
if (ADisPatcherChild* Child = Cast<ADisPatcherChild>(TempChild))
{
ADispatcherTest* SelfRef = const_cast<ADispatcherTest*>(this);
Child->InitFunction( SelfRef );
ChildrenArr.Add(Child);
}
}
//ParentActor->TurnLightDelegatePtr.BindSP(this, &ADisPatcherChild::TurnLight);
}
void ADispatcherTest::OnOverlapBegin(UPrimitiveComponent* OverlappedComp, AActor* OtherActor,
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
UE_LOG(LogTemp, Log, TEXT("Overlap Begin"));
TurnLightDelegatePtr.Broadcast();
//TurnLightDelegatePtr.ExecuteIfBound();
자식.h
더보기
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
//#include "DispatcherTest.h"
#include "Components/ArrowComponent.h"
#include "Components/SphereComponent.h"
#include "Components/SceneComponent.h"
#include "Components/StaticMeshComponent.h"
#include "Components/PointLightComponent.h"
#include "GameFramework/Actor.h"
#include "DisPatcherChild.generated.h"
class ADispatcherTest;
UCLASS()
class MYPROJECT_API ADisPatcherChild : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
ADisPatcherChild();
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dispatcher")
USceneComponent* RootComp;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dispatcher")
USphereComponent* SphereComp;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dispatcher")
UStaticMeshComponent* SphereMesh;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Dispatcher")
UPointLightComponent* PointLightComp;
bool bIsOn = false;
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
UFUNCTION(BlueprintCallable, Category = "Dispatcher")
void TurnLight();
void InitFunction(ADispatcherTest* ParentActor);
};
자식.cpp
더보기
// Fill out your copyright notice in the Description page of Project Settings.
#include "DisPatcherChild.h"
#include "DispatcherTest.h"
// Sets default values
ADisPatcherChild::ADisPatcherChild()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
RootComp = CreateDefaultSubobject<USceneComponent>(TEXT("Root"));
RootComponent = RootComp;
SphereComp = CreateDefaultSubobject<USphereComponent>(TEXT("sphereComp"));
SphereComp->SetupAttachment(RootComponent);
SphereMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("SphereMesh"));
SphereMesh->SetRelativeLocation(FVector(0, 0, 0));
SphereMesh->SetRelativeScale3D(FVector(0.5, 0.5, 0.5));
SphereMesh->SetupAttachment(SphereComp);
//SphereMesh->SetStaticMesh(ConstructorHelpers::FObjectFinder<UStaticMesh>(TEXT("StaticMesh'/Engine/BasicShapes/Sphere.Sphere'")).Object);
PointLightComp = CreateDefaultSubobject<UPointLightComponent>(TEXT("PointLightComp"));
PointLightComp->SetRelativeLocation(FVector(0, 0, 100));
PointLightComp->SetupAttachment(RootComponent);
PointLightComp->SetIntensity(1000);
}
// Called when the game starts or when spawned
void ADisPatcherChild::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void ADisPatcherChild::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void ADisPatcherChild::TurnLight()
{
if (bIsOn == false) // 불켜기
{
UE_LOG(LogTemp, Log, TEXT("TurnOn"));
PointLightComp->SetIntensity(100000);
bIsOn = true;
}
else// if (bIsOn == true) // 불끄기
{
UE_LOG(LogTemp, Log, TEXT("TurnOff"));
PointLightComp->SetIntensity(1000);
bIsOn = false;
}
}
void ADisPatcherChild::InitFunction(ADispatcherTest* ParentActor)
{
ADispatcherTest* ParentIns = Cast<ADispatcherTest>(ParentActor);
UE_LOG(LogTemp, Log, TEXT("Initted Child"));
//ParentIns->TurnLightDelegatePtr.BindUObject( this , &ADisPatcherChild::TurnLight);
//ParentIns->TurnLightDelegatePtr.BindUFunction(this, FName("TurnLight"));
ParentIns->TurnLightDelegatePtr.AddUObject(this, &ADisPatcherChild::TurnLight);
//ParentIns->TurnLightDelegatePtr.BindUObject(this, &ADisPatcherChild::TurnLight);
}
'Unreal > BP & UE Library' 카테고리의 다른 글
Class Name 접두 (0) | 2024.05.17 |
---|---|
code 내장 함수 (0) | 2024.05.17 |
BP Interface (0) | 2024.05.16 |
BP node list 1 (0) | 2024.05.16 |
BP Node 리스트 (0) | 2024.05.16 |