文章目录
- 一、自定义任务节点
 - 二、优化
 - 1. 子弹发射冷却
 - 2. 攻击时面朝玩家
 
一、自定义任务节点
- 本节需要创建自定义任务节点
BTTask,实现小兵进入角色范围后进射击的功能。 - 对于
BTTaskNode的子类,我们需要在代码中重写ExecuteTask函数即可。返回值为EBTNodeResult::Failed和EBTNodeResult::Successd,对应行为树的节点返回失败或者成功。 
//SBTTask_RangeAttack.h
UCLASS()
class FPSPROJECT_API USBTTask_RangeAttack : public UBTTaskNode
{
   GENERATED_BODY()
protected:
   virtual EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override;
   
   //用于角色发射投掷物攻击
   UPROPERTY(EditAnywhere, Category = "AI")
   TSubclassOf<AActor> ProjectileClass;
};
//SBTTask_RangeAttack.cpp
EBTNodeResult::Type USBTTask_RangeAttack::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
	AAIController* MyController = OwnerComp.GetAIOwner();
	if(ensure(MyController))
	{
		ACharacter* MyPawn = Cast<ACharacter>(MyController->GetPawn());
		if(MyPawn == nullptr)
		{
			return EBTNodeResult::Failed;
		}
		AActor* TargetActor = Cast<AActor>(OwnerComp.GetBlackboardComponent()->GetValueAsObject("TargetActor"));
		if(TargetActor == nullptr)
		{
			return EBTNodeResult::Failed;
		}
		FVector MuzzleLocation = MyPawn->GetMesh()->GetSocketLocation("Muzzle_01");
		//方向向量=目标位置-当前位置
		FVector Direction = TargetActor->GetActorLocation() - MuzzleLocation;
		FRotator MuzzleRotation = Direction.Rotation();
		FActorSpawnParameters params;
		params.Instigator = MyPawn;
		params.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
		ensure(ProjectileClass);
		AActor* NewProj = GetWorld()->SpawnActor<AActor>(ProjectileClass, MuzzleLocation, MuzzleRotation);
		return NewProj ? EBTNodeResult::Succeeded : EBTNodeResult::Failed;
	}
	return EBTNodeResult::Failed;
}
 
二、优化
1. 子弹发射冷却
Cooldown节点会控制节点执行的间隔,当节点处于冷却时间时,会直接返回false,以下节点自然都不会执行。Loop节点则会循环执行以下节点。
此时AI的逻辑:如果目标在攻击范围外,会向目标移动。进入攻击范围后,开枪向角色以0.5s为间隔时间射击三次,冷却2s。在此期间,行为树会运行后面两个节点,再重新判断是否结束冷却。
2. 攻击时面朝玩家
行为树自带了一个修改AI小兵的朝向服务BTService:Set defalt focus,从而不需要再使用SetActorRotation函数
- 最终的完整图(包括之后的EQS):

 


















