六一的部落格


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




说明

自定义服务: 对距离最近敌人射击


创建服务类

-
base BTService
Public
AI/Services
STUFireService

添加构造函数: 设置名称

public

ShootThemUp: AI/Services/STUFireService.h

1USTUFireService();

ShootThemUp: AI/Services/STUFireService.cpp

1USTUFireService::USTUFireService()
2{
3    NodeName = "Fire";
4}

添加属性: 存放敌人信息

protected

ShootThemUp: AI/Services/STUFireService.h

1UPROPERTY(EditAnywhere, BlueprintReadWrite)
2FBlackboardKeySelector EnemyActorKey;

服务逻辑: 实现TickNode

protected

ShootThemUp: AI/Services/STUFireService.h

1virtual void TickNode(UBehaviorTreeComponent &OwnerComp, uint8 *NodeMemory, float DeltaSeconds) override;

不需要检查EnemyActor的设置情况, 上节的Decorator提供检查; 还是推荐一个自给自足的逻辑闭环

ShootThemUp: AI/Services/STUFireService.cpp

 1#include "BehaviorTree/BlackboardComponent.h"
 2#include "AIController.h"
 3#include "Components/STUWeaponComponent.h"
 4#include "STUUtils.h"
 5
 6void USTUFireService::TickNode(UBehaviorTreeComponent &OwnerComp, uint8 *NodeMemory, float DeltaSeconds)
 7{
 8    const auto Controller = OwnerComp.GetAIOwner();
 9    const auto Blackboard = OwnerComp.GetBlackboardComponent();
10
11    const auto HasAim = Blackboard && Blackboard->GetValueAsObject(EnemyActorKey.SelectedKeyName);
12
13    if (Controller)
14    {
15        const auto WeaponComponent = STUUtils::GetSTUPlayerComponent<USTUWeaponComponent>(Controller->GetPawn());
16        if (WeaponComponent)
17        {
18            HasAim ? WeaponComponent->FireStart() : WeaponComponent->FireStop();
19        }
20    }
21}

应该在TickNode最后调用基类TickNode

1Super::TickNode(OwnerComp, NodeMemory, DeltaSeconds);

修改武器基类射击逻辑

STUBaseWeapon

NPC的控制器类型为AIController, 控制器相关逻辑需调整

获取子弹轨迹信息: GetTraceData; 调用GetPlayerViewPoint; 被武器派生类的MakeShot调用


APlayerController::GetPlayerViewPoint

AIController不具有类似功能的成员函数

若游戏角色的控制器类型为APlayerController, 走原有逻辑; 自行设置子弹起点和方向向量

ShootThemUp: Weapon/STUBaseWeapon.cpp

 1// GetPlayerViewPoint
 2
 3const auto STUCharacter = Cast<ACharacter>(GetOwner());
 4if (!STUCharacter) return false;
 5
 6if (STUCharacter->IsPlayerControlled())
 7{
 8    // 原逻辑
 9}
10else
11{
12    ViewLocation = GetMuzzleWorldLocation();
13    ViewRotation = WeaponMeshComponent->GetSocketRotation(MuzzleSocketName);
14}
15return true;

查看


调整NPC视觉感知参数

BP_STUAIController > STUAIPerceptionComponent

-
Sight Radius 2000
Lose Sight Radius 2500
PeripheralVisionHalfAngleDegrees 90



设置行为树

BT_STUCharacter

  • 为Attack添加射击服务

  • 设置射击目标

    选中 STUFireService , 设置 Details > STUFire Service > Enemy Actor Key 为EnemyActor



总结

  1. NPC注意到敌人就可以瞄准射击, 这一点太猛了
  2. 之前为NPC添加了转向过渡动画, 而射击在这之前

说明

自定义服务: 对距离最近敌人射击


创建服务类

-
base BTService
Public
AI/Services
STUFireService

添加构造函数: 设置名称

public

ShootThemUp: AI/Services/STUFireService.h

1USTUFireService();

ShootThemUp: AI/Services/STUFireService.cpp

1USTUFireService::USTUFireService()
2{
3    NodeName = "Fire";
4}

添加属性: 存放敌人信息

protected

ShootThemUp: AI/Services/STUFireService.h

1UPROPERTY(EditAnywhere, BlueprintReadWrite)
2FBlackboardKeySelector EnemyActorKey;

服务逻辑: 实现TickNode

protected

ShootThemUp: AI/Services/STUFireService.h

1virtual void TickNode(UBehaviorTreeComponent &OwnerComp, uint8 *NodeMemory, float DeltaSeconds) override;

不需要检查EnemyActor的设置情况, 上节的Decorator提供检查; 还是推荐一个自给自足的逻辑闭环

ShootThemUp: AI/Services/STUFireService.cpp

 1#include "BehaviorTree/BlackboardComponent.h"
 2#include "AIController.h"
 3#include "Components/STUWeaponComponent.h"
 4#include "STUUtils.h"
 5
 6void USTUFireService::TickNode(UBehaviorTreeComponent &OwnerComp, uint8 *NodeMemory, float DeltaSeconds)
 7{
 8    const auto Controller = OwnerComp.GetAIOwner();
 9    const auto Blackboard = OwnerComp.GetBlackboardComponent();
10
11    const auto HasAim = Blackboard && Blackboard->GetValueAsObject(EnemyActorKey.SelectedKeyName);
12
13    if (Controller)
14    {
15        const auto WeaponComponent = STUUtils::GetSTUPlayerComponent<USTUWeaponComponent>(Controller->GetPawn());
16        if (WeaponComponent)
17        {
18            HasAim ? WeaponComponent->FireStart() : WeaponComponent->FireStop();
19        }
20    }
21}

应该在TickNode最后调用基类TickNode

1Super::TickNode(OwnerComp, NodeMemory, DeltaSeconds);

修改武器基类射击逻辑

STUBaseWeapon

NPC的控制器类型为AIController, 控制器相关逻辑需调整

获取子弹轨迹信息: GetTraceData; 调用GetPlayerViewPoint; 被武器派生类的MakeShot调用


APlayerController::GetPlayerViewPoint

AIController不具有类似功能的成员函数

若游戏角色的控制器类型为APlayerController, 走原有逻辑; 自行设置子弹起点和方向向量

ShootThemUp: Weapon/STUBaseWeapon.cpp

 1// GetPlayerViewPoint
 2
 3const auto STUCharacter = Cast<ACharacter>(GetOwner());
 4if (!STUCharacter) return false;
 5
 6if (STUCharacter->IsPlayerControlled())
 7{
 8    // 原逻辑
 9}
10else
11{
12    ViewLocation = GetMuzzleWorldLocation();
13    ViewRotation = WeaponMeshComponent->GetSocketRotation(MuzzleSocketName);
14}
15return true;

查看


调整NPC视觉感知参数

BP_STUAIController > STUAIPerceptionComponent

-
Sight Radius 2000
Lose Sight Radius 2500
PeripheralVisionHalfAngleDegrees 90



设置行为树

BT_STUCharacter

  • 为Attack添加射击服务

  • 设置射击目标

    选中 STUFireService , 设置 Details > STUFire Service > Enemy Actor Key 为EnemyActor



总结

  1. NPC注意到敌人就可以瞄准射击, 这一点太猛了
  2. 之前为NPC添加了转向过渡动画, 而射击在这之前