Choose your operating system:
Windows
macOS
Linux
选择实现方法:
Blueprints
C++
本文介绍了如何创建一个能够改变颜色的光源Actor,并且在我们靠近后逐渐熄灭。
我们将用到 点光源组件 ,该组建包含一个作为触发器的盒体组件,以及一个用于操控点光源Actor的时间轴组件。
创建能够熄灭的光源Actor
-
首先,点击 新建(New) > 游戏(Games) > 空白(Blank) > 蓝图(Blueprint) 创建名为 FadingLights 的项目。
-
点击 添加/导入(Add/Import) 按钮,新建一个蓝图 Actor 类,将其命名为 BP_LightActor 。
-
在内容浏览器中双击该BP_LightActor,在蓝图编辑器中打开它,然后打开 类默认值(Class Defaults) 。
-
点击"添加组件(Add Component)",在下拉菜单中选择 盒体碰撞(Box Collision) ,将其重命名为 OverlapCollision 。
-
在组件(Components)选项卡中,选中碰撞体积,将他拖动到DefaultSceneRoot上,使OverlapCollision成为新的根组件。
-
点击添加组件(Add Component),搜索并选择 点光源(Point Light) 。
-
打开 事件图表(Event Graph) ,右关键帧点击图表,然后在 蓝图上下文菜单(Blueprint Context Menu) 中选择 添加时间轴(Add Timeline) 。将时间轴命名为 PointLightTimeline 。
-
导航至 我的蓝图(My Blueprint) 选项卡,然后在 变量(Variables) 类别中点击 +变量(+ Variable) 按钮添加 浮点(float) 类型的新变量。将变量命名为 BrightnessMultiplier ,进行编译并将其 默认值(Default Value) 设置为 20.0 。
-
编译 并 保存 。
设置亮度轨道
当玩家与光源Actor的盒体组件重叠时,时间轴组件将需要使用浮点曲线来操控点光源组件的亮度值。
亮度初始值5000,并将在5秒钟时间内下降到0。
-
双击 PointLightTimeline节点 ,打开时间轴编辑器,添加浮点曲线轨道。
-
将浮点曲线轨道命名为 LightBrightnessFloatTrack ,然后按住 shift 关键帧再点击,将两个关键帧添加到轨道。为一个关键帧分配时间值 (0,5000),为另一个关键帧分配时间值 (5,0)。
-
完成后的LightBrightnessFloat轨道将如下所示。
设置颜色轨道
当玩家与光源Actor的盒体组件边界重叠时,PointLight时间轴将使用线性颜色曲线轨道来操控点光源组件的颜色属性。
-
在 时间轴编辑器(Timeline Editor) 中添加颜色曲线轨道。
-
将新颜色轨道命名为 LightLinearColorTrack 。
-
双击第一个颜色关关键帧帧,将其时间值修改为 0 ,将 RGB 值修改为:( R :1, G: 0.665, B :0.015)。
-
将第二个颜色关键帧的时间值修改为 5 ,将 RGB 值修改为:( R :0, G :0, B :0)。
-
编译 并 保存 蓝图。
-
完成后的颜色轨道将如下所示。
蓝图阶段成果
创建碰撞事件以及更新逻辑
我们需要能在盒体组件遇到Actor时触发TimelineComponent。
此外,PointLightTimeline需要更新逻辑来更改亮度和颜色。
-
在BP_LightActor的蓝图编辑器中,找到组件(Components)选项卡,选择OverlapCollision盒体组件。在细节面板中,向下滚动到"事件"类别,点击 在组件开始重叠时(On Component Begin Overlap) 事件旁的 + 图标。
-
拖动 On Component Begin Overlap(OverlapCollision) 节点的执行引脚,连接到PointTimelineComponent节点的播放引脚。
-
在组件(Components)选项卡中,选择 PointLight 组件并拖入 事件图表(Event Graph) 。
-
拖动 PointLight 的引脚,在操作菜单搜索并选择 设置强度(Set Intensity) 。
-
拖动 PointLightTimeline 节点的 光源亮度浮点轨道(Light Brightness Float Track) 引脚,在操作菜单搜索并选择 float * float 。
-
在 我的蓝图(My Blueprint) 选项卡中,点击 BrightnessMultiplier 浮点变量并拖动到事件图表中,选择 获得亮度乘数(Get Brightness Multiplier) ,然后连接到 float float** 节点。
-
将 更新执行(Update Execution) 引脚连接到 Set Intensity 节点,然后将 float * float 节点的结果连到 新强度(New Intensity) 输入引脚。
-
拖动 PointLight 节点,然后在操作菜单中搜索并选择 设置光源颜色(Set Light Color) 。
-
在 PointLightTimeline 节点中,拖动 光源线性(Light Linear) 颜色轨道(Color Track) 引脚,连接到 Set Light Color 节点的 新光源颜色(New Light Color) 引脚。然后,将 Set Intensity 节点中的 执行引脚(execution pin) 连接到 Set Light Color 节点。
-
编译 并 保存 。
完成后的蓝图
关卡设置
为了充分演示代码的作用,请在关卡中删除所有光源。
-
首先,将你的 BP_LightActor 实例放入关卡。
-
导航至 世界大纲视图(World Outliner) ,然后选择 大气雾(Atmospheric Fog) Actor。从细节面板中导航至 太阳(Sun) 类别,将其 默认亮度(Default Brightness) 值设置为 0 。
-
从世界大纲视图中删除 天空球体(Sky Sphere) Actor。
-
此外,从世界大纲视图中删除 光源Actor(Light Source Actor) 。
-
导航至 工具栏(Toolbar) ,然后选择 构建(Build) ,在关卡中重新构建光照。
-
生成光照后,关卡应该看起来和下面差不多。
最终效果
现在光源Actor和关卡已经设置完成,点击 PIE 并自动获操控旁观者Pawn。
你可以控制旁观者Pawn了,试着走进光源Actor的盒体碰撞体积。
时间轴组件播放功能触发后,光源应该会开始改变颜色和亮度,并在5秒内完成改变。
本文介绍了如何创建一个能够改变颜色的光源Actor,并且在我们靠近后逐渐熄灭。
我们将用到 点光源组件 ,该组建包含一个作为触发器的盒体组件以及一个用于操控点光源Actor的时间轴组件。
创建能够熄灭的光源Actor
-
首先,点击 新建(New) > 游戏(Games) > 空白(Blank) > C++ 创建名为 FadingLights 的项目。
-
在 C++类向导(C++ Class Wizard) 中新建名为 LightActor 的 Actor 类。
-
导航至
LightActor.h
文件,并声明以下内容:#include "Components/TimelineComponent.h"
-
接下来,在
LightActor
类定义中添加以下代码:public: UPROPERTY(EditAnywhere) UCurveFloat* PointLightFloatCurve; UPROPERTY(EditAnywhere) UCurveLinearColor* PointLightColorCurve; protected: //用于控制点光源组件动画效果的TimelineComponent。 UPROPERTY(VisibleAnywhere, BlueprintReadWrite) UTimelineComponent* LightTimelineComp; //用于近似表示光源碰撞体积的盒体组件。 UPROPERTY(EditAnywhere, BlueprintReadWrite) class UBoxComponent* LightOverlapVolume; UPROPERTY(EditAnywhere,BlueprintReadWrite) class UPointLightComponent* PointLightComp; //用于控制点光源亮度的轨道 FOnTimelineFloat UpdateBrightnessTrack; //用于控制点光源颜色的轨道 FOnTimelineLinearColor UpdateColorTrack; //用于更新光源亮度的函数(对应轨道的UpdateBrightnessTrack函数) UFUNCTION() void UpdateLightBrightness(float BrightnessOutput); //用于更新光源颜色的函数(对应轨道的UpdateColorTrack函数) UFUNCTION() void UpdateLightColor(FLinearColor ColorOutput); UPROPERTY(EditDefaultsOnly) float BrightnessMultiplier;
-
导航至
LightActor.cpp
并添加以下头文件。#include "Components/BoxComponent.h" #include "Components/PointLightComponent.h"
-
在 ALightActor::ALightActor 的构造函数中声明以下内容:
//创建我们的默认组件 PointLightComp = CreateDefaultSubobject<UPointLightComponent>(TEXT("PointLightComp")); LightTimelineComp = CreateDefaultSubobject<UTimelineComponent>(TEXT("LightTimelineComp")); LightOverlapVolume = CreateDefaultSubobject<UBoxComponent>(TEXT("LightOverlapVolume")); //设置组件层级关系 RootComponent = LightOverlapVolume; PointLightComp->AttachToComponent(LightOverlapVolume,FAttachmentTransformRules::KeepRelativeTransform); //初始化亮度乘数 BrightnessMultiplier = 20.0f;
-
接下来,实现点光源组件的UFunction:
void ALightActor::UpdateLightBrightness(float BrightnessOutput) { PointLightComp->SetLightBrightness(BrightnessOutput * 20.0f); } void ALightActor::UpdateLightColor(FLinearColor ColorOutput) { PointLightComp->SetLightColor(ColorOutput); }
-
然后,在 BeginPlay 方法中,添加以下代码:
//将浮点和颜色轨道分别与函数绑定 UpdateBrightnessTrack.BindDynamic(this, &ALightActor::UpdateLightBrightness); UpdateColorTrack.BindDynamic(this, &ALightActor::UpdateLightColor); //如果有浮点曲线,将它的图表与我们的更新函数绑定 if (PointLightFloatCurve) { LightTimelineComp->AddInterpFloat(PointLightFloatCurve, UpdateBrightnessTrack); } //如果有线性颜色曲线,将它的图表与我们的更新函数绑定 if (PointLightColorCurve) { LightTimelineComp->AddInterpLinearColor(PointLightColorCurve, UpdateColorTrack); }
-
编译你的代码。
-
在内容浏览器中导航至 C++类文件夹(C++ Classes folder) 。
10.右键点击LightActor类,选择 基于光源Actor创建蓝图类(Create Blueprint Class based on LightActor) ,并将蓝图Actor命名为 BP_LightActor 。
![图像替换文本](image_2.png)(w:549 h:173 convert:false)
BP_LightActor的类默认值将按照如下方式显示:
阶段性代码
LightActor.h
//版权所有 1998-2021 Epic Games, Inc。保留所有权利。
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Components/TimelineComponent.h"
#include "LightActor.generated.h"
UCLASS()
class FADINGLIGHTS_API ALightActor : public AActor
{
GENERATED_BODY()
public:
// 设置Actor属性的默认值
ALightActor();
UPROPERTY(EditAnywhere)
UCurveFloat* PointLightFloatCurve;
UPROPERTY(EditAnywhere)
UCurveLinearColor* PointLightColorCurve;
protected:
// 游戏开始或Actor生成时调用
virtual void BeginPlay() override;
// 用于控制点光源组件动画的TimelineComponent。
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
UTimelineComponent* LightTimelineComp;
// 用于近似表示碰撞体积的盒体组件。
UPROPERTY(EditAnywhere, BlueprintReadWrite)
class UBoxComponent* LightOverlapVolume;
UPROPERTY(EditAnywhere,BlueprintReadWrite)
class UPointLightComponent* PointLightComp;
//用于控制点光源亮度的轨道
FOnTimelineFloat UpdateBrightnessTrack;
//用于控制点光源颜色的轨道
FOnTimelineLinearColor UpdateColorTrack;
//用于更新光源亮度的函数(对应轨道的UpdateBrightnessTrack函数)
UFUNCTION()
void UpdateLightBrightness(float BrightnessOutput);
//用于更新光源颜色的函数(对应轨道的UpdateColorTrack函数)
UFUNCTION()
void UpdateLightColor(FLinearColor ColorOutput);
UPROPERTY(EditDefaultsOnly)
float BrightnessMultiplier;
public:
// 每一帧都被调用
virtual void Tick(float DeltaTime) override;
}
LightActor.cpp
//版权所有 1998-2021 Epic Games, Inc。保留所有权利。
#include "LightActor.h"
#include "Components/PointLightComponent.h"
#include "Components/BoxComponent.h"
// 设置默认值
ALightActor::ALightActor()
{
// 将此Actor设置为每帧更新。如果不需要,可以关闭它以提升执行效率。
PrimaryActorTick.bCanEverTick = true;
//创建默认组件
PointLightComp = CreateDefaultSubobject<UPointLightComponent>(TEXT("PointLightComp"));
LightTimelineComp = CreateDefaultSubobject<UTimelineComponent>(TEXT("LightTimelineComp"));
LightOverlapVolume= CreateDefaultSubobject<UBoxComponent>(TEXT("LightOverlapVolume"));
//绑定组件
RootComponent = LightOverlapVolume;
PointLightComp->AttachToComponent(LightOverlapVolume,FAttachmentTransformRules::KeepRelativeTransform);}
// 当游戏开始或Actor生成时调用
void ALightActor::BeginPlay()
{
//将浮点和颜色轨道绑定到各自的函数。
UpdateBrightnessTrack.BindDynamic(this, &ALightActor::UpdateLightBrightness);
UpdateColorTrack.BindDynamic(this, &ALightActor::UpdateLightColor);
//如果有浮点曲线,将其图表绑定到我们的更新函数
if (PointLightFloatCurve)
{
LightTimelineComp->AddInterpFloat(PointLightFloatCurve, UpdateBrightnessTrack);
}
//如果有线性颜色曲线,将其图表绑定到我们的更新函数
if (PointLightColorCurve)
{
LightTimelineComp->AddInterpLinearColor(PointLightColorCurve, UpdateColorTrack);
}
}
void ALightActor::UpdateLightBrightness(float BrightnessOutput)
{
PointLightComp->SetLightBrightness(BrightnessOutput * 20.0f);
}
void ALightActor::UpdateLightColor(FLinearColor ColorOutput)
{
PointLightComp->SetLightColor(ColorOutput);
}
// 每帧调用
void ALightActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
创建并绑定碰撞事件
我们需要让盒体组件在碰到Actor时触发TimelineComponent。
-
导航至
LightActor.h
文件的类定义部分,并在BrightnessMultiplier
中声明以下内容:UFUNCTION() void OnOverlapBegin(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
-
接下来,导航至
LightActor.cpp
文件并实现OnOverlapBegin
函数。void ALightActor::OnOverlapBegin(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult) { LightTimelineComp->Play(); }
-
在 BeginPlay 方法中绑定碰撞函数:
//将盒体组件绑定给光源Actor的重叠函数 LightProxVolume->OnComponentBeginOverlap.AddDynamic(this, &ALightActor::OnOverlapBegin);
-
编译你的代码。
已完成代码
LightActor.h
//在项目设置(Project Settings)的描述(Description)页面中填写版权声明。
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Components/TimelineComponent.h"
#include "LightActor.generated.h"
UCLASS()
class FADINGLIGHTS_API ALightActor : public AActor
{
GENERATED_BODY()
public:
// 为此Actor的属性设置默认值
ALightActor();
protected:
// 当游戏开始或Actor生成(Spawn)时调用
virtual void BeginPlay() override;
public:
UPROPERTY(EditAnywhere)
UCurveFloat* PointLightFloatCurve;
UPROPERTY(EditAnywhere)
UCurveLinearColor* PointLightColorCurve;
protected:
//用于控制点光源组件动画的TimelineComponent。
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
UTimelineComponent* LightTimelineComp;
//用于近似表示碰撞体积的盒体组件。
UPROPERTY(EditAnywhere, BlueprintReadWrite)
class UBoxComponent* LightOverlapVolume;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
class UPointLightComponent* PointLightComp;
//用于点光源亮度的轨道
FOnTimelineFloat UpdateBrightnessTrack;
//用于点光源颜色的轨道
FOnTimelineLinearColor UpdateColorTrack;
//用于更新光源亮度的函数(对应轨道的UpdateBrightnessTrack函数)
UFUNCTION()
void UpdateLightBrightness(float BrightnessOutput);
//用于更新光源颜色的函数(对应轨道的UpdateColorTrack函数)
UFUNCTION()
void UpdateLightColor(FLinearColor ColorOutput);
UPROPERTY(EditDefaultsOnly)
float BrightnessMultiplier;
UFUNCTION()
void OnOverlapBegin(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
public:
// 每一帧都被调用
virtual void Tick(float DeltaTime) override;
};
LightActor.cpp
//在项目设置(Project Settings)的描述(Description)页面中填写版权声明。
#include "LightActor.h"
#include "Components/BoxComponent.h"
#include "Components/PointLightComponent.h"
//设置默认值
ALightActor::ALightActor()
{
//将此Actor设置为每帧调用更新函数()。如果不需要此特性,可以关闭以提升性能。
PrimaryActorTick.bCanEverTick = true;
//创建我们的默认组件
PointLightComp = CreateDefaultSubobject<UPointLightComponent>(TEXT("PointLightComp"));
LightTimelineComp = CreateDefaultSubobject<UTimelineComponent>(TEXT("LightTimelineComp"));
LightOverlapVolume = CreateDefaultSubobject<UBoxComponent>(TEXT("LightOverlapVolume"));
//绑定组件
RootComponent = LightOverlapVolume;
PointLightComp->AttachToComponent(LightOverlapVolume, FAttachmentTransformRules::KeepRelativeTransform);
//初始化亮度乘数
BrightnessMultiplier = 20.0f;
}
void ALightActor::UpdateLightBrightness(float BrightnessOutput)
{
PointLightComp->SetLightBrightness(BrightnessOutput * 20.0f);
}
void ALightActor::UpdateLightColor(FLinearColor ColorOutput)
{
PointLightComp->SetLightColor(ColorOutput);
}
void ALightActor::OnOverlapBegin(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
LightTimelineComp->Play();
}
// 当游戏开始或Actor生成(Spawn)时调用
void ALightActor::BeginPlay()
{
Super::BeginPlay();
//将我们的浮点和颜色轨道绑定到各自的函数。
UpdateBrightnessTrack.BindDynamic(this, &ALightActor::UpdateLightBrightness);
UpdateColorTrack.BindDynamic(this, &ALightActor::UpdateLightColor);
//如果有浮点曲线,将其图表与我们的更新函数绑定
if (PointLightFloatCurve)
{
LightTimelineComp->AddInterpFloat(PointLightFloatCurve, UpdateBrightnessTrack);
}
//如果有线性颜色曲线,将其图表与我们的更新函数绑定
if (PointLightColorCurve)
{
LightTimelineComp->AddInterpLinearColor(PointLightColorCurve, UpdateColorTrack);
}
//将我们的盒体组件与光源Actor的碰撞函数相绑定
LightOverlapVolume->OnComponentBeginOverlap.AddDynamic(this, &ALightActor::OnOverlapBegin);
}
// 每一帧都被调用
void ALightActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
设置亮度轨道
当玩家与光源Actor的盒体组件碰撞时,时间轴组件将通过浮点曲线来操控点光源组件的亮度值。
亮度的初始值是5000,并将在5秒钟时间内下降到0。
-
从 内容浏览器(Content Browser) 中选择 添加/导入(Add/Import) > 杂项(Miscellaneous) > 曲线(Curve) 。
-
选择 CurveFloat 并将资产命名为 BrightnessCurveFloat
-
双击BrightnessCurveFloat打开 时间轴编辑器(Timeline Editor) 。
-
在浮点曲线中添加两个关键帧,为一个关键帧赋予时间值(0,5000),另一个关键帧赋予时间值(5,0)。
-
保存 BrightnessCurveFloat ,然后回到 内容浏览器(Content Browser) ,双击 BP_LightActor 打开 类默认值(Class Defaults) 。
-
从 点光源浮点曲线(Point Light Float Curve) 下拉菜单中导航至细节面板,然后选择 亮度曲线浮点(Brightness Curve Float) 。
-
编译 并 保存 。
设置颜色轨道
当玩家与光源Actor的盒体组件碰撞时,PointLight时间轴将用线性颜色曲线轨道来控制点光源组件的颜色属性。
-
从 内容浏览器 中选择 添加/导入(Add/Import) > 杂项(Miscellaneous) > 曲线(Curve) 。
-
选择 CurveLinearColor 并将资产命名为 LinearColorCurve
-
双击 LinearColorCurve ,打开 时间轴编辑器(Timeline Editor) 。
-
将第一个颜色关键帧的时间值修改为 0,RGB 值修改为:( R :1, G: 0.665, B :0.015), 将第二个颜色关键帧的时间修改为5,将RGB值修改为:( R :0, G :0, B :0)。
-
保存 LinearColorCurve ,然后导航回内容浏览器,双击 BP_LightActor 打开类默认值。
-
从 点光源浮点曲线(Point Light Float Curve) 下拉菜单中导航至**细节面板,然后选择 亮度曲线浮点(Brightness Curve Float) 。
-
编译 并 保存 。
关卡设置
为了便于演示代码的功能,请在关卡中删除所有光源。
-
首先,将你的 BP_LightActor 实例放入关卡。
-
导航至 世界大纲视图(World Outliner) ,然后选择 大气雾(Atmospheric Fog) Actor。在细节面板中导航至 太阳(Sun) 类别,将其 默认亮度(Default Brightness) 值设置为 0 。
-
在世界大纲视图中删除 天空球体(Sky Sphere) Actor。
-
此外,从世界大纲视图中删除 光源Actor(Light Source Actor) 。
-
导航至 工具栏(Toolbar) ,然后选择 构建(Build) ,在关卡中重新构建光源。
-
完成光源的构建之后,关卡看起来类似于下面的图像。
最终效果
现在,光源Actor和关卡已经完成设置,点击 PIE 后会自动控制旁观者Pawn。
控制旁观者Pawn并走进光源Actor的盒体碰撞体积。
触发时间轴组件的播放功能之后,光源应该会开始改变颜色和亮度并在5秒内完成。