2. 将变量和函数公开到编辑器

使用UPROPERTY和UFUNCTION宏对编辑器公开变量和函数

Windows
MacOS
Linux
On this page
  1. 倒计时定时器当前被硬编码为使用3秒的值。在编辑器中将倒计时设为任意数值十分实用,也很容易实现。在 Visual Studio 中,我们打开Countdown.h可以找到拥有以下代码的行:

    int32 CountdownTime;

    为将此变量公开到 虚幻引擎,我们需要将其设为 UPROPERTY。这是的引擎能在启动游戏或加载保存关卡时保存变量的值。含空括号的UPROPERTY标签将被添加到其所影响变量的正上方:

    UPROPERTY()
    int32 CountdownTime;

    UPROPERTY支持多项参数,其将修改 虚幻引擎 对变量的使用方式。我们需要将变量设为可编辑,因此可以添加 EditAnywhere 参数:

    UPROPERTY(EditAnywhere)
    int32 CountdownTime;

    ExposingVariable.png

    还可在C++中为变量添加一个注释。这个注释将成为 虚幻编辑器 中变量的描述,如下所示:

    // 倒计时运行时长(以秒计)
    UPROPERTY(EditAnywhere)
    int32 CountdownTime;

    CommentingVariable.png

    对UPROPERTY还可进行更多操作,之后可继续研究其它参数,如 BlueprintReadWriteCategory。但目前暂时不需要操作。

    返回 虚幻编辑器 并按下 编译(Compile),变量将出现在之前放置的ACountdown的 细节面板 中。修改此数字并按下 运行(Play) 按钮即可对不同的定时器数值进行测试。

  2. 除修改定时器数值外,还可使非编程开发者能够改变倒计时结束后发生的情况。在 Visual Studio 中打开Countdown.h并找到以下行:

    void CountdownHasFinished();

    将此函数以如下方式设为一个 UFUNCTION,即可将其对 虚幻引擎 公开:

    UFUNCTION()
    void CountdownHasFinished();

    和UPROPERTY宏一样,我们需要提供可使用它进行何种操作的信息,以便为非编程开发者启用更多功能和访问权。可以考虑3个选项:

    1. BlueprintCallable 函数在C++中编写,可从 蓝图图表 中进行调用,但不编辑C++代码便无法对其进行修改或覆盖。以此方式标记的函数通常是已编程、以便非编程人士使用的功能,但不应对其进行修改(或者说完全无需对其进行修改)。任意类型的数学函数便是这个的简单实例。

    2. BlueprintImplementableEvent 函数在C++标头(.h)文件中设置,但函数主体整体在蓝图图表中编写,而非C++。它们被创建出来后,非编程人员即可创建针对特殊情况(其无预期默认操作或标准行为)的自定义响应。举例而言,其为太空船游戏中升级道具与玩家船只接触时发生的事件。

    3. BlueprintNativeEvent 函数则是BlueprintCallable和BlueprintImplementableEvent函数的组合。其默认行为在C++中被编入程序,但在蓝图图表中进行覆盖后即可对其进行补充或替换。如下所示,对其进行编程时,C++代码固定进入一个命名末尾添加有_Implementation的虚拟函数。这是灵活性最强的选项,因此我们将其用于此教程中。

    要使非编程人员能够调用C++函数并使用 蓝图 对其进行覆盖,须对Countdown.h进行以下修改:

    UFUNCTION(BlueprintNativeEvent)
    void CountdownHasFinished();
    virtual void CountdownHasFinished_Implementation();

    然后我们需要在 Countdown.cpp 中将拥有以下代码的行:

    void ACountdown::CountdownHasFinished()

    改为:

    void ACountdown::CountdownHasFinished_Implementation()

现在我们设置好了非编程人员可访问并调整的变量和函数,同时在C++中提供了默认值和功能。为了解非编程人员能够如何进行使用,我们将设置一个ACountdown类的蓝图延展并自行进行修改。

完成的代码

Countdown.h

// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.

#pragma once

#include "GameFramework/Actor.h"
#include "Countdown.generated.h"

UCLASS()
class HOWTO_VTE_API ACountdown : public AActor
{
    GENERATED_BODY()

public: 
    // 设置该Actor属性的默认值
    ACountdown();

protected:
    // 游戏开始时或生成时调用
    virtual void BeginPlay() override;

public:
    // 每帧调用
    virtual void Tick( float DeltaSeconds ) override;

    // 倒计时运行时长(以秒计)
    UPROPERTY(EditAnywhere)
    int32 CountdownTime;

    UTextRenderComponent* CountdownText;

    void UpdateTimerDisplay();

    void AdvanceTimer();

    UFUNCTION(BlueprintNativeEvent)
    void CountdownHasFinished();
    virtual void CountdownHasFinished_Implementation();

    FTimerHandle CountdownTimerHandle;
};

Countdown.cpp

// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.

#include "HowTo_VTE.h"
#include "Countdown.h"

// 设置默认值
ACountdown::ACountdown()
{
    // 设置此Actor每帧调用Tick()。如果不需要,则可将其关闭来改善性能。
    PrimaryActorTick.bCanEverTick = false;

    CountdownText = CreateDefaultSubobject<UTextRenderComponent>(TEXT("CountdownNumber"));
    CountdownText->SetHorizontalAlignment(EHTA_Center);
    CountdownText->SetWorldSize(150.0f);
    RootComponent = CountdownText;

    CountdownTime = 3;
}

// 游戏开始时或生成时调用
void ACountdown::BeginPlay()
{
    Super::BeginPlay();

    UpdateTimerDisplay();
    GetWorldTimerManager().SetTimer(CountdownTimerHandle, this, &ACountdown::AdvanceTimer, 1.0f, true);
}

// 每帧调用
void ACountdown::Tick( float DeltaTime )
{
    Super::Tick( DeltaTime );

}

void ACountdown::UpdateTimerDisplay()
{
    CountdownText->SetText(FString::FromInt(FMath::Max(CountdownTime, 0)));
}

void ACountdown::AdvanceTimer()
{
    --CountdownTime;
    UpdateTimerDisplay();
    if (CountdownTime < 1)
    {
        // 倒计时结束,停止运行定时器。
        GetWorldTimerManager().ClearTimer(CountdownTimerHandle);
        //在定时器结束时按执行所需的特殊操作。
        CountdownHasFinished();
    }
}

void ACountdown::CountdownHasFinished_Implementation()
{
    // 改为一个特殊的读出
    CountdownText->SetText(TEXT("GO!"));
}
Select Skin
Light
Dark

Welcome to the new Unreal Engine 4 Documentation site!

We're working on lots of new features including a feedback system so you can tell us how we are doing. It's not quite ready for use in the wild yet, so head over to the Documentation Feedback forum to tell us about this page or call out any issues you are encountering in the meantime.

We'll be sure to let you know when the new system is up and running.

Post Feedback