Tworzenie Delegates w C++

W tym artykule pokaże ci jak tworzyć delegates w C ++. W prosty sposób możemy zdefiniować Delegata jako odniesienie do funkcji.

Unreal Engine ma szeroką gamę typów delegatów, co utrudnia zrozumienie wszystkich tych opcji.

Z tego powodu w tym artykule skupimy się na użytecznym przykładzie funkcjonalnym, który możesz dostosować do swojego projektu.

W pierwszej części artykułu przedstawię kroki niezbędne do korzystania z Delegata, pokazując fragmenty przykładowego kodu. W przykładowym użyciu zobaczysz pełny przykładowy kod.

W tym przykładzie utworzymy klasę o nazwie APlatformTrigger . Gdy Aktor nakłada się na wystąpienie APlatformTrigger , delegat zostanie użyty do powiadomienia, że ​​platforma została aktywowana. Inne klasy mogą wiązać funkcje z delegatem, które zostaną wykonane po aktywowaniu platformy.

Oto kroki niezbędne do utworzenia delegata:

Krok 1 – Utwórz typ delegata

Unreal Engine ma kilka makr, które są używane do tworzenia typu delegata. Poniższy kod utworzył typ delegata o nazwie FDelegateTrigger . 

DECLARE_DYNAMIC_MULTICAST_DELEGATE(FDelegateTrigger);

To makro musi znajdować się w pliku nagłówkowym klasy APlatformTrigger powyżej makra UCLASS () . Ten delegat jest DYNAMICZNY, aby umożliwić wiązanie w Blueprints i MULTICAST, aby umożliwić powiązanie więcej niż jednej funkcji. 

Krok 2 – Zdefiniuj zmienną przy użyciu utworzonego typu delegata

Poniższy wiersz definiuje zmienną typu FDelegateTrigger . Makro UPROPERTY (BlueprintAssignable) jest używane, aby umożliwić powiązanie w Blueprints. 

UPROPERTY(BlueprintAssignable)
FDelegateTrigger OnPlatformTriggered;

Krok 3 – Uruchom delegata

W naszym przykładzie delegat zostanie wykonany, gdy platforma się nakłada. Odbywa się to przez wywołanie funkcji Broadcast () zmiennej Delegate.

OnPlatformTriggered.Broadcast();

Kolejne kroki są wykonywane w innej klasie C ++. W tym przykładzie jest to klasa o nazwie AExplosionHandle . 

Krok 4 – Zdefiniuj wskaźnik do klasy, która ma delegata

Wskaźnik jest zdefiniowany jako UPROPERTY (), dzięki czemu instancję APlatformTrigger można wybrać w edytorze poziomów. 

UPROPERTY(EditAnywhere, Category = "Delegate Test")
APlatformTrigger* PlatformTriggerInstance;

Krok 5 – Zdefiniuj UFUNCTION (), który będzie powiązany z Delegatem

W tym przykładzie jest funkcja o nazwie Explode () , która aktywuje system cząstek. 

UFUNCTION()
void Explode();

Krok 6 – Powiązanie funkcji z delegatem

Wiązanie jest wykonywane w funkcji BeginPlay () . Wskaźnik PlatformTriggerInstance służy do wywoływania funkcji AddDynamic () zmiennej delegata OnPlatformTriggered . 

PlatformTriggerInstance->OnPlatformTriggered.AddDynamic(this,
                                                        &AExplosionHandle::Explode);

Kiedy Delegat APlatformTrigger klasy jest wykonywany, Explode () funkcja AExplosionHandle klasie zostanie wywołana.

W przykładowym użyciu zobaczymy również, jak łączyć się za pomocą schematów.

Przykładowe użycie:

W tym przykładzie będziesz potrzebować projektu C ++, który ma szablon trzeciej osoby z zawartością startową .

Utwórz klasę C ++ o nazwie PlatformTrigger, używając klasy Actor jako klasy nadrzędnej. Plik PlatformTrigger.h zawiera makro, które tworzy typ Delegate FDelegateTrigger i zmienną zdefiniowaną za pomocą tego typu:

#pragma once

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

DECLARE_DYNAMIC_MULTICAST_DELEGATE(FDelegateTrigger);

UCLASS()
class TUTOPROJECT_API APlatformTrigger : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	APlatformTrigger();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;
	
	virtual void NotifyActorBeginOverlap(AActor* OtherActor) override;
	
	UPROPERTY(VisibleAnywhere)
	USceneComponent* RootScene;

	UPROPERTY(VisibleAnywhere)
	UStaticMeshComponent* StaticMeshComponent;
	
	UPROPERTY(BlueprintAssignable)
	FDelegateTrigger OnPlatformTriggered;
};

PlatformTrigger klasa używa Static Mesh Shape_Cylinder . Wysokość zmniejszono, zmieniając skalę na 0,1 na osi Z. Delegat jest wykonywany w funkcji NotifyActorBeginOverlap () . Oto zawartość pliku PlatformTrigger.cpp:

#include "PlatformTrigger.h"

// Sets default values
APlatformTrigger::APlatformTrigger()
{
  // Set this actor to call Tick() every frame.
  PrimaryActorTick.bCanEverTick = true;
	
  RootScene = CreateDefaultSubobject<USceneComponent>("RootScene");
  RootComponent = RootScene;

  StaticMeshComponent = CreateDefaultSubobject<UStaticMeshComponent>("StaticMesh");
  StaticMeshComponent->SetupAttachment(RootScene);
  
  ConstructorHelpers::FObjectFinder<UStaticMesh> MeshFile(
    TEXT("/Game/StarterContent/Shapes/Shape_Cylinder.Shape_Cylinder"));

  if (MeshFile.Succeeded())
  {
    StaticMeshComponent->SetStaticMesh(MeshFile.Object);
  }
  
  StaticMeshComponent->SetCollisionResponseToAllChannels(
                                      ECollisionResponse::ECR_Overlap);
  StaticMeshComponent->SetRelativeScale3D(FVector(1.0f, 1.0f, 0.1f));
}


void APlatformTrigger::NotifyActorBeginOverlap(AActor* OtherActor)
{
  Super::NotifyActorBeginOverlap(OtherActor);
	
  OnPlatformTriggered.Broadcast();
}

// Called when the game starts or when spawned
void APlatformTrigger::BeginPlay()
{
  Super::BeginPlay();			
}

// Called every frame
void APlatformTrigger::Tick(float DeltaTime)
{
  Super::Tick(DeltaTime);
}

Utwórz kolejną klasę C ++ o nazwie ExplosionHandle, używając klasy Actor jako klasy nadrzędnej. Ta klasa ma wskaźnik do klasy PlatformTrigger i ma funkcję UFUNCTION (), która zostanie powiązana z delegatem. Plik ExplosionHandle.h wygląda następująco:

#pragma once

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

UCLASS()
class TUTOPROJECT_API AExplosionHandle : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	AExplosionHandle();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;	

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;
	
	UPROPERTY(VisibleAnywhere)
	USceneComponent* RootScene;
	
	UPROPERTY(VisibleAnywhere)	
	class UParticleSystemComponent* ParticleSystemComponent;
	
	UPROPERTY(EditAnywhere, Category = "Delegate Test")
	class APlatformTrigger* PlatformTriggerInstance;
	
	UFUNCTION()
	void Explode();
};

W konstruktorze mamy konfigurację układu cząstek, który reprezentuje eksplozję. W funkcji BeginPlay () funkcja Explode () jest powiązana z delegatem. Nie zapomnij dodać niezbędnego #include . Oto zawartość pliku ExplosionHandle.cpp:

#include "ExplosionHandle.h"
#include "PlatformTrigger.h"
#include "Particles/ParticleSystemComponent.h"

// Sets default values
AExplosionHandle::AExplosionHandle()
{
  // Set this actor to call Tick() every frame.
  PrimaryActorTick.bCanEverTick = true;

  // RootComponent initialization 
  RootScene = CreateDefaultSubobject<USceneComponent>("RootScene");
  RootComponent = RootScene;
  
  // ParticleSystemComponent initialization
  ParticleSystemComponent = CreateDefaultSubobject<UParticleSystemComponent>(
                              TEXT("ParticleSystemComponent"));
  ParticleSystemComponent->SetupAttachment(RootScene);
  ParticleSystemComponent->SetAutoActivate(false);
  
  ConstructorHelpers::FObjectFinder<UParticleSystem> ParticleTemplate(
    TEXT("/Game/StarterContent/Particles/P_Explosion.P_Explosion"));

  if (ParticleTemplate.Succeeded())
  {
    ParticleSystemComponent->SetTemplate(ParticleTemplate.Object);
  }
  
}

void AExplosionHandle::BeginPlay()
{
  Super::BeginPlay();
	
  if(PlatformTriggerInstance)
  {
    PlatformTriggerInstance->OnPlatformTriggered.AddDynamic(this,
&AExplosionHandle::Explode);
  }
	
}

void AExplosionHandle::Explode()
{
  ParticleSystemComponent->Activate();	
}

void AExplosionHandle::Tick(float DeltaTime)
{
  Super::Tick(DeltaTime);
}

Skompiluj kod C ++ i dodaj wystąpienie PlatformTrigger na poziomie. Dodaj instancję ExplosionHandle w pobliżu platformy i na karcie Szczegóły instancji w kategorii Delegate Test wybierz instancję PlatformTrigger .

Zacząć gre. Kiedy nachodzisz na platformę z Postacią, wybuch zostanie aktywowany.

Teraz powiążmy niestandardowe zdarzenie z delegatem za pomocą schematów.

Wybierz wystąpienie PlatformTrigger, które znajduje się na poziomie i otwórz Blueprint poziomu.

Kliknij prawym przyciskiem myszy na wykresie zdarzeń i wybierz opcję  Utwórz odniesienie do PlatformTrigger .

Przeciągnij z niebieskiej szpilki węzła i upuść go na wykresie zdarzeń, aby wyświetlić menu kontekstowe. Wyszukaj platformę i wybierz opcję Assign On Platform Triggered . Spowoduje to dodanie węzła Bind i nowego zdarzenia niestandardowego.

Dodaj Event BeginPlay i połącz się z węzłem Bind Event . Dodaj czynność Drukuj ciąg i połącz się z węzłem zdarzenia niestandardowego. Umieść wiadomość w węźle Print String i skompiluj Level Blueprint. Ostateczny schemat wygląda następująco:

Uruchom ponownie grę. Gdy platforma jest aktywna, delegat wywoła funkcję, która aktywuje eksplozję, a także wywoła niestandardowe zdarzenie zdefiniowane w Blueprints: 


Źródło:https://romeroblueprints.blogspot.com/2021/01/creating-delegates-in-c.html