C++和蓝图

向初识虚幻引擎的游戏程序员讲解相关信息。

Windows
MacOS
Linux
本页面的内容

利用蓝图可延伸C++,程序员可在代码中设置新的gameplay类,关卡设计师可利用蓝图编译和修改此类代码。有些说明符可修改C++类与蓝图系统的交互方式,其中一部分将在本范例中高亮显示。

类设置

类设置的第一部分:使用C++类向导创建名为LightSwitchBoth的类。

Most of the code setup in the LightSwitchBoth类中设置的多数代码与纯C++ LightSwitch范例中的代码类似。可使用蓝图延展LightSwitchCodeOnly类,而蓝图图表无法访问这个类中的组件、变量和函数。此范例将讲解 UPROPERTY()UFUNCTION() 说明符,这两个说明符可使LightSwitchBoth作为派生自其中的蓝图模板进行运作。

首先参考纯C++ LightSwitch范例会十分有用,可了解设置标头文件和源文件来创建LightSwitchComponent、SphereComponent、DesiredIntensity变量和OnOverlap函数的方法。

此标头文件源自纯C++ LightSwitch范例,以添加以下功能:

  • PointLightComponent和SphereComponent为BlueprintReadOnly,将在 我的蓝图(My Blueprint) 选项卡的 切换组件(Switch Components) 目录中显示。

  • OnOverlapBegin和OnOverlapEnd现为BlueprintNativeEvents,将在 我的蓝图(My Blueprint) 选项卡的 切换函数(Switch Functions) 目录中显示。

  • DesiredIntensity为BlueprintReadWrite,将在 我的蓝图(My Blueprint) 选项卡的 切换变量(Switch Variables) 目录中显示。

  • DesiredIntensity现为EditAnywhere,而非VisibleAnywhere。

UCLASS() 宏含有 Blueprintable 说明符。LightSwitchBoth可设为蓝图且直接继承自Actor,而可设为蓝图说明符已继承,因此其在此情况下并非必需。

有了 UPROPERTY()UFUNCTION() 宏中的附加说明符后,LightSwitchBoth类的标头文件类似于:

LightSwitchBoth.h

    // 版权所有 1998-2018 Epic Games, Inc. 保留所有权利。

    #pragma once

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

    /**
     * 
     */
    UCLASS()
    class [PROJECTNAME]_API ALightSwitchBoth : public AActor
    {
        GENERATED_BODY()
        public:
        /** 点光源组件 */
        UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Switch Components")
        class UPointLightComponent* PointLight1;

        /** 球体组件 */
        UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Switch Components")
        class USphereComponent* Sphere1;

        ALightSwitchBoth();

        /** 物体进入球体组件时调用 */
        UFUNCTION(BlueprintNativeEvent, Category="Switch Functions")
        void OnOverlapBegin(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);

        void OnOverlapBegin_Implementation(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);

        /** 物体离开球体组件时调用 */
        UFUNCTION(BlueprintNativeEvent, Category="Switch Functions")
        void OnOverlapEnd(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);

        void OnOverlapEnd_Implementation(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);

        /** 切换光源组件的可视性*/
        UFUNCTION()
        void ToggleLight();

        /** 光源的理想强度 */
        UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Switch Variables")
        float DesiredIntensity;

    };

在LightSwitchBoth的源文件中,构造函数保持不变。但 OnOverlapBeginOnOverlapEnd 函数需要进行变更。此类函数现为BlueprintNativeEvent。这意味蓝图派生自该类,可放置覆盖 OnOverlapBeginOnOverlapEnd 的事件,正常调用函数时将执行该事件。若此类事件之一不存在,将转而执行函数的C++实现。要使此设置生效,需将C++函数分别重命名为 OnOverlapBegin_ImplementationOnOverlapEnd_Implementation。之后本范例将讲解蓝图设置。 修改 OnOverlapBeginOnOverlapEnd 定义后,LightSwitchBoth的源文件类似于:

LightSwitchBoth.cpp

// 版权所有 1998-2018 Epic Games, Inc. 保留所有权利。

#include "BasicClasses.h"
#include "LightSwitchBoth.h"

ALightSwitchBoth::ALightSwitchBoth()
{

    DesiredIntensity = 3000.0f;

    PointLight1 = CreateDefaultSubobject<UPointLightComponent>(TEXT("PointLight1"));
    PointLight1->Intensity = DesiredIntensity;
    PointLight1->bVisible = true;
    RootComponent = PointLight1;

    Sphere1 = CreateDefaultSubobject<USphereComponent>(this, TEXT("Sphere1"));
    Sphere1->InitSphereRadius(250.0f);
    Sphere1->SetupAttachment(RootComponent);

    Sphere1->OnComponentBeginOverlap.AddDynamic(this, &ALightSwitchBoth::OnOverlapBegin);       // 设置通知,该组件进行覆盖时会弹出通知
    Sphere1->OnComponentEndOverlap.AddDynamic(this, &ALightSwitchBoth::OnOverlapEnd);       // 设置通知,该组件进行覆盖时会弹出通知
}

void ALightSwitchBoth::OnOverlapBegin_Implementation(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
    if (OtherActor && (OtherActor != this) && OtherComp)
    {
        ToggleLight();
    }
}

void ALightSwitchBoth::OnOverlapEnd_Implementation(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
    if (OtherActor && (OtherActor != this) && OtherComp)
    {
        ToggleLight();
    }
}

void ALightSwitchBoth::ToggleLight()
{
    PointLight1->ToggleVisibility();
}

若此为添加至空白项目的首个代码类,需要首先关闭虚幻编辑器,在Visual Studio或Xcode中编译项目,然后打开虚幻编辑器并重新打开项目,以保证正确创建和加载游戏模块。此外,需确保 编译配置(Build Configuration) 与用于开启项目的虚幻引擎可执行文件相匹配,这一点同样重要。浏览编译游戏项目文档,了解编译配置和编译项目的详情。

若将代码添加至现有C++项目,可使用热重载功能在虚幻编辑器中编译新代码。

编译此新类后可新建蓝图类。 在这种情况下,LightSwitchBoth被用作蓝图的父类,将被命名为 LightSwitchBoth_BP

BPBoth_ParentClass.png

C++中添加的PointLightComponent和SphereComponent同样会在 蓝图编辑器(Blueprint Editor) 中的 组件(Components) 选项卡中显示。其图标为深蓝色,表明为继承自父LightSwitchBoth类的原生组件。添加至 LightSwitchBoth_BP 蓝图的新组件将显示为淡蓝色图标。参见组件选项卡文档,了解使用 组件(Components) 添加和整理组件的详情。

Both_ComponentList.png

蓝图编辑器(Components图表(Graph) 面板是蓝图编辑的核心。在 图表(Graph) 面板内,可在我的蓝图选项卡中添加新的变量函数。同时可存取蓝图内的所有图表。图表中的节点互相连线,创建由类变量、gameplay事件,甚至是Actor周围环境驱动的设计时和gameplay功能。

图表(Graph) 面板的 我的蓝图(My Blueprint) 选项卡显示了添加到C++中LightSwitchBoth 类的PointLightComponent和the SphereComponent。这是 BlueprintReadOnly 说明符导致的。在 我的蓝图(My Blueprint) 中点击此类组件的节点并将其拖入图表,即可添加至图表。之后可将这些节点与修改变量可视度或光源颜色的变量相连接。DesiredIntensity 变量同样在 我的蓝图(My Blueprint) 选项卡中显示。其为变量而非组件,因此可使用 BlueprintReadWrite 说明符。这意味可创建节点在蓝图图表中同时获取和赋予 DesiredIntensity 的值。参见我的蓝图文档,了解常规使用信息。

默认不显示父LightSwitchBoth类的组件和变量。勾选 我的蓝图(My Blueprint) 选项卡底部的 显示继承变量(Show inherited variables) 复选框时, 将显示继承自父类的变量。

显示所有变量

仅显示使用者创建的变量

showInhVar2.PNG

showInhVar.PNG

BP_Only_MyBlueprint.png

Both_MyBlueprint.png

有两种图表被用于设置LightSwitchBoth_BP类行为。第一种是构造脚本图表,含有专用的构造脚本事件。若未设置构造脚本,新的LightSwitchBoth_BP Actor将只使用LightSwitchBoth构造函数。但Actor在关卡中移动或修改DesiredIntensity时,构造脚本将执行。使用构造脚本意味着可轻易修改公开到蓝图的Actor变量,还能快速地看到这些变更的效果。

LightSwitchBoth_BP 类中,构造脚本(Construction Script) 事件与 设置强度(Set Intensity) 节点相连,因此将Actor添加至关卡中或在其中移动时,或是DesiredIntensity发生变更时,点光源1(PointLightComponent)的亮度将被设为 DesiredIntensity 的值。

Both_ConstructionScript.png

LightSwitch_BPOnly类中设置的另一个图表是事件图表。EventGraph中的执行将从事件开始。因此,C++功能 OnOverlap 被调用时,OnOverlap事件将执行。在LightSwitchBoth源文件中设置委托,以便Actor进入或离开SphereComponent时OnOverlap进行执行:

    Sphere1->OnComponentBeginOverlap.AddDynamic(this, &ALightSwitchBoth::OnOverlapBegin);       // 设置通知,该组件进行覆盖时会弹出通知
    Sphere1->OnComponentEndOverlap.AddDynamic(this, &ALightSwitchBoth::OnOverlapEnd);       // 设置通知,该组件进行覆盖时会弹出通知

OnOverlap 事件节点与 设置光源颜色(Set Light Color) 节点相连。事件执行时其会导致PointLightComponent的光源颜色被设为随机颜色。 这会覆盖源文件中的 OnOverlap_Implementation 功能,将切换PointLightComponent的可视性。

参见事件(Events)事件图表,和蓝图类UI文档,了解事件和使用图表的详情。

Both_EventGraph_2.png

LightSwitchBoth标头文件中的 DesiredIntensity 变量设为EditAnywhere,因此其在 蓝图编辑器(Blueprint Editor) 的默认项中可见。点击 类默认项(Class Defaults) 按钮在细节面板中显示类默认项后,即可对其进行编辑。这也意味着可依据类的各实例修改变量,以便各Actor可拥有各自的DesiredIntensity。DesiredIntensity同样为在构造脚本中使用的BlueprintReadWrite,因此对其进行更新也会导致构造脚本再次执行。

Both_Defaults.png

使用其他蓝图类可延展蓝图类,其方法为:使用 类查看器(Class Viewer) 中类旁的下拉按钮,或是对蓝图 点击右键 并选择 基于此新建蓝图(Create New Blueprint Based on This),新建蓝图。

蓝图类LightSwitchBoth_BP位于内容浏览器中,可将其从其中拖入关卡。该蓝图类同样位于类查看器中。参见放置Actor文档,了解使用“内容浏览器”或“类查看器”将Actor放入关卡的详情。

Select Skin
Light
Dark

欢迎来到全新虚幻引擎4文档站!

我们正在努力开发新功能,包括反馈系统,以便您能对我们的工作作出评价。但它目前还未正式上线。如果您对此页面有任何意见与在使用中遭遇任何问题,请前往文档反馈论坛告知我们。

新系统上线运行后,我们会及时通知您的。

发表反馈意见