Choose your operating system:
Windows
macOS
Linux
选择实现方法:
Blueprints
C++
概述
直接Actor通信(Direct Actor communication)是关卡中各Actor之间的常用信息共享方法。 这种方法要求你引用目标Actor,以便当前Actor访问它。采用这种通信方法时,工作Actor和目标Actor之间是一对一关系。 在此快速入门指南中,你将学习如何使用直接Actor通信来访问目标Actor中的信息。
1 - 必要设置
-
在菜单的 新项目类别(New Project Categories) 部分中,选择 游戏(Games) ,然后点击 下一步(Next) 。
-
选择 第三人称(Third Person) 模板,然后点击 下一步(Next) 。
-
选择 蓝图(Blueprint) 和 含初学者内容包(With Starter Content) 选项,然后点击 创建项目(Create Project) 。
阶段成果
你已经创建了一个新的第三人称项目,现在可以开始实现直接Actor通信。
2 - 添加直接Actor通信
-
转到 内容浏览器(Content Browser) 中的 初学者内容包(Starter Content) > 蓝图(Blueprints) ,然后 Blueprint_CeilingLight actor拖动到关卡中。
-
在关卡中选择 ThirdPersonCharacter Actor,将其放置在靠近电灯的位置。
-
选择你的 ThirdPersonCharacter Actor之后,转到 世界大纲视图(World Outliner) ,点击 编辑ThirdPersonCharacter(Edit ThirdPersonCharacter) 以打开蓝图编辑器。
-
转到 变量(Variable) 部分,然后点击 添加变量(+ Variable) 按钮以创建新的变量。
-
将变量命名为 LampReference 。
-
转到 细节(Details) 面板,然后点击 变量类型(Variable Type) 下拉菜单。搜索并选择 对象引用(Object Reference) 中的 蓝图天花板光源(Blueprint Ceiling Light) ,如下所示。
-
最后,启用 实例可编辑(Instance Editable) 复选框,并 编译(Compile) 和 保存(Save) 蓝图。
-
在 事件图表(Event Graph) 中,右键点击并搜索和选择 F 键,以创建输入节点。
-
从 F Key 节点的 已按下(Pressed) 引脚拖出一根引线,然后搜索并选择 Flip Flop 。
-
将 电灯引用(Lamp Reference) 变量拖动到 事件图表(Event Graph) 中,然后选择 获取LampReference(Get LampReference) 。从引脚拖出一根引线,然后搜索并选择 Get Point Light 1 。
-
从 Point Light 1 引脚拖出一根引线,然后搜索并选择 Set Visibility 。将 A引脚(A pin) 从 Flip Flop 节点连接到 Set Visibility 节点,如下所示。
-
复制 Lamp Reference 、 Point Lamp 1 和 Set Visibility 节点,将它们连接到 Flip Flop 节点的 B 引脚。启用 New Visibility(新可视性) 复选框,如下所示。
-
编译(Compile) 并 保存(Save) 蓝图。
阶段成果
在此小节中,你修改了 ThirdPersonCharacter 蓝图Actor以使用对电灯Actor的引用,并通过按F键打开和关闭电灯。
3 - 与电灯Actor交互
1.在你的关卡中选择 ThirdPersonCharacter Actor,然后在 细节(Details) 面板中点击 电灯引用(Lamp Reference) 下拉菜单。搜索并选择 Blueprint_CeilingLight 蓝图。
![图像替换文本](image_14.png)(convert:false)
-
按运行(Play)进入播放模式,然后按 F键(F Key) 打开和关闭电灯。
阶段成果
在本小节中,你在 ThirdPersonCharacter 蓝图Actor中添加了天花板电灯的引用,并且通过按F键打开和关闭了光源。
后续步骤
现在,你现在你已了解如何使用直接Actor通信,接下来可以查看 Actor通信 文档页面中引用的其他通信类型。
概述
直接蓝图通信(Direct Blueprint communication)是在关卡中的Actor之间共享信息时的常用方法。 这种方法要求你引用目标Actor蓝图,以便当前Actor的蓝图能够访问它。采用这种通信类型时,当前Actor和目标Actor之间是一对一关系。 在此快速入门指南中,你将学习如何使用直接蓝图通信来访问目标Actor蓝图中的信息。
1 - 准备工作
-
在菜单的 新项目类别(New Project Categories) 部分中,选择 游戏(Games) ,然后点击 下一步(Next) 。
-
选择 第三人称(Third Person) 模板,然后点击 下一步(Next) 。
-
选择 C++ 和 含初学者内容包(With Starter Content) 选项,然后点击 创建项目(Create Project) 。
阶段成果
你已经创建了一个新的第三人称项目,现在可以开始实现直接蓝图通信了。
2 - 创建天花板光源Actor
-
在 [C++类向导]([C++ Class Wizard])(ProductionPipelines/DevelopmentSetup/ManagingGameCode/CppClassWizard) 中新建名为 CeilingLight 的Actor类。
-
在类中, CeilingLight.h 的类默认值中,实现以下代码。
protected: UPROPERTY(EditInstanceOnly, BlueprintReadWrite) USceneComponent* SceneComp; UPROPERTY(EditInstanceOnly, BlueprintReadWrite) class UPointLightComponent* PointLightComp; UPROPERTY(EditInstanceOnly, BlueprintReadWrite) UStaticMeshComponent* StaticMeshComp; UPROPERTY(EditInstanceOnly, BlueprintReadWrite) float Brightness; UPROPERTY(EditInstanceOnly, BlueprintReadWrite) float SourceRadius; UPROPERTY(EditInstanceOnly, BlueprintReadWrite) FLinearColor Color; UPROPERTY(EditInstanceOnly, BlueprintReadWrite) bool IsLightOn;
-
然后导航至 CeilingLight.Cpp 并声明以下Include库。
#include "Components/PointLightComponent.h"
-
在构造函数 ACeilingLight::CeilingLight 中声明以下代码。
ACeilingLight::ACeilingLight() { // 将此Actor设置为每帧调用Tick()函数。如果你不需要此特性,你可以关闭它以提升性能。 PrimaryActorTick.bCanEverTick = true; SceneComp = CreateDefaultSubobject<USceneComponent>(TEXT("SceneComp")); PointLightComp = CreateDefaultSubobject<UPointLightComponent>(TEXT("PointLightComp")); StaticMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMeshComp")); SceneComp = RootComponent; PointLightComp->AttachToComponent(SceneComp,FAttachmentTransformRules::KeepRelativeTransform); StaticMeshComp->AttachToComponent(SceneComp, FAttachmentTransformRules::KeepRelativeTransform); PointLightComp->SetWorldLocation(FVector(0, 0, -130)); Brightness = 1700.f; Color = FLinearColor(1.f, 0.77f, 0.46f); SourceRadius = 3.5f; PointLightComp->SetIntensity(Brightness); PointLightComp->SetLightColor(Color); PointLightComp->SetSourceRadius(SourceRadius); }
-
编译你的代码。
最终代码
CeilingLight.h
//在项目设置(Project Settings)的描述(Description)页面中填写版权声明。
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "CeilingLight.generated.h"
UCLASS()
class BPCOMMUNICATION_API ACeilingLight : public AActor
{
GENERATED_BODY()
public:
// 为此Actor的属性设置默认值
ACeilingLight();
protected:
// 当游戏开始或重生(Spawn)时被调用
virtual void BeginPlay() override;
UPROPERTY(EditInstanceOnly, BlueprintReadWrite)
USceneComponent* SceneComp;
UPROPERTY(EditInstanceOnly, BlueprintReadWrite)
class UPointLightComponent* PointLightComp;
UPROPERTY(EditInstanceOnly, BlueprintReadWrite)
UStaticMeshComponent* StaticMeshComp;
UPROPERTY(EditInstanceOnly, BlueprintReadWrite)
float Brightness;
UPROPERTY(EditInstanceOnly, BlueprintReadWrite)
float SourceRadius;
UPROPERTY(EditInstanceOnly, BlueprintReadWrite)
FLinearColor Color;
UPROPERTY(EditInstanceOnly, BlueprintReadWrite)
bool IsLightOn;
public:
// 每一帧都调用
virtual void Tick(float DeltaTime) override;
UFUNCTION()
void TurnOffLight();
};
CeilingLight.cpp
//版权所有Epic Games, Inc。保留所有权利。
#include "CeilingLight.h"
#include "Components/PointLightComponent.h"
// 设置默认值
ACeilingLight::ACeilingLight()
{
// 将此Actor设置为每帧调用Tick()。 如果你不需要此特性,你可以关闭它以提升性能。
PrimaryActorTick.bCanEverTick = true;
SceneComp = CreateDefaultSubobject<USceneComponent>(TEXT("SceneComp"));
PointLightComp = CreateDefaultSubobject<UPointLightComponent>(TEXT("PointLightComp"));
StaticMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMeshComp"));
SceneComp = RootComponent;
PointLightComp->AttachToComponent(SceneComp,FAttachmentTransformRules::KeepRelativeTransform);
StaticMeshComp->AttachToComponent(SceneComp, FAttachmentTransformRules::KeepRelativeTransform);
PointLightComp->SetWorldLocation(FVector(0, 0, -130));
Brightness = 1700.f;
Color = FLinearColor(1.f, 0.77f, 0.46f);
SourceRadius = 3.5f;
PointLightComp->SetIntensity(Brightness);
PointLightComp->SetLightColor(Color);
PointLightComp->SetSourceRadius(SourceRadius);
}
// 当游戏开始或重生(Spawn)时被调用
void ACeilingLight::BeginPlay()
{
Super::BeginPlay();
}
void ACeilingLight::TurnOffLight()
{
if (IsLightOn)
{
PointLightComp->SetVisibility(false);
IsLightOn = false;
}
else
{
PointLightComp->SetVisibility(true);
IsLightOn = true;
}
}
// 每一帧都调用
void ACeilingLight::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
6.在 C++类文件夹(C++ Classes folder) 中,右键点击 CeilingLight Actor,然后在 C++类操作(C++ Class Actions) 下拉菜单中,选择 基于CeilingLight创建蓝图类(Create Blueprint class based on CeilingLight) 。将蓝图命名为 BP_CeilingLight 。
![图像替换文本](image_4.png)(convert:false)
7.在 BP_CeilingLight 类默认值中,导航至 组件(Components) 面板,然后选择 StaticMeshComp 。
![图像替换文本](image_5.png)(convert:false)
8.在 细节(Details) 面板中,导航至 静态网格体类别(Static Mesh category) ,选择 静态网格体(Static Mesh) 变量旁边的下拉箭头,然后搜索并选择 SM_Lamp_Ceiling 。
![图像替换文本](image_6.png)(convert:false)
-
编译并保存蓝图
-
从 内容浏览器(Content Browser) 中,将 BP_CeilingLight Actor 的实例拖动到关卡中。
修改ThirdPersonCharacter类
-
导航至C++类文件夹,然后双击 BPCommunicationCharacter 类以打开其 BPCommunicationCharacter.h ,然后在类默认值中声明以下代码。
protected: UPROPERTY(EditInstanceOnly, BlueprintReadWrite) class ACeilingLight* CeilingLightToToggle; void ToggleCeilingLight();
-
导航至你的 BPCommunicationCharacter.cpp ,并声明以下include代码:
#include "CeilingLight.h"
-
实现你的 ABPCommunicationCharacter::ToggleCeilingLight 方法。
void ABPCommunicationCharacter::ToggleCeilingLight() { if (CeilingLightToToggle) { CeilingLightToToggle->TurnOffLight(); } }
-
导航至 ABPCommunicationCharacter::SetupPlayerInputComponent 方法,并声明以下代码。
PlayerInputComponent->BindAction("Use", IE_Pressed, this, &ABPCommunicationCharacter::ToggleCeilingLight);
-
在 编辑器(Editor) 中,导航至 编辑(Edit) > 项目设置(Project Settings) > 输入(Input) 。 在 绑定(Bindings) 类别中,导航至 操作映射(Action Mappings) ,然后点击 + 按钮以创建名为 Use 的新 操作映射(Action mapping) ,然后为 键值(key value) 选择 E 键。
-
编译你的代码。
最终代码
BPCommunicationCharacter.h
//版权所有Epic Games, Inc。保留所有权利。
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "BPCommunicationCharacter.generated.h"
UCLASS(config=Game)
class ABPCommunicationCharacter : public ACharacter
{
GENERATED_BODY()
/** 用于将摄像机放置在角色后面的摄像机升降臂 */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
class USpringArmComponent* CameraBoom;
/** 跟随摄像机 */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
class UCameraComponent* FollowCamera;
public:
ABPCommunicationCharacter();
/** 基本旋转速度,以"度/秒"为单位。其他计量方式可能会影响最终旋转速度。*/
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
float BaseTurnRate;
/** 基本仰视/俯视速度,以"度/秒"为单位。其他计量方式可能会影响最终速度。*/
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
float BaseLookUpRate;
protected:
UPROPERTY(EditInstanceOnly, BlueprintReadWrite)
class ACeilingLight* CeilingLightToToggle;
void ToggleCeilingLight();
/** 重置VR中的HMD方向。*/
void OnResetVR();
/** 出现向前/向后输入时调用 */
void MoveForward(float Value);
/** 出现侧边到侧边输入时调用 */
void MoveRight(float Value);
/**
* 通过输入进行调用,以给定的速度旋转。
* @param速度 这是标准化速度,即1.0表示100%的所需旋转速度
*/
void TurnAtRate(float Rate);
/**
* 通过输入进行调用,以给定的速度仰视/俯视旋转。
* @param速度 这是标准化速度,即1.0表示100%的所需旋转速度
*/
void LookUpAtRate(float Rate);
/** 当触摸输入开始时的处理程序。*/
void TouchStarted(ETouchIndex::Type FingerIndex, FVector Location);
/** 当触摸输入停止时的处理程序。*/
void TouchStopped(ETouchIndex::Type FingerIndex, FVector Location);
protected:
// APawn接口
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
// APawn接口结束
public:
/** 返回CameraBoom子对象 **/
FORCEINLINE class USpringArmComponent* GetCameraBoom() const { return CameraBoom; }
/** 返回FollowCamera子对象 **/
FORCEINLINE class UCameraComponent* GetFollowCamera() const { return FollowCamera; }
};
BPCommunicationCharacter.cpp
//版权所有Epic Games, Inc。保留所有权利。
#include "BPCommunicationCharacter.h"
#include "HeadMountedDisplayFunctionLibrary.h"
#include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h"
#include "Components/InputComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "GameFramework/Controller.h"
#include "GameFramework/SpringArmComponent.h"
#include "CeilingLight.h"
ABPCommunicationCharacter::ABPCommunicationCharacter()
{
// 设置碰撞胶囊体的大小
GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f);
// 设置我们的输入旋转速度
BaseTurnRate = 45.f;
BaseLookUpRate = 45.f;
// 不在控制器旋转时旋转。使其仅影响摄像机。
bUseControllerRotationPitch = false;
bUseControllerRotationYaw = false;
bUseControllerRotationRoll = false;
// 配置角色移动
GetCharacterMovement()->bOrientRotationToMovement = true; // 角色沿输入方向移动...
GetCharacterMovement()->RotationRate = FRotator(0.0f, 540.0f, 0.0f); // ...以此旋转速度
GetCharacterMovement()->JumpZVelocity = 600.f;
GetCharacterMovement()->AirControl = 0.2f;
// 创建摄像机升降臂(如果发生碰撞,朝着玩家推进)
CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
CameraBoom->SetupAttachment(RootComponent);
CameraBoom->TargetArmLength = 300.0f; // 摄像机在角色后面的这个距离上跟随
CameraBoom->bUsePawnControlRotation = true; // 基于控制器旋转升降臂
// 创建跟随摄像机
FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName); // 将摄像机附于升降臂末端,调整升降臂,使其与控制器方向一致
FollowCamera->bUsePawnControlRotation = false; // 摄像机不相对于升降臂旋转
// 注意:网格体组件上的骨骼网格体和动画蓝图引用(从角色继承)
// 是在名为MyCharacter的派生蓝图资产中设置的(以避免C++中的直接内容引用)
}
void ABPCommunicationCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
// 设置游戏的按键绑定
check(PlayerInputComponent);
PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);
PlayerInputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping);
PlayerInputComponent->BindAction("Use", IE_Pressed, this, &ABPCommunicationCharacter::ToggleCeilingLight);
PlayerInputComponent->BindAxis("MoveForward", this, &ABPCommunicationCharacter::MoveForward);
PlayerInputComponent->BindAxis("MoveRight", this, &ABPCommunicationCharacter::MoveRight);
// 我们提供了两个版本的旋转绑定来分别处理不同类型的设备
// "turn"处理提供绝对增量的设备,例如鼠标。
// "turn rate"适用于我们选择以变化速度方式进行处理的设备,例如模拟摇杆
PlayerInputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput);
PlayerInputComponent->BindAxis("TurnRate", this, &ABPCommunicationCharacter::TurnAtRate);
PlayerInputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput);
PlayerInputComponent->BindAxis("LookUpRate", this, &ABPCommunicationCharacter::LookUpAtRate);
// 处理触摸设备
PlayerInputComponent->BindTouch(IE_Pressed, this, &ABPCommunicationCharacter::TouchStarted);
PlayerInputComponent->BindTouch(IE_Released, this, &ABPCommunicationCharacter::TouchStopped);
// VR头戴设备功能
PlayerInputComponent->BindAction("ResetVR", IE_Pressed, this, &ABPCommunicationCharacter::OnResetVR);
}
void ABPCommunicationCharacter::ToggleCeilingLight()
{
if (CeilingLightToToggle)
{
CeilingLightToToggle->TurnOffLight();
}
}
void ABPCommunicationCharacter::OnResetVR()
{
// 如果在虚幻编辑器中通过"添加功能(Add Feature)"将BPCommunication添加到项目,则BPCommunication.Build.cs中HeadMountedDisplay上的依赖关系不会自动传播,
// 并将产生连接器错误。
// 你需要:
// 将"HeadMountedDisplay"添加到[YourProject].Build.cs PublicDependencyModuleNames,以便成功构建(如果支持VR则适用)。
// 或者:
// 注释掉或删除下面对ResetOrientationAndPosition的调用(如果不支持VR则适用)
UHeadMountedDisplayFunctionLibrary::ResetOrientationAndPosition();
}
void ABPCommunicationCharacter::TouchStarted(ETouchIndex::Type FingerIndex, FVector Location)
{
Jump();
}
void ABPCommunicationCharacter::TouchStopped(ETouchIndex::Type FingerIndex, FVector Location)
{
StopJumping();
}
void ABPCommunicationCharacter::TurnAtRate(float Rate)
{
// 根据速度信息计算此帧的增量
AddControllerYawInput(Rate * BaseTurnRate * GetWorld()->GetDeltaSeconds());
}
void ABPCommunicationCharacter::LookUpAtRate(float Rate)
{
// 根据速度信息计算此帧的增量
AddControllerPitchInput(Rate * BaseLookUpRate * GetWorld()->GetDeltaSeconds());
}
void ABPCommunicationCharacter::MoveForward(float Value)
{
if ((Controller != nullptr) && (Value != 0.0f))
{
// 找出向前方向
const FRotator Rotation = Controller->GetControlRotation();
const FRotator YawRotation(0, Rotation.Yaw, 0);
// 获取向前向量
const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
AddMovementInput(Direction, Value);
}
}
void ABPCommunicationCharacter::MoveRight(float Value)
{
if ( (Controller != nullptr) && (Value != 0.0f) )
{
// 找出向右方向
const FRotator Rotation = Controller->GetControlRotation();
const FRotator YawRotation(0, Rotation.Yaw, 0);
// 获取向右向量
const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
// 在该方向上添加位移
AddMovementInput(Direction, Value);
}
}
3 - 与电灯蓝图交互
-
在关卡中选择 ThirdPersonCharacter 蓝图,将其放置在靠近电灯的位置。
-
在选择 ThirdPersonCharacter 之后,导航至 细节(Details) 面板,然后从BPCommunication角色类别中,找到 要切换的天花板光源(Ceiling Light To Toggle) 变量,然后选择它旁边的箭头。在下拉菜单中,搜索并选择 BP_CeilingLight Actor。
1.按 运行(Play) 进入 PlE (在编辑器中运行)模式,然后按 E键(E Key) 打开和关闭电灯。
![图像替换文本](image_11.gif)(convert:false)
阶段成果
在此部分中,你添加了天花板光源Actor对 ThirdPersonCharacter 蓝图的引用,并且通过按E键打开和关闭了光源。
后续步骤
现在你已了解如何使用直接蓝图通信类型,接下来可以查看 Actor通信 文档页面中引用的其他通信类型。