实现灯光闪烁

Programming Language

×C++

Select an option from the dropdown to see content relevant to it. 本文将介绍如何建立能够在接触时变色并随时间闪烁的光源Actor。

我们将用到点光源组件,该组件包含一个作为重叠触发器的盒体组件,以及一个用于操控点光源Actor的时间轴组件。

创建能够熄灭的光源Actor

  1. 使用空白(Blank)模板新建一个C++项目,将项目命名为FadingLights。 点击查看大图。

图:点击查看大图。

  1. 找到内容浏览器,点击C++ Classes文件夹,然后点击添加(+)(Add (+))按钮并选择新建C++类(New C++ Class)。 点击查看大图。

图:点击查看大图。

  1. 选择Actor作为父类。 点击查看大图。

图:点击查看大图。

  1. 将创建的Actor命名为LightActor。 点击查看大图。

图:点击查看大图。

  1. 创建新Actor时,Visual Studio会自动打开LightActor.h和LightActor.cpp文件。 找到LightActor.h文件并声明如下内容:LightActor.h C++ #include "Components/TimelineComponent.h" #include "Components/TimelineComponent.h" Copy full snippet(1 line long)
  2. 接下来,在LightActor的类定义中添加以下代码:LightActor.h C++ public: UPROPERTY(EditAnywhere) UCurveFloat* PointLightFloatCurve; UPROPERTY(EditAnywhere) UCurveLinearColor* PointLightColorCurve; protected: Expand code Copy full snippet(37 lines long)
  3. 找到LightActor.cpp并添加以下类库。LightActor.cpp C++ #include "Components/BoxComponent.h" #include "Components/PointLightComponent.h" #include "Components/BoxComponent.h" #include "Components/PointLightComponent.h" Copy full snippet(2 lines long)
  4. 在ALightActor::ALightActor的构造函数中声明以下内容:LightActor.cpp C++ ALightActor::ALightActor() { // 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; //Create our Default Components PointLightComp = CreateDefaultSubobject(TEXT("PointLightComp")); LightTimelineComp = CreateDefaultSubobject(TEXT("LightTimelineComp")); LightOverlapVolume = CreateDefaultSubobject(TEXT("LightOverlapVolume")); Expand code Copy full snippet(17 lines long)
  5. 接下来,实现点光源组件的UFunction方法:LightActor.cpp C++ void ALightActor::UpdateLightBrightness(float BrightnessOutput) { PointLightComp->SetLightBrightness(BrightnessOutput * 20.0f); } void ALightActor::UpdateLightColor(FLinearColor ColorOutput) { PointLightComp->SetLightColor(ColorOutput); } void ALightActor::UpdateLightBrightness(float BrightnessOutput) { PointLightComp->SetLightBrightness(BrightnessOutput * 20.0f); } void ALightActor::UpdateLightColor(FLinearColor ColorOutput) { PointLightComp->SetLightColor(ColorOutput); } Copy full snippet(9 lines long)
  6. 然后,在BeginPlay方法中添加以下代码:LightActor.cpp C++ void ALightActor::BeginPlay() { Super::BeginPlay(); //Binding our float and color track to their respective functions UpdateBrightnessTrack.BindDynamic(this, &ALightActor::UpdateLightBrightness); UpdateColorTrack.BindDynamic(this, &ALightActor::UpdateLightColor); //If we have a float curve, bind it's graph to our update function if (PointLightFloatCurve) Expand code Copy full snippet(20 lines long)
  7. 编译你的代码。
  8. 在内容浏览器中找到C++Classes文件夹。
  9. 右键点击LightActor,选择 基于LightActor创建蓝图类(Create Blueprint Class based on LightActor),并将蓝图Actor命名为BP_LightActor。 实现灯光闪烁 - 图5

BP_LightActor的类默认值将按照如下方式显示:

点击查看大图。

图:点击查看大图。

阶段性代码

LightActor.h

C++

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

    #pragma once
    #include "Components/TimelineComponent.h"
    #include "CoreMinimal.h"
    #include "GameFramework/Actor.h"
    #include "LightActor.generated.h"

    UCLASS()
    class FADINGLIGHTS_API ALightActor : public AActor

Expand code Copy full snippet(63 lines long)

LightActor.cpp

C++

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

    #include "LightActor.h"
    #include "Components/BoxComponent.h"
    #include "Components/PointLightComponent.h"

    // Sets default values
    ALightActor::ALightActor()
    {
        // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.

Expand code Copy full snippet(63 lines long)

创建并绑定碰撞重叠事件

盒体组件需要拥有在Actor进入其碰撞边界时触发TimelineComponent的能力。

  1. 找到你的LightActor.h文件的类定义,并在BrightnessMultiplier下声明如下内容:LightActor.h C++ protected: UFUNCTION() void OnOverlapBegin(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult); protected: UFUNCTION() void OnOverlapBegin(class UPrimitiveComponent OverlappedComp, class AActor OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult); Copy full snippet(4 lines long)
  2. 然后,找到LightActor.cpp文件并实现OnOverlapBegin函数。LightActor.cpp C++ void ALightActor::OnOverlapBegin(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult) { LightTimelineComp->Play(); } void ALightActor::OnOverlapBegin(class UPrimitiveComponent OverlappedComp, class AActor OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult) { LightTimelineComp->Play(); } Copy full snippet(4 lines long)
  3. 在BeginPlay方法中绑定重叠函数:LightActor.cpp C++ //Binding our Box Component to our Light Actor's Overlap Function LightOverlapVolume->OnComponentBeginOverlap.AddDynamic(this, &ALightActor::OnOverlapBegin); //Binding our Box Component to our Light Actor's Overlap Function LightOverlapVolume->OnComponentBeginOverlap.AddDynamic(this, &ALightActor::OnOverlapBegin); Copy full snippet(2 lines long)
  4. 编译你的代码。

已完成代码

LightActor.h

C++

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

    #pragma once
    #include "Components/TimelineComponent.h"
    #include "CoreMinimal.h"
    #include "GameFramework/Actor.h"
    #include "LightActor.generated.h"

    UCLASS()
    class FADINGLIGHTS_API ALightActor : public AActor

Expand code Copy full snippet(68 lines long)

LightActor.cpp

C++

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

    // Fill out your copyright notice in the Description page of Project Settings.

    #include "LightActor.h"
    #include "Components/BoxComponent.h"
    #include "Components/PointLightComponent.h"

    // Sets default values
    ALightActor::ALightActor()

Expand code Copy full snippet(70 lines long)

设置亮度轨道

当玩家与光源Actor的盒体组件边界重叠时,时间轴组件将需要使用浮点曲线来操控点光源组件的亮度值。

亮度的初始值为5000,并将在5秒钟内下降到0。

  1. 找到内容浏览器,选择添加(+)(Add (+))> 杂项(Miscellaneous)> 曲线(Curve)。 实现灯光闪烁 - 图7

  2. 选择CurveFloat并将资产命名为BrightnessCurveFloat。 实现灯光闪烁 - 图8

  3. 双击BrightnessCurveFloat,打开时间轴编辑器。

  4. 右键点击图表(Graph),然后选择添加关键点(Add Key),为浮点曲线添加两个关键点。 将第一个关键点的时间值调整为(0, 5000)。 将第二个关键点的时间值调整为(5, 0)。 你的BrightnessCurveFloat应如下所示: 点击查看大图。

图:点击查看大图。

  1. 保存BrightnessCurveFloat,然后回到内容浏览器,双击BP_LightActor以打开类默认值(Class Defaults)。
  2. 前往细节(Details)面板,在点光源浮点曲线(Point Light Float Curve)下拉菜单中,选择亮度曲线浮点(Brightness Curve Float)。 实现灯光闪烁 - 图10

  3. 点击编译(Compile)和保存(Save)按钮。 实现灯光闪烁 - 图11

设置颜色轨道

当玩家与光源Actor的盒体组件边界重叠时,PointLight时间轴将需要使用线性颜色曲线轨道来操控点光源组件的颜色属性。

  1. 找到内容浏览器,选择添加(+)(Add (+))> 杂项(Miscellaneous)> 曲线(Curve)。 实现灯光闪烁 - 图12

  2. 选择CurveLinearColor并将资产命名为LinearColorCurve。 实现灯光闪烁 - 图13

  3. 双击LinearColorCurve以打开时间轴编辑器。

  4. 双击第一个颜色关键点并修改,将RGB值修改为:(R:1、G:0.665、B:0.015)。 点击查看大图。

图:点击查看大图。

  1. 双击第二个颜色关键点并修改,将RGB值修改为:(R:0、G:0、B:0)。 点击查看大图。

图:点击查看大图。

  1. 点击选择图表上的第二个点(Point),并将时间设置为5秒。 点击查看大图。

图:点击查看大图。

  1. 你的LinearColorCurve应如下所示: 点击查看大图。

图:点击查看大图。

  1. 保存LinearColorCurve,然后回到内容浏览器,双击BP_LightActor以打开类默认值。
  2. 前往细节(Details)面板,在点光源浮点曲线(Point Light Float Curve)下拉菜单中,选择亮度曲线浮点(Brightness Curve Float)。 实现灯光闪烁 - 图18

  3. 点击编译(Compile)和保存(Save)按钮。 实现灯光闪烁 - 图19

关卡设置

为了充分展示你编写的代码的功能,需要从关卡中删除所有光源Actor。

  1. 在内容浏览器中找到BP_LightActor资产,将其选中并拖入关卡。 点击查看大图。

图:点击查看大图。

  1. 在世界大纲视图中选择BP_LightActor,找到细节(Details)面板并将位置(Location)设置设为(0, 0, 300),将缩放(Scale)设置设为(10, 10, 10)。 实现灯光闪烁 - 图21

  2. 在世界大纲视图中删除定向光源Actor(DirectionalLight Actor)。 实现灯光闪烁 - 图22

  3. 关卡内容应如下所示。 点击查看大图。

图:点击查看大图。

最终结果

现在,光源Actor和关卡已经完成设置,点击运行(PIE)(Play (PIE))即可自动持有旁观者Pawn。

你可以控制旁观者Pawn,可以找到光源Actor的盒体组件边界。

触发时间轴组件的播放功能之后,光源应该开始在5秒的时间跨度内变换颜色和亮度。