查找Actor

介绍如何通过蓝图或C++代码,查找场景中的Actor。

Choose your operating system:

Windows

macOS

Linux

每当项目变复杂后,你会发现在场景中查找 Actor 会变得愈发困难。场景中往往可以有数以百计的Actor,包括关卡模型和几何体、NPC、敌人、可交互对象、可拾取对象等。 在虚幻编辑器中工作时,你可以使用 世界大纲 视图来定位某个Actor。

image alt text

在上图中,世界大纲视图(右)展示了所有放置在关卡中的Actor。点击世界大纲视图中的一个Actor后,该Actor会在关卡视图中高亮显示。你可以点击 Actor类型(Type),将Actor按照名称或类型进行排序(你可以点击类型框中的向下箭头,将二级类别从类型改为其他过滤条件)。

在世界大纲视图中选中某个Actor,然后点击关卡视图,双击该Actor或直接按下 F,可直接将窗口 对准 该Actor。

请参阅世界大纲视图了解在场景中定位Actor的方法。

选择实现方法:

Blueprints

C++

项目设置

在本教程中,你将使用 Get All Actors of Class 节点在关卡中找到Actor。此节点受到调用时,它将检索关卡指定类(Class)中的所有Actor,并将它们放置在 数组(Array) 中。然后,你可以根据筛选条件从该数组中检索Actor。然后,你可以访问Actor的属性,或者根据你要实现的功能以某种方式修改它们。

  1. 首先,点击 新建(New) > 游戏(Games)> 第三人称(ThirdPerson) > 蓝图项目带初学者内容包(Blueprint Project With Starter Content),创建名为 FindingActors 的项目。

    image alt text

  2. 找到 编辑(Edit) > 项目设置(Project Settings) >引擎(Engine) > 输入(Input) >绑定(Bindings) > 操作映射(Action Mappings) ,然后点击 添加(Add)+),创建名为 FindActorPressed 的新操作映射,然后将 关键值 设置为 1

    image alt text

在本教程中,你将使用 Gameplay静态类库(Gameplay Statics Class Library)Get All Actors of Class 节点)在关卡中找到 Actor 。此函数(节点)受到调用时,它将检索关卡指定 类(Class) 中的所有Actor,并将它们放置在 数组(Array) 中。然后,你可以根据筛选条件从该数组中检索全部Actor或一个Actor。然后,你可以访问Actor的属性,或者根据你要实现的功能以某种方式修改它们。

  1. 首先,点击 新建(New) > 游戏(Games) > 第三人称(ThirdPerson) > C++ 项目 初学者内容包C++ Project With Starter Content ),创建名为 FindingActors 的项目。

image alt text

  1. 找到 编辑(Edit) > 项目设置(Project Settings) >引擎(Engine) > 输入(Input) >绑定(Bindings) > 操作映射(Action Mappings) ,然后点击 添加(Add)+),创建名为 FindActorPressed 的新操作映射,然后将 关键值 设置为 1

image alt text

创建火焰Actor

初学者内容包(Starter Content) 文件夹提供了完整的FireEffect Actor,其中包括表示火焰效果的 粒子组件(Particle Component) 和用于声音效果的 音频组件(Audio Component) 。此Actor将用作从Get All Actors of Class节点查找的Actor基类。

  1. 找到 内容(Content) > StarterContent > 蓝图(Blueprints) ,然后将 Blueprint_Effect_Fire 实例拖到世界中。

    image alt text

  1. 点击 添加/导入(Add/Import) 按钮可以创建 新C++类(New C++ Class) ,然后从 选择父类(Choose a Parent Class) 菜单中,选择 Actor ,创建名为 FireEffect 的新Actor类。

image alt text

  1. 在FireEffect.h中,声明以下内容:

    public:
    
    //获取火焰音效音频组件。
    UAudioComponent* GetFireAudioComponent() const { return FireAudioComponent; }
    
    //获取火焰效果粒子系统组件。
    UParticleSystemComponent* GetParticleFireComponent() const { return ParticleFireComponent; }
    
    protected:
    
    UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
    UParticleSystemComponent* ParticleFire;
    
    UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
    UAudioComponent* FireAudio;
  2. 找到 FireEffect.cpp 文件并添加以下类库:

    #include "Particles/ParticleSystemComponent.h"
    #include "Components/AudioComponent.h"
  3. 在FireEffect构造函数中,实现以下代码:

    AFireEffect::AFireEffect()
    
    {
    
        // 将此Actor设置为每帧调用更新函数()。  如果不需要此特性,可以关闭以提升性能。
    
        PrimaryActorTick.bCanEverTick = true;
    
        ParticleFire = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("P_Fire"));
    
        FireAudio = CreateDefaultSubobject<UAudioComponent>(TEXT("Fire Audio"));
    
        ParticleFire->SetupAttachment(RootComponent);
    
        FireAudio->AttachToComponent(ParticleFire,FAttachmentTransformRules::KeepRelativeTransform);
    
    }
  4. 编译 你的代码。

  5. 找到 内容浏览器(Content Browser) > C++类(C++ Classes) > FindingActors,右键点击 FireEffect Actor,创建 名为 BP_FireEffect 的基于FireEffect的蓝图类。

image alt text

  1. BP_FireEffect类默认值(Class Defaults) 中,点击 组件(Components) 面板中的 粒子火焰(Particle Fire) ,然后找到 细节(Details) 面板,在 粒子(Particles) 类别下,打开 模板(Template) 下拉菜单并选择 P_Fire

image alt text

  1. 点击 组件(Components) 面板中的 火焰音频(Fire Audio) ,然后找到 细节(Details) 面板。从 音效(Sound) 类别打开 音效(Sound) 变量下拉菜单,然后选择 Fire01_Cue

image alt text

  1. 点击 编译(Compile)保存(Save)

image alt text

已完成代码

    FireEffectActor.h

    #pragma once

    #include "CoreMinimal.h"
    #include "GameFramework/Actor.h"
    #include "FireEffect.generated.h"

    UCLASS()

    class FINDINGACTORS_API AFireEffect : public AActor

    {

        GENERATED_BODY()
    public: 

        // 为此Actor的属性设置默认值

        AFireEffect();

        UAudioComponent* GetFireAudioComponent() const { return FireAudioComponent; }

        UParticleSystemComponent* GetParticleFireComponent() const { return ParticleFireComponent; }

    protected:

        // 当游戏开始或生成时调用

        virtual void BeginPlay() override;

        UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)

        UParticleSystemComponent* ParticleFireComponent;

        UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)

        UAudioComponent* FireAudioComponent;

    public: 

        // 每一帧都调用

        virtual void Tick(float DeltaTime) override;

    };

FireEffectActor.cpp

    #include "FireEffect.h"

    #include "Particles/ParticleSystemComponent.h"

    #include "Components/AudioComponent.h"

    // 设置默认值

    AFireEffect::AFireEffect()

    {

        // 将此Actor设置为每帧调用更新函数()。  如果不需要此特性,可以关闭以提升性能。

        PrimaryActorTick.bCanEverTick = true;

        ParticleFireComponent = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("P_Fire"));

        FireAudioComponent = CreateDefaultSubobject<UAudioComponent>(TEXT("Fire Audio"));

        ParticleFireComponent->SetupAttachment(RootComponent);

        FireAudioComponent->AttachToComponent(ParticleFireComponent,FAttachmentTransformRules::KeepRelativeTransform);

    }

    // 当游戏开始或生成时调用

    void AFireEffect::BeginPlay()

    {

        Super::BeginPlay();

    }

    // 每一帧都调用

    void AFireEffect::Tick(float DeltaTime)

    {

        Super::Tick(DeltaTime);

    }

第三人称角色:设置FindingActor Pressed Event

  1. 找到 内容(Content) > ThirdPersonBp > 蓝图(Blueprints) 文件夹,并双击 ThirdPersonCharacter 打开其 类默认值(Class Defaults)

    image alt text

  2. 右键点击 事件图表(Event Graph),然后在 操作(Actions) 菜单中搜索 FindActorPressed 操作键事件。

    image alt text

  3. FindActorPressed 节点键事件,从 Pressed 引脚拖出,然后从 操作(Actions)菜单 搜索 Get All Actors Of Class 节点。

    image alt text

  4. Get All Actors of Class 节点内,点击 Actor类(Actor Class),然后在下拉列表中选择 Blueprint_Effect_Fire 类。

    image alt text

  5. Out Actors 引脚拖出,然后在 操作(Actions) 菜单中搜索 ForEachLoop

    image alt text

  6. Get All Actors Of Class 节点的 执行(Execution) 引脚拖出,并将其插入 For Each Loop 节点的 执行(Exec) 引脚。

    image alt text

  7. ForEachLoop 节点拖出 数组元素(Array Element) 引脚,然后在 操作(Actions) 菜单中搜索 Get P_Fire

    image alt text

  8. 数组元素(Array Element) 引脚拖出,并在 操作(Actions) 菜单中搜索 Get Fire Audio

    image alt text

  9. P Fire 引脚拖出,然后在 操作(Actions) 菜单中搜索 Deactivate 节点。

    image alt text

  10. 火焰音频(Fire Audio) 引脚拖出,并将其连接到 Deactivate 节点的 目标(Target) 引脚。

    image alt text

  11. 点击 编译(Compile)保存(Save)

    image alt text

  1. 内容浏览器(Content Browser) 中,找到 C++类(C++ Classes) > FindingActors ,双击 FindingActorsCharacter 打开 FindingActorsCharacter.h 文件。

    image alt text

  2. FindingActorsCharacter 类默认值中,声明以下内容:

    protected:
    void OnFindActorPressed();
  3. 找到 FindingActorsCharacter.cpp,并添加以下类库:

    #include "Kismet/GameplayStatics.h"
    #include "FireEffect.h"
    #include "Particles/ParticleSystemComponent.h"
    #include "Components/AudioComponent.h"

    注意:虚幻引擎将使用Include-What-You-Use(IWYU)依赖性模型。这意味着引擎的源代码只包含它需要编译的依赖性。有关更多文档,请参阅IWYU

  4. 通过声明以下代码来实现 OnFindActorPressed 的逻辑:

    void AFindingActorsCharacter::OnFindActorPressed()
    {
        TArray<AActor*> ActorsToFind;
        if(UWorld* World = GetWorld())
    {
        UGameplayStatics::GetAllActorsOfClass(GetWorld(), AFireEffect::StaticClass(), ActorsToFind);
    }
        for (AActor* FireEffectActor: ActorsToFind)
    
        {
    
            //这是否是类型FireEffect类的Actor?
            AFireEffect* FireEffectCast = Cast<AFireEffect>(FireEffectActor);
            if (FireEffectCast)
            {
                //获取粒子火焰组件并停用它。         
                FireEffectCast->GetParticleFireComponent()->Deactivate();
    
                //获取火焰音频组件并停用它。         
                FireEffectCast->GetFireAudioComponent()->Deactivate();
            }   
        }
    }
  5. 找到 SetupPlayerInputComponent 方法,并声明以下代码:

    void AFindingActorsCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
    
    {
    
        PlayerInputComponent->BindAction("FindActorPressed", IE_Pressed, this, &AFindingActorsCharacter::OnFindActorPressed);
    
    }
  6. 编译你的代码。

完成的蓝图

image alt text

已完成代码

FindingCharacters.h

    #pragma once

    #include "CoreMinimal.h"
    #include "GameFramework/Character.h"
    #include "FindingActorsCharacter.generated.h"

    UCLASS(config=Game)

    class AFindingActorsCharacter : 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:

        AFindingActorsCharacter();

        /** 基础旋转速度,以度/秒为单位。其他单位可能会影响最终旋转速度。*/

        UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)

        float BaseTurnRate;

        /** 基础向上看/向下看速度,以度/秒为单位。其他单位可能会影响最终速度。*/

        UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)

        float BaseLookUpRate;

    protected:

        /** 重置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);

        /** 当从玩家(Player)输入组件中按下输入(Input)键时调用 */

        void OnFindActorPressed();

    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; }

    };

最终效果

  1. 找到 工具栏(Toolbar) ,并点击 运行(Play)PIE)。

    image alt text

当按下数字1键时,你应该注意到,火焰效果粒子将熄灭,并且不再听到从音频组件发出的音效。

image alt text

  1. 找到 内容浏览器(Content Browser) ,将 BP_FireEffect 的一些实例拖入关卡。

image alt text

  1. 找到 工具栏(Toolbar),并点击 运行(Play)PIE)。

image alt text

  1. 当按下数字1键时,你应该注意到,火焰效果粒子将熄灭,并且不再听到从音频组件发出的音效。

image alt text

通过标签获取特定Actor

你使用了Get All Actors of Class节点来获取指定类的Actor数组。但是,你也可以在Actor上使用 标签(Tags) ,根据不同的条件筛选数组结果,以便从数组中获取特定的Actor或单个Actor。示例,

  1. 找到 内容(Content)> StarterContent > 蓝图(Blueprints) ,并选择 Blueprint_Effect_Fire

    image alt text

  2. 细节(Details) 面板中,找到 标签(Tags) 分段,然后点击 添加(Add)+)将标签添加到Actor。

    image alt text

  3. 0 元素字段中,在文本字符串中输入"FindActorTag"。

    image alt text

  4. MyCharacter 蓝图中,从 ForEachLoop数组元素(Array Element) 引脚拖出,然后在 操作(Actions) 菜单中搜索 Get Tags

    image alt text

  5. 标签(Tags) 引脚拖出,然后在 操作(Actions) 菜单中搜索 Get 节点。

    image alt text

    此处,我们正在"获取"索引0处的标签,我们已在上文中将其设置为 FindActorTag

  6. 在图表中 右键点击,并在 操作(Actions) 菜单中搜索 Branch 节点。

    image alt text

  7. Branch 节点的 条件(Condition) 引脚拖出,然后添加 Actor Has Tag 节点。

    image alt text

  8. Get 节点的 输出(out) 引脚连接到 Actor Has Tag 节点上的 标签(Tag) 引脚。

    image alt text

  9. ForEachLoop 节点的 数组元素(Array Element) 引脚连接到 Actor Has Tag 节点上的 目标(Target) 引脚。

    image alt text

  10. ForEachLoop 引脚的 数组元素(Array Element) 拖出两次,获得 P_FireFire Audio 节点,并将它们连接到 Deactivate 节点。

    image alt text

  11. 点击 编译(Compile)保存(Save)

    image alt text

  12. 关卡视口(Level Viewport) 中选择你的 Blueprint_FireEffect 之一,然后在 细节(Details)面板 中,找到 标签(Tags) 变量,找到 FindActorTag 字段并打开下拉菜单,然后选择 删除(Delete) 删除标签变量。

    image alt text

为了演示功能,我们特意留下了一个没有标签的火焰效果。

  1. 找到 工具栏(Toolbar),按 运行(Play)(PIE)

    image alt text

你使用Gameplay静态库中的Get All Actors of Class函数来获取指定类的Actor数组。但是,你也可以在Actor上使用 标签(Tags) ,根据不同的条件筛选数组结果,以便从数组中获取特定的Actor或单个Actor。示例,

  1. 首先,找到 内容浏览器(Content Browser) > C++类(C++ Classes) 文件夹,然后双击 FireEffect Actor 打开其 FireEffect.cpp 文件。

image alt text

  1. FireEffect构造函数中 实现以下代码

    AFireEffect::AFireEffect()
    
    {
    
    Tags.Add(FName("FindActorTag"));
    
    }

    注意:标签是数组,是Actor类默认值的一部分,可以用于分组和分类。

  2. 编译 你的代码。

  3. 打开 BP_FireEffect ,然后在 细节(Details) 面板中找到 Actor 类别,你会注意到你的Actor标签已创建。

    image alt text

  4. 首先,找到 内容浏览器(Content Browser) > C++类(C++ Classes) 文件夹,然后双击 FindingActorsCharacter ,打开其 .cpp 文件。

image alt text

  1. OnFindActorPressed 方法中实现以下内容:

    void AFindingActorsCharacter::OnFindActorPressed()
    
    {
    
        TArray<AActor*> ActorsToFind;
    
    //获取所有具有"FindActorTag"的FireEffect类的Actor
    
        UGameplayStatics::GetAllActorsOfClassWithTag(GetWorld(), AFireEffect::StaticClass(), FName("FindActorTag"),ActorsToFind);
    
        for (AActor* FireEffectActor: ActorsToFind)
    
        {
    
            AFireEffect* FireEffectCast = Cast<AFireEffect>(FireEffectActor);
    
            if (FireEffectCast)
    
            {
    
             FireEffectCast->GetParticleFireComponent()->Deactivate();           FireEffectCast->GetFireAudioComponent()->Deactivate();
    
            }   
    
        }
    
    }
  2. 编译 你的代码。

  3. 关卡视口(Level Viewport) 中选择你的 BP_FireEffect 实例之一,然后在 细节(Details) 面板中找到 标签(Tags) 变量,找到 FindActorTag 字段,打开旁边的下拉菜单删除变量。

    image alt text

  4. 找到 工具栏(Toolbar) ,按 运行(Play)(PIE)

image alt text

最终效果

当按下数字1键时,你应该注意到,所有带有ActorsToFindTag的Bluprint_Fire_ Effect粒子均熄灭,而没有标签的火焰效果仍然存在。

image alt text

当按下数字1键时,你应该注意到,所有带有FindActorsTag的BP_FireEffect粒子都熄灭,而没有标签的火焰效果仍然存在。

image alt text

本文基于此前的虚幻引擎版本编写,未针对当前的虚幻引擎5.0版本更新过。