UnrealEngine是一个非常强大的引擎,UE4基于DirectX11,拥有新的材料流水线、蓝图视觉化脚本、直观蓝图调试、内容浏览器、人物动画、Matinee影院级工具集、后期处理效果、热重载、模拟与沉浸式视角、实时游戏预览、AI人工智能、音频、中间件集成等一系列全新特性。
下面是用C++结合蓝图实现一个简单的AI功能。效果如下图
首先创建一个C++的第三人称工程,UE4的工程有很多类型,我们可以根据自己的需要选择。
然后新建需要的C++文件,包括AIPatrol、AIPatrolController、AI巡逻的目标点AITargetPoint,类型分别为Character、Controller、TargetPoint。
将上述三个文件扩展成蓝图,这样C++和蓝图可以结合起来,比较方便的实现一些功能。
新建BehaviorTree、Blackboard。行为树用来实现AI的逻辑。
![T98AAKVRE6
]OVK5(AWG0A.png](http://upload-images.jianshu.io/upload_images/1765742-312a11011d4cc53f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)在AIPatrol上加BehaviorTree:
UPROPERTY(EditAnywhere,Category=AI)//add behavior to character
class UBehaviorTree* BehaviorTree;
- 配置character的参数
![($$_]V}CV$-GAEQ5IIO7MOE.png](http://upload-images.jianshu.io/upload_images/1765742-ad8ce6fb1d799c49.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- AIPatrolController
.h文件:
/*behavior tree component*/
UBehaviorTreeComponent* BehaviorComp;
/*Our blackboard component*/
UBlackboardComponent* BlackboardComp;
/*Blackboard keys*/
UPROPERTY(EditDefaultsOnly, Category = AI)
FName LocationToGoKey;
UPROPERTY(EditDefaultsOnly, Category = AI)
FName PlayerKey;
//store all TargetPoints
TArray PatrolPoints;
virtual void Possess(APawn* Pawn) override;
public:
AAIPatrolController();
void SetPlayerCaught(APawn* Pawn);//caught:捕捉
/*Inline getter functions*/
FORCEINLINE UBlackboardComponent* GetBlackboardComp() const { return BlackboardComp; }
FORCEINLINE TArray GetPatrolPoints() const { return PatrolPoints; }
.cpp文件:
AAIPatrolController::AAIPatrolController()
{
/*initialize blackboard and behavior tree*/
BehaviorComp = CreateDefaultSubobject(TEXT("BehaviorComp"));
BlackboardComp = CreateDefaultSubobject(TEXT("BlackboardComp"));
/*Initialize blackboard keys*/
PlayerKey = "Target";
LocationToGoKey = "LocationToGo";
}
void AAIPatrolController::SetPlayerCaught(APawn* MyPawn)
{
if (BlackboardComp)
{
BlackboardComp->SetValueAsObject(PlayerKey, MyPawn);
}
}
void AAIPatrolController::Possess(APawn* MyPawn)
{
Super::Possess(MyPawn);
/*Get reference to the character*/
AAIPatrol* AICharacter = Cast(MyPawn);
if (AICharacter)
{
if (AICharacter->BehaviorTree->BlackboardAsset)
{
BlackboardComp->InitializeBlackboard(*(AICharacter->BehaviorTree->BlackboardAsset));
}
/*Populate patrol point array*/
UGameplayStatics::GetAllActorsOfClass(GetWorld(), AAIpPatrolPoint::StaticClass(), PatrolPoints);
BehaviorComp->StartTree(*AICharacter->BehaviorTree);
}
}
- 玩家被抓住的方法:
AIPatrolController:
void AAIPatrolController::SetPlayerCaught(APawn* MyPawn)//玩家被抓住
{
if (BlackboardComp)
{
BlackboardComp->SetValueAsObject(PlayerKey, MyPawn);//给玩家添加key值
}
}
AIPatrol:
AAIPatrol::AAIPatrol()
{
//Initialize senses
/**UPawnSensingComponent :
* SensingComponent encapsulates(封装) sensory(感知) (ie sight and hearing) settings and functionality for an Actor,
* allowing the actor to see/hear Pawns in the world. It does nothing on network clients.
*/
PawnSensingComp = CreateDefaultSubobject(TEXT("PawnSensingComp"));
PawnSensingComp->SetPeripheralVisionAngle(90.0f);
}
// Called when the game starts or when spawned
void AAIPatrol::BeginPlay()
{
Super::BeginPlay();
if (PawnSensingComp)
{
/** OnSeePawn : Delegate to execute when we see a Pawn. */
PawnSensingComp->OnSeePawn.AddDynamic(this, &AAIPatrol::OnplayerCaught);
}
}
void AAIPatrol::OnplayerCaught(APawn* Pawn)
{
/*Get a reference to the palyer controller*/
AAIPatrolController* AIController = Cast(GetController());
if (AIController)
{
GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("You having been caught!"));
AIController->SetPlayerCaught(Pawn);
}
}
* 创建BTTask的C++文件,命名为BTSelectPatrolPoint。注意,这时要在Source文件夹中找到ProjectName.Build.cs文件,添加GameplayTasks到PublicDependencyModuleName中。.build.cs文件是编译文件,位于游戏性模块的根目录中,它定义了UnrealBuildTool编译该模块时要使用的一些信息。
BTTask:
EBTNodeResult::Type UBTSelectPatrolPoint::ExecuteTask(UBehaviorTreeComponent & OwnerComp, uint8 * NodeMemory)
{
//get AIPatrolController
AAIPatrolController* AICon = Cast(OwnerComp.GetAIOwner());
// check the get is successful
if (AICon)
{
//Get Blackboard Component
UBlackboardComponent* BlackboardComp = AICon->GetBlackboardComp();
// get patrolPoint
AAIpPatrolPoint* CurrentPoint = Cast(BlackboardComp->GetValueAsObject("LocationToGo"));
TArray AvailablePatrolPoints = AICon->GetPatrolPoints();
AAIpPatrolPoint* NextPatrolPoint = nullptr;
// set NextPatrolPoint
if (AICon->CurrentPatrolPoint != AvailablePatrolPoints.Num() - 1)
{
NextPatrolPoint = Cast(AvailablePatrolPoints[++AICon->CurrentPatrolPoint]);
}
else
{
NextPatrolPoint = Cast(AvailablePatrolPoints[0]);
AICon->CurrentPatrolPoint = 0;
}
// set blackboard keyValue
BlackboardComp->SetValueAsObject("LocationToGo", NextPatrolPoint);
return EBTNodeResult::Succeeded;
}
return EBTNodeResult::Failed;
}
- 将BP_AIPatrol放入场景,摆放好BP_AIPatrolPoints,即AI 要走的路径,编辑BehaviorTree。
BehaviorTree的思路是首先执行BTSelectPatrolPoint,如果没有找到目标,就move to key值为LocationToGo的点,如果找到了Target,就移动到Target处,然后在target处停留1秒。
- 最后,添加自动寻路组件NavMeshBoundsVolume,这样AI在寻路过程中就会自动绕开障碍物。