• [UE4]事件处理(Handling Events)和委托(Delegate)代码示例(一)


    1. 通过重写虚函数来处理事件

    MyTriggerVolume.h

    自定义一个Actor类,添加一个 Box 组件作为触发区域,然后通过重写虚函数——NotifyActorBeginOverlap, NotifyActorEndOverlap来响应事件
    #pragma once  
      
    #include "GameFramework/Actor.h"  
    #include "MyTriggerVolume.generated.h"  
      
    UCLASS()  
    class TEST_API AMyTriggerVolume : public AActor  
    {  
        GENERATED_BODY()  
          
    public:   
        // Sets default values for this actor's properties  
        AMyTriggerVolume();  
      
        // Called when the game starts or when spawned  
        virtual void BeginPlay() override;  
          
        // Called every frame  
        virtual void Tick( float DeltaSeconds ) override;  
      
        UPROPERTY()  
        UBoxComponent* TriggerZone;  
          
        UFUNCTION()  
        virtual void NotifyActorBeginOverlap(AActor* OtherActor) override;  
        UFUNCTION()  
        virtual void NotifyActorEndOverlap(AActor* OtherActor) override;  
    };  

    MyTriggerVolume.cpp

    #include "Test.h"  
    #include "UE4TestGameMode.h"  
    #include "MyTriggerVolume.h"  
      
      
    // Sets default values  
    AMyTriggerVolume::AMyTriggerVolume()  
    {  
        // 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;  
        TriggerZone = CreateDefaultSubobject<UBoxComponent>("TriggerZone");  
        TriggerZone->SetBoxExtent(FVector(200, 200, 100));// 设置触发区域的范围  
    }  
      
    // Called when the game starts or when spawned  
    void AMyTriggerVolume::BeginPlay()  
    {  
        Super::BeginPlay();  
          
    }  
      
    // Called every frame  
    void AMyTriggerVolume::Tick( float DeltaTime )  
    {  
        Super::Tick( DeltaTime );  
      
    }  
      
    // 重写虚函数来响应事件  
    void AMyTriggerVolume::NotifyActorBeginOverlap(AActor* OtherActor)  
    {  
        GEngine->AddOnScreenDebugMessage(-1, 1, FColor::Red, FString::Printf(TEXT("%s entered me"), *(OtherActor->GetName())));// 注意FString::Format需要解引用  
    }  
    // 重写虚函数来响应事件  
    void AMyTriggerVolume::NotifyActorEndOverlap(AActor* OtherActor)  
    {  
        GEngine->AddOnScreenDebugMessage(-1, 1, FColor::Red, FString::Printf(TEXT("%s left me"), *(OtherActor->GetName())));  
    }  

    2. 绑定在 UFUNCTION 函数上的委托(不带参数)

    委托的好处在于,我们不用知道当前指派的函数的细节就可以调用它,它是一种安全版本的函数指针。

    以下代码将展示如何关联 UFUNCTION 到一个委托上,即委托执行时,UFUNCTION 将被调用。
    (效果为 当玩家进入触发区域,点光源亮)

    首先在 UE4TestGameMode.h 中添加一个委托声明(在 UCLASS 之前),如下:

    DECLARE_DELEGATE(FStandardDelegateSignature)  

    然后,为 UE4TestGameMode 类添加一个新成员

    FStandardDelegateSignature MyStandardDelegate;  

    接着,我们新建一个 Actor 类——DelegateListener,主要实现具体方法,以及负责委托的绑定和解绑 

    DelegateListener.h

    UCLASS()  
    class TEST_API ADelegateListener : public AActor  
    {  
        GENERATED_BODY()  
          
    public:   
        // Sets default values for this actor's properties  
        ADelegateListener();  
      
        // Called when the game starts or when spawned  
        virtual void BeginPlay() override;  
          
        // Called every frame  
        virtual void Tick( float DeltaSeconds ) override;  
          
        UFUNCTION()  
        void EnableLight();  
      
        UFUNCTION()  
        virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;  
      
        UPROPERTY()  
        UPointLightComponent* PointLight;  
          
    };  

    DelegateListener.cpp

    #include "Test.h"  
    #include "UE4TestGameMode.h" // 注意 include 的位置  
    #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>("PointLight");  
        RootComponent = PointLight;  
          
        PointLight->SetVisibility(false);  
    }  
      
    // Called when the game starts or when spawned  
    void ADelegateListener::BeginPlay()  
    {  
        Super::BeginPlay();  
        UWorld* TheWorld = GetWorld();  
        if (TheWorld != nullptr)  
        {  
            AGameMode* GameMode = Cast<AGameMode>(UGameplayStatics::GetGameMode(TheWorld));  
            AUE4TestGameMode * MyGameMode = Cast<AUE4TestkGameMode>(GameMode);  
            if (MyGameMode != nullptr)  
            {  
                // ❤ 绑定一个基于 UObject 的成员函数的委托。UObject 委托保留了一个弱引用在你的对象上,可以通过.ExecuteIfBound() 来调用委托的函数  
                MyGameMode->MyStandardDelegate.BindUObject(this, &ADelegateListener::EnableLight);// 其实就是将 EnableLight 函数绑定在了委托上。  
                     }  
        }  
      
    }  
      
    // Called every frame  
    void ADelegateListener::Tick( float DeltaTime )  
    {  
        Super::Tick( DeltaTime );  
      
    }  
      
    void ADelegateListener::EnableLight()  
    {  
        PointLight->SetVisibility(true);  
    }  
      
    void ADelegateListener::EndPlay(const EEndPlayReason::Type EndPlayReason)  
    {  
        Super::EndPlay(EndPlayReason);  
        UWorld* TheWorld = GetWorld();  
        if (TheWorld != nullptr)  
        {  
            AGameMode* GameMode = Cast<AGameMode>(UGameplayStatics::GetGameMode(TheWorld));  
            AUE4TestGameMode * MyGameMode = Cast<AUE4TestGameMode>(GameMode);  
            if (MyGameMode != nullptr)  
            {  
                // 解绑委托  
                MyGameMode->MyStandardDelegate.Unbind();  
            }  
        }  
    }  

    值得注意的是,如果我们绑定的是普通的C++函数,那么就应该将 BindUObject 改为 BindRaw,如果是静态方法,那就改为 BindStatic。

    最后,回到我们之前的 MyTriggerVolume.cpp, 利用 GameMode(我们之前声明委托和定义委托成员的地方) 执行委托,

    在 NotifyActorBeginOverlap 方法中添加以下代码:

    UWorld* TheWorld = GetWorld();  
    if (TheWorld != nullptr)  
    {  
        AGameMode* GameMode = Cast<AGameMode>(UGameplayStatics::GetGameMode(TheWorld));  
        AUE4TestGameMode * MyGameMode = Cast<AUE4TestGameMode>(GameMode);  
        // ❤ 执行委托的函数  
        MyGameMode->MyStandardDelegate.ExecuteIfBound();  
    }  
  • 相关阅读:
    python之变量与常量
    Python之历史
    关于图像重采样插值算法
    常用的日期的方法
    数组常用的方法
    判断鼠标进入容器方向
    用JS实现一个时钟的效果
    搞定flex布局
    整理 45 道 CSS 基础面试题(附答案)
    CSS实战3
  • 原文地址:https://www.cnblogs.com/timy/p/8682719.html
Copyright © 2020-2023  润新知