代理(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);
}
}