Ue4C++编程------AI与c++(四)

    上文中,我们介绍了怎么更新我们的黑板数据,怎么将黑板数据与行为树绑定,怎么运行我们的行为树。本文将介绍行为树的一些节点。首先介绍的就是Task节点,Task故名思意就是任务节点的意思。Task节点只能作为行为树的叶子节点。首先我们创建一个c++类,继承自BTTask,如下图所示:

    

    创建完该类后,重写ExecuteTask函数,在ExecuteTask函数中,我们需要让我们的AI移动到targetlocation,如下所示:

virtual EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override;
EBTNodeResult::Type UMoveBTTaskNode::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
	AAIBlogController* AIC = Cast<AAIBlogController>(OwnerComp.GetAIOwner()); // 获得行为树的所属control
	if (AIC != nullptr)
	{
		FVector TargetLocation = OwnerComp.GetBlackboardComponent()->GetValueAsVector(TEXT("TargetLocation")); // 获得黑板上的数据
		AAIBlogCharacter* AI = Cast<AAIBlogCharacter>(AIC->GetPawn()); // 获取所控制的AI
		if (AI != nullptr) // 让AI移动到targetlocation
		{
			AIC->MoveToLocation(TargetLocation);
			return EBTNodeResult::Succeeded;
		}
		else
		{
			return EBTNodeResult::Failed;
		}
	}
	else
	{
		return EBTNodeResult::Failed; // 失败
	}
}

    接下来介绍第二个节点,就是Decorators,该节点是一个判断节点,可以附加task,selector和sequence节点上,起到条件作用,决定是否执行。我们创建一个closeenough节点,当距离过近的时候,就不进行我们的ai移动,如下所示:

    

    在新创建的类里,重写CalculateRawConditionValue函数,这个函数返回的是bool值,true表示接着往下执行,false为返回。如下所示:

virtual bool CalculateRawConditionValue(UBehaviorTreeComponent& OwnerComp, uint8 * NodeMemory) const override;
	UPROPERTY(EditAnywhere, Category = LimitDis)
	float fDis;

    fDis设置成编辑器可编辑,这样就可以在编辑器中调整我们的最短距离。CalculateRawConditionValue的实现如下所示:

bool UCloseEnoughBTDecorator::CalculateRawConditionValue(UBehaviorTreeComponent& OwnerComp, uint8 * NodeMemory) const
{
	AAIBlogController* AIC = Cast<AAIBlogController>(OwnerComp.GetAIOwner());
	if (AIC != nullptr)
	{
		FVector AILocation = Cast<AAIBlogCharacter>(AIC->GetPawn())->GetActorLocation();
		ABlogProjectCharacter* Player = Cast<ABlogProjectCharacter>(GetWorld()->GetFirstPlayerController()->GetPawn()); // 获得玩家
		if (Player != nullptr)
		{
			FVector PlayerLocation = Player->GetActorLocation();
			// 计算距离
			float Dis = (PlayerLocation - AILocation).Size();
			if (Dis < fDis)
			{
				return false; // 足够近,不移动了
			}
			else
			{
				return true; // 不够近,继续移动
			}
		}
		else
		{
			return false;
		}
	}
	else
	{
		return false;
	}
}

    编译我们的代码,在编译我们的代码之前,要先将AI模块加入到我们的配置里面,如下所示:

    

    接下来就要构建我们的行为树了,selector节点表示选择执行,即对selector节点的所有子节点进行执行,知道成功为止则返回根。而sequence节点呢,对所有字节点进行执行,直到失败位置。这就是这两个节点的区别。

    首先从我们的Root节点,添加一个子节点,为selector,如下所示:

扫描二维码关注公众号,回复: 1842542 查看本文章

    

    接着为我们的selector添加一个Blacboard的Decorator,表示当黑板资源的targetlocation值设置了我们才往下执行我们的节点,如下图所示:

    

    选择我们的targetlocation,如下图所示:

    

    接下来从selector中,添加我们的之前创建的movetask。并且为我们的movetask节点添加修饰closeenough,如下图所示:

    

    接着为selector再新建一个子节点,选择wait的任务,使我们的ai离我们的任务足够近的时候,等待一段时间,如下所示:

    

    接下来,则为我们的aicharacter,生成蓝图,调整我们的Sight组件,并拖入关卡中进行测试吧,如下图所示:

    

    

    经测试,成功,AI能够移动到人物这,如下图所示:

    

猜你喜欢

转载自blog.csdn.net/li2818/article/details/80848324