zoukankan      html  css  js  c++  java
  • [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】turtle龟绘制开了花朵的树,程序画图
    【python】一行代码,使用pychorus提取音乐高潮部分
    【python】自动打开指定软件
    【VBA】用excel玩游戏,俄罗斯方块
    【python】3行代码搞定音频剪辑,入门版
    【python】3分钟搞定音频剪辑,进阶版
    【python】一键生成漂亮的节日快乐词云图
    【python】python学习之循环语句,小实验:九九乘法表
    【python】python学习之条件语句,小实验:商品打折后价格
    【python】使用webdriver在网页输入关键词并截屏
  • 原文地址:https://www.cnblogs.com/timy/p/8682719.html
Copyright © 2011-2022 走看看