【UE4C++-ActionRougelike-10】AI基础
1、AI系统
UE中内置了强大的人工智能(AI)系统,用于创建复杂的游戏角色和NPC行为。以下是虚幻引擎中的一些主要的AI系统和功能:
1.1AI控制器(AI Controller)
AI控制器是虚幻引擎中负责处理游戏角色和NPC行为的组件之一。用于控制角色的移动、旋转、寻路、攻击、对话等行为,并且可以与游戏角色或NPC关联。
1.2 黑板(Blackboard)
黑板是一种用于在AI系统中存储和共享数据的工具。它允许AI角色在运行时根据条件和情境来读取和写入数据,例如目标位置、目标状态、感知到的敌人等。
1.3 任务系统(Behavior Tree)
任务系统是一种基于行为树(Behavior Tree)的AI行为管理工具。行为树是一种树状结构,用于描述复杂的决策流程和行为序列。行为树系统可以通过可视化编辑器创建任务树,并与AI控制器关联。任务树可以用于管理角色的行为、决策、状态转换等。
1.4 感知系统(Perception System)
感知系统允许AI角色感知游戏世界中的其他角色、物体和环境信息。感知系统支持多种感知方式,例如视觉、听觉、碰触等,感知系统可以用于实现角色的警戒、追踪、攻击等行为。
1.5 寻路系统(Navigation System)
寻路系统允许AI角色在游戏世界中进行导航和移动。它可以生成路径、处理障碍、进行跳跃、避免碰撞等。虚幻引擎中的寻路系统支持多种导航方式,例如网格导航、点导航、复合导航等,并且可以与AI控制器、行为树等其他系统集成。
1.6 追踪器(EQS)
追踪器(Environment Query System,简称EQS)是虚幻引擎中用于在环境中进行查询和搜索的工具。EQS允许AI角色通过查询环境中的属性、特征、位置等信息来做出决策和行为选择。它可以用于实现角色的目标选择、目标评估、目标搜索等功能。
更详细内容参考官方文档。
2、AI寻路角色
2.1 创建AI角色
以Character为父类创建AI角色类MyAICharacter,以MyAICharacter为父类创建蓝图类MinionRanged_BP,并设置相应Mesh和Animation。
2.2 设置导航
向世界添加导航网格边界体(Nav Mesh Bounds Volume),并覆盖整个Level。
2.3 寻路行为树
新建行为树MinionRanged_BT和黑板MinionRanged_BB。在黑板中设置数据,添加Object类型key,命名为TargetActor,Base Class选择Actor。TargetActor用作于AI跟踪目标。
在行为树中编写AI行动逻辑,设置Blackboard Asset为MinionRanged_BB,并在根节点下添加Sequence,添加MoveTo和Wait节点,并设置MoveTo对象为TargetActor。
2.4 设置寻路对象
以AIController为父类创建MyAIController类。
class ACTIONROGUELIKE_API AMyAIController : public AAIController
{
GENERATED_BODY()
protected:
UPROPERTY(EditDefaultsOnly, Category = "AI")
UBehaviorTree* BehaviorTree;
virtual void BeginPlay() override;
};
在MyAIController.cpp中,BeginPlay()开始后运行行为树,并且为Blackboard中的TargetActor赋值为玩家
void AMyAIController::BeginPlay()
{
Super::BeginPlay();
//运行行为树
RunBehaviorTree(BehaviorTree);
APawn* MyPawn = UGameplayStatics::GetPlayerPawn(this, 0);
if (MyPawn)
{
//GetBlackboardComponent()->SetValueAsVector("MoveToLocation", MyPawn->GetActorLocation());
//设置寻路目标Actor为玩家
GetBlackboardComponent()->SetValueAsObject("TargetActor", MyPawn);
}
}
最终效果演示如下:
3、自定义检查攻击范围
3.1 创建行为树节点类
以BTService为父类创建行为树节点类MyBTService_CheckAttackRange
UCLASS()
class ACTIONROGUELIKE_API UMyBTService_CheckAttackRange : public UBTService
{
GENERATED_BODY()
protected:
//TickNode 函数是 UBTService 类中的一个虚函数,用于在行为树(Behavior Tree)节点每一帧被执行时调用。
virtual void TickNode(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds) override;
UPROPERTY(EditAnywhere, Category = "AI")
FBlackboardKeySelector AttackRangeKey;
};
在MyBTService_CheckAttackRange.cpp中实现TickNode中的逻辑功能
// OwnerComp 参数获取了行为树组件的黑板组件
void UMyBTService_CheckAttackRange::TickNode(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds)
{
Super::TickNode(OwnerComp,NodeMemory,DeltaSeconds);
UBlackboardComponent* BlackboardComp = OwnerComp.GetBlackboardComponent();
if (ensure(BlackboardComp))
{
//从黑板组件中获取了名为 "TargetActor" 的黑板键对应的值
AActor* TargetActor = Cast<AActor>(BlackboardComp->GetValueAsObject("TargetActor"));
if (TargetActor)
{
//获取了行为树组件的 AI 控制器 AAIController 对象
AAIController* MyAIController = OwnerComp.GetAIOwner();
if (ensure(MyAIController))
{
//获取该 AI 控制器的控制的角色 APawn 对象
APawn* AIPawn = MyAIController->GetPawn();
if (ensure(AIPawn))
{
//计算了TargetActor和AI角色的距离
float DistanceTo = FVector::Distance(TargetActor->GetActorLocation(), AIPawn->GetActorLocation());
//根据距离是否小于1000来设置一个名为 AttackRangeKey 的黑板键对应的布尔值
bool bWithinRange = DistanceTo < 1000.0f;
bool bHasLOS = false;
if (bWithinRange)
{
bHasLOS = MyAIController->LineOfSightTo(TargetActor);
}
BlackboardComp->SetValueAsBool(AttackRangeKey.SelectedKeyName, (bWithinRange && bHasLOS));
}
}
}
}
}
注:这里编译前需要在模块构建脚本ActionRoguelike.Build.cs中添加对 “GameplayTasks” 模块的依赖。
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "AIModule", "GameplayTasks" });
3.2 修改行为树
修改之前的行为树,Root根节点连接一个Selector节点,Selector节点是按顺序评估其子节点,并选择第一个返回成功 (Success) 或运行 (Running) 状态的子节点进行执行。如果子节点返回失败 (Failure) 状态,则继续评估下一个子节点。并同时调用上述定义的行为树节点CheckAttackRange获取WithinAttackRange的值。
Observer Aborts(观察者中止):是一种特殊的中止条件,用于控制行为树节点的执行。当观察者的条件满足时,Observer Aborts(Self) 模式下的节点将立即中止自身的执行,不再继续执行下面的子节点。(具体内容见总结部分)
当WithinAttackRange为真时继续执行,为假时终止。
最终效果图如下:
4、总结
4.1 装饰器/黑板节点
通知观察者(Notify Observer)
- 结果改变时(On Result Change):仅在条件改变时进行重新计算。
- 值改变时(On Value Change):仅在观察到的黑板键改变时进行重新计算。
观察者中止(Observer Aborts)
- 无(None):不中止执行。
- 自身(Self):中止此节点自身和在其下运行的所有子树。
- 低优先级(Lower Priority):中止此节点自身和在其下运行的所有子树。
- 两者(Both):中止此节点自身和在其下运行的所有子树,以及此节点右侧的所有节点。
黑板键(Blackboard Key):装饰器将运行的黑板键。
键查询(Key Query)
- 已经设置(Is Set):数值是否已设置?不为空或不为默认值,则条件节点返回 true;否则,返回 false
- 尚未设置(Is Not Set):数值是否尚未设置?为空或为默认值,则条件节点返回 true;否则,返回 false
节点名称(Node Name):节点应该在行为树图表中显示的名称。