UE4_代理(Delegate)

代理(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 values
ABoomTriggerVolume::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 spawned
void ABoomTriggerVolume::BeginPlay()
{
    Super::BeginPlay();

}

// Called every frame
void 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 values
ADelegateListener::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 spawned
void 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 frame
void 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 values
AExplode::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 spawned
void 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 frame
void 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 values
AUpDownPlatform::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 spawned
void 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 frame
void AUpDownPlatform::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

}

void AUpDownPlatform::Move()
{
    // 实现来回移动功能,先记录当前的位置,判断当前位置是否是目标位置,再来回移动
    FVector curLoc = GetActorLocation();
    if (curLoc.Equals(TargetLocation))
    {
        SetActorLocation(BeginLocation);
    }
    else
    {
        SetActorLocation(TargetLocation);
    }
}

猜你喜欢

转载自blog.csdn.net/longyanbuhui/article/details/76184140