六一的部落格


关关难过关关过,前路漫漫亦灿灿。




说明

AI / EQS / Find Health Pickup


概览

  • EQS生成器
  • 生成器限制条件
  • 使用C++实现Decorator

暂时修改生命补给外观

EQS标记也是亮色

  1. Content > Materials 目录下选中 M_BaseColor

  2. 选择关卡中的BP_STUHealthPickup, 通过Details面板在蓝图编辑器中打开 BP_STUHealthPickup


  3. 选中 Static Mesh , 应用材质


  4. 回到关卡编辑器, 按住 Option 拖动BP_STUHealthPickup进行复制, 共三个

  5. 在场景中添加墙

    Place Actors > Geometry > Box

  6. 设置墙; 将一个生命补给放在墙后

    Details > Brush Settings , 设置X = 50, Y = 500, Z = 500



创建EQS资产

Content/AI/EQS 目录下, 新建EQS资产, 命名为EQS_FindHealthPickup


添加生成器, 寻找场景中指定类型的Actor

Generators > Actors Of Class

-
Searched Actor Class 指定Actor类型 STUHealthPickup
Search Radius 搜索半径 1500



设置场景中EQS_TestPawn使用的EQS模板

Details > EQS > Query Template , 选择EQS_FindHealthPickup

移动EQS_TestPawn到合适位置, 三个生命补给均被标记为亮蓝色, 此时无视阻挡, 以搜索半径为准



为生成器添加限制条件: 要求视线可见

Add Test > Trace

在Visibility通道计算Pawn到Actor之间是否存在其他物体阻挡视线

  • 使用默认设置

    -
    Trace > Trace Data > Trace Channel Visibility
    Trace > Trace Data > Trace Shape Line


  • 勾选则要求阻挡


  • 取消勾选则要求无阻挡


  • 设置为无阻挡

    -
    Filter > Bool Match 取消勾选

    通道存在阻挡则Actor被标记为蓝色; 无阻挡被标记为绿色


为生成器添加限制条件: 寻找距离最近的生命补给

Add Test > Distance

-
Filter > Filter Type Minimum
Filter > Float Value Min 0
Score > Scoring Factor -1 距离越近, 权重越大



为生成器添加限制条件: 存在获取生命补给的有效路径

Add Test > Path Finding

过滤掉无法去到的生命补给

使用默认设置

-
Pathfinding > Test Mode Path Exists



在行为树中使用EQS_FindHealthPickup

  1. 暂时停止当前逻辑

  2. 添加节点: Selector

    NPC寻找生命补给, 或等待

  3. 添加节点: Wait

    设置时长为2s

  4. 添加序列

  5. 为序列添加任务: RunEQSQuery

  6. 设置EQS

    • Details > EQS > EQSRequest > Query Template , 设置为EQS_FindHealthPickup
    • Details > Blackboard > Blackboard Key , 设置为AimLocation


  7. 为序列添加任务: MoveTo

    Details > Blackboard > Blackboard Key , 设置为AimLocation



查看

  1. 在选中窗口运行


  2. 按下 F8 或者点击 Eject


  3. 拖动距离NPC最近的生命补给: NPC寻找并去到此时距离最近的生命补给位置

  4. 点击 Pause simulation , 将所有生命补给移动到墙后, 点击 Resume play-in-editor session

    序列停止, NPC循环执行Wait任务


使用C++实现Decorator

检查NPC生命值, 低于给定百分比NPC才会拾取生命补给


学习BTDecorator类

在CalculateRawConditionValue中计算条件布尔值

protected

1// calculates raw, core value of decorator's condition. Should not include calling IsInversed
2virtual bool CalculateRawConditionValue(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) const; 

创建C++类

-
基类 BTDecorator
名称 STUHealthPercentDecorator
路径 AI/Decorators
属性 Public

添加到头文件搜索路径

ShootThemUp: ShootThemUp.Build.cs

 1PublicIncludePaths.AddRange(new string[]
 2{
 3    "ShootThemUp/Public/Player",
 4    "ShootThemUp/Public/Components",
 5    "ShootThemUp/Public/Dev",
 6    "ShootThemUp/Public/Weapon",
 7    "ShootThemUp/Public/UI",
 8    "ShootThemUp/Public/Animations",
 9    "ShootThemUp/Public/Pickups",
10    "ShootThemUp/Public/Weapon/Components",
11    "ShootThemUp/Public/AI",
12    "ShootThemUp/Public/AI/Tasks",
13    "ShootThemUp/Public/AI/Services",
14    "ShootThemUp/Public/AI/EQS",
15    "ShootThemUp/Public/AI/Decorators"
16});

添加构造函数

public

ShootThemUp: AI/Decorators/STUHealthPercentDecorator.h

1USTUHealthPercentDecorator();

ShootThemUp: AI/Decorators/STUHealthPercentDecorator.cpp

1USTUHealthPercentDecorator::USTUHealthPercentDecorator()
2{
3    NodeName = "Health Percent";
4}

添加属性: 指定生命值

protected

ShootThemUp: AI/Decorators/STUHealthPercentDecorator.h

1UPROPERTY(EditAnywhere, BlueprintReadWrite)
2float HealthPercent = 0.6f;

覆写条件

protected

ShootThemUp: AI/Decorators/STUHealthPercentDecorator.h

1virtual bool CalculateRawConditionValue(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) const override;

通过控制器获取当前Pawn, 通过Pawn获取健康组件

ShootThemUp: AI/Decorators/STUHealthPercentDecorator.cpp

 1#include "AIController.h"
 2#include "STUUtils.h"
 3#include "Components/STUHealthComponent.h"
 4
 5bool USTUHealthPercentDecorator::CalculateRawConditionValue(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) const
 6{
 7    const auto Controller = OwnerComp.GetAIOwner();
 8    if (!Controller) return false;
 9
10    const auto HealthComponent = STUUtils::GetSTUPlayerComponent<USTUHealthComponent>(Controller->GetPawn());
11    if (!HealthComponent || HealthComponent->IsDead()) return false;
12
13    return HealthComponent->GetHealthPercent() <= HealthPercent;
14}

使用STUHealthPercentDecorator

BT_STUCharacter

  1. 为Sequence添加Decorator

  2. 设置STUHealthPercentDecorator

    -
    Observer aborts Self


  3. 查看

    NPC满生命值时呆在原地 > 使之生命值不大于60% > NPC去到生命补给所在


整理行为树

  1. 将本节新建序列移动到原行为树左侧: 优先级最高


  2. 作为Selector的下级; 设置Root节点


  3. 将Fire服务移动到选择器

    NPC寻找生命补给时仍射击敌人(是否有敌人?)


  4. 查看时注意NPC是否满足寻找生命补给条件


恢复设置

  1. 可以恢复Fire服务目标: 保证当前为None


  2. 恢复生命补给材质


使用EQS寻找生命补给



说明

AI / EQS / Find Health Pickup


概览

  • EQS生成器
  • 生成器限制条件
  • 使用C++实现Decorator

暂时修改生命补给外观

EQS标记也是亮色

  1. Content > Materials 目录下选中 M_BaseColor

  2. 选择关卡中的BP_STUHealthPickup, 通过Details面板在蓝图编辑器中打开 BP_STUHealthPickup


  3. 选中 Static Mesh , 应用材质


  4. 回到关卡编辑器, 按住 Option 拖动BP_STUHealthPickup进行复制, 共三个

  5. 在场景中添加墙

    Place Actors > Geometry > Box

  6. 设置墙; 将一个生命补给放在墙后

    Details > Brush Settings , 设置X = 50, Y = 500, Z = 500



创建EQS资产

Content/AI/EQS 目录下, 新建EQS资产, 命名为EQS_FindHealthPickup


添加生成器, 寻找场景中指定类型的Actor

Generators > Actors Of Class

-
Searched Actor Class 指定Actor类型 STUHealthPickup
Search Radius 搜索半径 1500



设置场景中EQS_TestPawn使用的EQS模板

Details > EQS > Query Template , 选择EQS_FindHealthPickup

移动EQS_TestPawn到合适位置, 三个生命补给均被标记为亮蓝色, 此时无视阻挡, 以搜索半径为准



为生成器添加限制条件: 要求视线可见

Add Test > Trace

在Visibility通道计算Pawn到Actor之间是否存在其他物体阻挡视线

  • 使用默认设置

    -
    Trace > Trace Data > Trace Channel Visibility
    Trace > Trace Data > Trace Shape Line


  • 勾选则要求阻挡


  • 取消勾选则要求无阻挡


  • 设置为无阻挡

    -
    Filter > Bool Match 取消勾选

    通道存在阻挡则Actor被标记为蓝色; 无阻挡被标记为绿色


为生成器添加限制条件: 寻找距离最近的生命补给

Add Test > Distance

-
Filter > Filter Type Minimum
Filter > Float Value Min 0
Score > Scoring Factor -1 距离越近, 权重越大



为生成器添加限制条件: 存在获取生命补给的有效路径

Add Test > Path Finding

过滤掉无法去到的生命补给

使用默认设置

-
Pathfinding > Test Mode Path Exists



在行为树中使用EQS_FindHealthPickup

  1. 暂时停止当前逻辑

  2. 添加节点: Selector

    NPC寻找生命补给, 或等待

  3. 添加节点: Wait

    设置时长为2s

  4. 添加序列

  5. 为序列添加任务: RunEQSQuery

  6. 设置EQS

    • Details > EQS > EQSRequest > Query Template , 设置为EQS_FindHealthPickup
    • Details > Blackboard > Blackboard Key , 设置为AimLocation


  7. 为序列添加任务: MoveTo

    Details > Blackboard > Blackboard Key , 设置为AimLocation



查看

  1. 在选中窗口运行


  2. 按下 F8 或者点击 Eject


  3. 拖动距离NPC最近的生命补给: NPC寻找并去到此时距离最近的生命补给位置

  4. 点击 Pause simulation , 将所有生命补给移动到墙后, 点击 Resume play-in-editor session

    序列停止, NPC循环执行Wait任务


使用C++实现Decorator

检查NPC生命值, 低于给定百分比NPC才会拾取生命补给


学习BTDecorator类

在CalculateRawConditionValue中计算条件布尔值

protected

1// calculates raw, core value of decorator's condition. Should not include calling IsInversed
2virtual bool CalculateRawConditionValue(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) const; 

创建C++类

-
基类 BTDecorator
名称 STUHealthPercentDecorator
路径 AI/Decorators
属性 Public

添加到头文件搜索路径

ShootThemUp: ShootThemUp.Build.cs

 1PublicIncludePaths.AddRange(new string[]
 2{
 3    "ShootThemUp/Public/Player",
 4    "ShootThemUp/Public/Components",
 5    "ShootThemUp/Public/Dev",
 6    "ShootThemUp/Public/Weapon",
 7    "ShootThemUp/Public/UI",
 8    "ShootThemUp/Public/Animations",
 9    "ShootThemUp/Public/Pickups",
10    "ShootThemUp/Public/Weapon/Components",
11    "ShootThemUp/Public/AI",
12    "ShootThemUp/Public/AI/Tasks",
13    "ShootThemUp/Public/AI/Services",
14    "ShootThemUp/Public/AI/EQS",
15    "ShootThemUp/Public/AI/Decorators"
16});

添加构造函数

public

ShootThemUp: AI/Decorators/STUHealthPercentDecorator.h

1USTUHealthPercentDecorator();

ShootThemUp: AI/Decorators/STUHealthPercentDecorator.cpp

1USTUHealthPercentDecorator::USTUHealthPercentDecorator()
2{
3    NodeName = "Health Percent";
4}

添加属性: 指定生命值

protected

ShootThemUp: AI/Decorators/STUHealthPercentDecorator.h

1UPROPERTY(EditAnywhere, BlueprintReadWrite)
2float HealthPercent = 0.6f;

覆写条件

protected

ShootThemUp: AI/Decorators/STUHealthPercentDecorator.h

1virtual bool CalculateRawConditionValue(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) const override;

通过控制器获取当前Pawn, 通过Pawn获取健康组件

ShootThemUp: AI/Decorators/STUHealthPercentDecorator.cpp

 1#include "AIController.h"
 2#include "STUUtils.h"
 3#include "Components/STUHealthComponent.h"
 4
 5bool USTUHealthPercentDecorator::CalculateRawConditionValue(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) const
 6{
 7    const auto Controller = OwnerComp.GetAIOwner();
 8    if (!Controller) return false;
 9
10    const auto HealthComponent = STUUtils::GetSTUPlayerComponent<USTUHealthComponent>(Controller->GetPawn());
11    if (!HealthComponent || HealthComponent->IsDead()) return false;
12
13    return HealthComponent->GetHealthPercent() <= HealthPercent;
14}

使用STUHealthPercentDecorator

BT_STUCharacter

  1. 为Sequence添加Decorator

  2. 设置STUHealthPercentDecorator

    -
    Observer aborts Self


  3. 查看

    NPC满生命值时呆在原地 > 使之生命值不大于60% > NPC去到生命补给所在


整理行为树

  1. 将本节新建序列移动到原行为树左侧: 优先级最高


  2. 作为Selector的下级; 设置Root节点


  3. 将Fire服务移动到选择器

    NPC寻找生命补给时仍射击敌人(是否有敌人?)


  4. 查看时注意NPC是否满足寻找生命补给条件


恢复设置

  1. 可以恢复Fire服务目标: 保证当前为None


  2. 恢复生命补给材质