구조

 

 

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 )

  1. 문제 : Header 파일은 상호참조가 불가능함 
  2. 예시
    1. A.h : # include B.h
    2. B.h : # include A.h

  3. 방법
    1. 한쪽에서는 소스파일에서 include
    2. 예시
      1. A.h : # include B.h
      2. B.cpp : # include A.h

 

 

전방선언 ( forward declaration )

  1. 문제 : 함수가 상호참조할 경우
    1. 같은 파일 내의 두 함수 중 하나는 상대방을 인식할 수 없음
    2. 다른 파일간의 두 함수 중 하나는 header에서 include를 못하므로, header에서 함수선언시 type을 정의할 수 없음

  2. 예시
    1. 본문의 경우, child.h에서 InitFunction 선언 시 argument로 dispatcherTest를 가질 수 없음

  3. 방법
    1. 동일한 명칭의 가상(더미) 클래스를 만듬
      1. 헤더파일에서만 사용됨
      2. 소스파일에서는 #include가 되어있을 경우, 자동으로 대체되는걸로 보임
      3. DisPatchChild.h - 
        class ADispatcherTest;

 

자신 클래스에 대한 참조 ( Self reference )

  1. 문제
    1. cpp에서 this는 const var* 형태 이므로 다른 class에 reference로 전달 시, 내부에 접근하지 못하는 문제

  2. 예시
    1. this를 통해 얻은 pointer를 그대로 전달 시, 해당 객체가 보유한 [delegate] 객체를 call만 가능하고 bind는 불가능

  3. 해결
    1. const_cast로 const 제거
      1. CustomClass* [var] = const_cast<CustomClass*>(this)

  4. 추가정보
    1. const [Ptr] : 해당 ptr을 통해 내용물의 set 불가
    2. [Ptr] const : 해당 ptr의 참조 대상(메모리 주소) 변경 불가(재할당 불가)
    3. 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

+ Recent posts