UE4_代理(Delegate)

来源:互联网 发布:ajax提交form表单json 编辑:程序博客网 时间:2024/05/16 17:31

代理(delegate)

  1. 代理相当于时间调度器,他们俩的功能类似。delegate多用于虚幻C++,而事件调度器多用于蓝图。  2. delegate可以让任意类对象都可以向某些特定事件进行注册,当特定的事件发生时就可以得到通知并进行处理。  3. 使用delegate可以绑定一个成员函数到任意对象,并由被绑定的对象进行呼叫,被绑定的对象可以不知道绑定在自己身上的成员函数的类型

EventHandler(事件处理器函数)

  1.  Actor和Component 都采用虚函数的方式内置了一些EventHandler,比如:  BeginPlay(),BeginDestroy()....等等,用复写的方式来实现。例如:  virtual void NotifyActorBeginOverlap(AActor* OtherActor);  virtual void NotifyActorEndOverlap(AActor* OtherActor);

创建Delegate并绑定

1.  声明   使用DECLARE_DELEGATE(FDelegateSignature)宏声明代理类型2. 类内FDelegateSignature myDelegate;声明一个以FDelegateSignature作为类型的成员变量3. 在接受通知事件的类内写一个EventHandler。例如BeginPlay()内获得分发事件的代理变量myDelegate,使用myDelegate.BindUObject()函数绑定Event Handler

执行Delegate

  myDelegate->ExecuteIfBound();

取消 delegate绑定

  myDelegate->unbind();

这里写图片描述

代码示例:(默认,先是.h文件,后是cpp文件)
DelegateGameMode

// Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "GameFramework/GameModeBase.h"#include "DelegateGameMode.generated.h"// 注册  //单播,只能注册一个DECLARE_DELEGATE(FStandardDelegateSignature)// 注册带有参数的DECLARE_DELEGATE_OneParam(FParamDelegateSignature,FLinearColor)// 多播DECLARE_MULTICAST_DELEGATE(FMulticastDelegateSingnature)/** *  */UCLASS()class BLANKUECPP_API ADelegateGameMode : public AGameModeBase{    GENERATED_BODY()public:    FStandardDelegateSignature StandardDelegate;    FParamDelegateSignature ParaDelegate;    FMulticastDelegateSingnature MultiDelegate;};
// Fill out your copyright notice in the Description page of Project Settings.#include "BlankUECPP.h"#include "DelegateGameMode.h"

BoomTriggerVolume

// Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "GameFramework/Actor.h"#include "BoomTriggerVolume.generated.h"DECLARE_EVENT(ABoomTriggerVolume,FPlayerEnteredEvent)UCLASS()class BLANKUECPP_API ABoomTriggerVolume : public AActor{    GENERATED_BODY()public:     // Sets default values for this actor's properties    ABoomTriggerVolume();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;    virtual void NotifyActorEndOverlap(AActor* OtherActor) override;public:        UPROPERTY()        UBoxComponent* TriggerBox;        FPlayerEnteredEvent OnplayerEntered;};
// Fill out your copyright notice in the Description page of Project Settings.#include "BlankUECPP.h"#include "DelegateGameMode.h"#include "BoomTriggerVolume.h"// Sets default valuesABoomTriggerVolume::ABoomTriggerVolume(){    // 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;    TriggerBox = CreateDefaultSubobject<UBoxComponent>(TEXT("TriggerBox01"));    // 设置盒子的大小    TriggerBox->SetBoxExtent(FVector(200, 200, 100));}// Called when the game starts or when spawnedvoid ABoomTriggerVolume::BeginPlay(){    Super::BeginPlay();}// Called every framevoid ABoomTriggerVolume::Tick(float DeltaTime){    Super::Tick(DeltaTime);}void ABoomTriggerVolume::NotifyActorBeginOverlap(AActor* OtherActor){    UWorld *world = GetWorld();    // 获得当前关卡的GameMode    AGameModeBase* gameMode = UGameplayStatics::GetGameMode(world);    // 转化成我们自己定义的GameMode,里边有我们注册的代理    ADelegateGameMode* delegateGM = Cast<ADelegateGameMode>(gameMode);    if (delegateGM)    {        delegateGM->StandardDelegate.ExecuteIfBound();        delegateGM->ParaDelegate.ExecuteIfBound(FLinearColor(0,1,0));        // 多播代理执行        delegateGM->MultiDelegate.Broadcast();    }        GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Cyan, FString::Printf(TEXT("%s Boom @@@@!"),*OtherActor->GetName()));        OnplayerEntered.Broadcast();}void ABoomTriggerVolume::NotifyActorEndOverlap(AActor* OtherActor){    UWorld *world = GetWorld();    AGameModeBase* gameMode = UGameplayStatics::GetGameMode(world);    ADelegateGameMode* delegateGM = Cast<ADelegateGameMode>(gameMode);    if (delegateGM)    {        delegateGM->StandardDelegate.ExecuteIfBound();        //带参数代理执行        //delegateGM->ParaDelegate.ExecuteIfBound(FLinearColor(0, 1, 0));        // 多播代理执行        delegateGM->MultiDelegate.Broadcast();    }    GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Cyan, FString::Printf(TEXT("%s Leave Boom @@@@!"),* OtherActor->GetName()));}

DelegateListener

// Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "GameFramework/Actor.h"#include "DelegateListener.generated.h"UCLASS()class BLANKUECPP_API ADelegateListener : public AActor{    GENERATED_BODY()public:     // Sets default values for this actor's properties    ADelegateListener();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 EndPlay(EEndPlayReason::Type EndPlayReason) override;public:    UFUNCTION()        void SetLightColor(FLinearColor LightColor);    UFUNCTION()        void EnableLight();    UFUNCTION()        void SetLightColorWithPayLoad(FLinearColor LightColor, bool isEnable);public:    // 加载灯泡颜色    UPROPERTY()        UPointLightComponent *PointLight;    bool isEnable = false;};
// Fill out your copyright notice in the Description page of Project Settings.#include "BlankUECPP.h"#include "DelegateGameMode.h"#include "DelegateListener.h"// Sets default valuesADelegateListener::ADelegateListener(){    // 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;    // 灯光的组件    PointLight = CreateDefaultSubobject < UPointLightComponent>(TEXT("PointLight01"));    // 把灯光组件作为根组件    RootComponent = PointLight;    PointLight->SetVisibility(false);    PointLight->SetLightColor(FLinearColor::Red);}// Called when the game starts or when spawnedvoid ADelegateListener::BeginPlay(){    Super::BeginPlay();    UWorld *world = GetWorld();    if (world)    {        // 获得世界里边的所有的gamemode        AGameModeBase *gm = UGameplayStatics::GetGameMode(world);        // 把世界里的所有的gamemode转成我们定义的DelegateGameMode        ADelegateGameMode *delegateGM = Cast<ADelegateGameMode>(gm);        if (delegateGM)        {            delegateGM->StandardDelegate.BindUObject(this, &ADelegateListener::EnableLight);// 开关灯            // 同 一个代理绑了两次,它只对最后一次代理生效,这就是单播的意义。            delegateGM->ParaDelegate.BindUObject(this, &ADelegateListener::SetLightColor);// 设置颜色            //delegateGM->ParaDelegate.BindUObject(this, &ADelegateListener::SetLightColorWithPayLoad, isEnable); // 这个isEnable是一个默认参数,默认为false            // 它会传给SetLightColorWithPayLoad这个函数            GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Cyan, TEXT("StandardDelegate.BindUObject"));        }    }}// Called every framevoid ADelegateListener::Tick(float DeltaTime){    Super::Tick(DeltaTime);}void ADelegateListener::SetLightColorWithPayLoad(FLinearColor LightColor, bool isEnable){    PointLight->SetLightColor(LightColor);    PointLight->SetVisibility(isEnable);    GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Cyan, TEXT("SetLightColorWithPayLoad"));}void ADelegateListener::SetLightColor(FLinearColor LightColor){    PointLight->SetLightColor(LightColor);    GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Cyan, TEXT("SetLightColor"));}void ADelegateListener::EnableLight(){    //PointLight->SetVisibility(true);    PointLight->ToggleVisibility();    GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Cyan, TEXT("EnableLight"));}void ADelegateListener::EndPlay(EEndPlayReason::Type EndPlayReason){    Super::EndPlay(EndPlayReason);    UWorld *world = GetWorld();    if (world)    {        AGameModeBase *gm = UGameplayStatics::GetGameMode(world);        ADelegateGameMode *delegateGM = Cast<ADelegateGameMode>(gm);        if (delegateGM)        {            delegateGM->StandardDelegate.Unbind();            GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Cyan, TEXT("StandardDelegate.Unbind()"));         }    }}

Explode 这个是爆炸的特效

// Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "GameFramework/Actor.h"#include "Explode.generated.h"UCLASS()class BLANKUECPP_API AExplode : public AActor{    GENERATED_BODY()public:     // Sets default values for this actor's properties    AExplode();protected:    // Called when the game starts or when spawned    virtual void BeginPlay() override;    virtual void EndPlay(EEndPlayReason::Type EndPlayReason) override;public:     // Called every frame    virtual void Tick(float DeltaTime) override;    void KaBoom();public:    FDelegateHandle EnterVolumHandle;    // 粒子组件    UPROPERTY()        UParticleSystemComponent* ParticleComp;    // 图标,用来指示我们的粒子效果在哪    UPROPERTY()        UBillboardComponent* BillBoard;};
// Fill out your copyright notice in the Description page of Project Settings.#include "BlankUECPP.h"#include "DelegateGameMode.h"#include "Explode.h"// Sets default valuesAExplode::AExplode(){    //  // 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;       ParticleComp = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("Particles"));       BillBoard = CreateDefaultSubobject<UBillboardComponent>(TEXT("BoardBoom"));       // BillBoard 作为根组件       RootComponent = BillBoard;       // FAttachmentTransformRules 是一个枚举       ParticleComp->AttachToComponent(GetRootComponent(),FAttachmentTransformRules::KeepRelativeTransform);       ConstructorHelpers::FObjectFinder<UTexture2D> boardAsset(TEXT("Texture2D'/Engine/EngineResources/AICON-Red.AICON-Red'"));       if (boardAsset.Object)       {           // 用SetSprite是因为在蓝图里就是这个属性设置图片           BillBoard->SetSprite(boardAsset.Object);       }       ConstructorHelpers::FObjectFinder<UParticleSystem> particleAsset(TEXT("ParticleSystem'/Game/P_Explosion.P_Explosion'"));       if (particleAsset.Object)       {              // SetTemplate 用来设置粒子效果           ParticleComp->SetTemplate(particleAsset.Object);           ParticleComp->bAutoActivate = false;// 默认不播放       }}// Called when the game starts or when spawnedvoid AExplode::BeginPlay(){    Super::BeginPlay();    UWorld *world = GetWorld();    if (world)    {        AGameModeBase *gm = UGameplayStatics::GetGameMode(world);        ADelegateGameMode *delegateGM = Cast<ADelegateGameMode>(gm);        if (delegateGM)        {            // MultiDelegate 是在DelegateGameMode文件里边的            EnterVolumHandle=delegateGM->MultiDelegate.AddUObject(this,&AExplode::KaBoom);            GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Cyan, TEXT("MultiDelegate.BindUObject"));        }    }}// Called every framevoid AExplode::Tick(float DeltaTime){    Super::Tick(DeltaTime);}void AExplode::EndPlay(EEndPlayReason::Type EndPlayReason){    Super::EndPlay(EndPlayReason);    UWorld *world = GetWorld();    if (world)    {        AGameModeBase *gm = UGameplayStatics::GetGameMode(world);        ADelegateGameMode *delegateGM = Cast<ADelegateGameMode>(gm);        if (delegateGM)        {            // 如果不记录这个EnterVolumeHandle这个Handle的话,用RemoveAll比较合适            delegateGM->MultiDelegate.Remove(EnterVolumHandle);            GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Cyan, TEXT("MultiDelegate.BindUObject"));        }    } }void AExplode::KaBoom(){    //ParticleComp->ActivateSystem(false);    // 激活粒子组件    ParticleComp->ToggleActive();}

UpDownPlatform 文件

// Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "GameFramework/Actor.h"#include "BoomTriggerVolume.h"#include "UpDownPlatform.generated.h"UCLASS()class BLANKUECPP_API AUpDownPlatform : public AActor{    GENERATED_BODY()public:     // Sets default values for this actor's properties    AUpDownPlatform();protected:    // Called when the game starts or when spawned    virtual void BeginPlay() override;    void Move();public:     // Called every frame    virtual void Tick(float DeltaTime) override;    UPROPERTY(EditAnyWhere)        UStaticMeshComponent* PlatformMesh;private:    UPROPERTY(EditAnyWhere,Category=Destination)    class ABoomTriggerVolume* TriggerVolum;    // 目标位置是我们在编辑器中手动指定的位置    UPROPERTY(EditAnyWhere, Category = Destination,meta=(AllowPrivateAccess=true,MakeEditWidget=true))        FVector TargetLocation;    FVector BeginLocation;};

// Fill out your copyright notice in the Description page of Project Settings.#include "BlankUECPP.h"#include "UpDownPlatform.h"// Sets default valuesAUpDownPlatform::AUpDownPlatform(){    // 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;    RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("SceneRoot"));    PlatformMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh0"));    PlatformMesh->SetupAttachment(RootComponent);    ConstructorHelpers::FObjectFinder<UStaticMesh> meshAsset(TEXT("StaticMesh'/Game/SM_Platform.SM_Platform'"));    if (meshAsset.Object)    {        PlatformMesh->SetStaticMesh(meshAsset.Object);        // 设置缩放比        PlatformMesh->SetRelativeScale3D(FVector(1, 1, 0.1));    }}// Called when the game starts or when spawnedvoid AUpDownPlatform::BeginPlay(){    Super::BeginPlay();    // GetActorLocation获得当前的位置    BeginLocation = GetActorLocation();    GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Blue, TargetLocation.ToString());    //把本地坐标转成世界坐标    TargetLocation= GetActorTransform().TransformPosition(TargetLocation);    GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Green, TEXT("After:")+TargetLocation.ToString());    if (TriggerVolum)    {        ABoomTriggerVolume *trigger = Cast<ABoomTriggerVolume>(TriggerVolum);        if (trigger)        {            // OnPlayerEntered 是在BoomTriggerVolume注册的一个事件            trigger->OnplayerEntered.AddUObject(this, &AUpDownPlatform::Move);            GEngine->AddOnScreenDebugMessage(-1,5.0f,FColor::Red,TEXT("OnPlayerEntered.AddUObject"));        }    }}// Called every framevoid AUpDownPlatform::Tick(float DeltaTime){    Super::Tick(DeltaTime);}void AUpDownPlatform::Move(){    // 实现来回移动功能,先记录当前的位置,判断当前位置是否是目标位置,再来回移动    FVector curLoc = GetActorLocation();    if (curLoc.Equals(TargetLocation))    {        SetActorLocation(BeginLocation);    }    else    {        SetActorLocation(TargetLocation);    }}
原创粉丝点击