11月18日 虚幻争霸小兵缺少动画蓝图,让AI动起来与射击,无法解析的外部符号

昨天和同学吃饭去了,没来得及做完ai

修复金币贴图

金币没材质是因为贴图错误,在材质内将材质重新添加即可

11月18日 虚幻争霸小兵缺少动画蓝图,让AI动起来与射击,无法解析的外部符号_第1张图片

虚幻争霸小兵缺少动画蓝图

GitHub - tomlooman/ActionRoguelike: Third-person Action Roguelike made in Unreal Engine C++. Project for Unreal Engine Pro C++ Course & Stanford University (CS193U)

在作者的github链接内单独下载MinionRanged_AnimBP.uasset这个文件即可

制作AI

创建AI

添加charaer的类命名为SAICharaer

添加AI控制器类SAIController

在Controller内添加

protected: UPROPERTY(EditDefaultsOnly,Category="AI") UBehaviorTree* BehaviorTree; virtual void BeginPlay() override; };

回到UE4,添加NavMeshBoundsVolume并且在Show里将Nav打开

11月18日 虚幻争霸小兵缺少动画蓝图,让AI动起来与射击,无法解析的外部符号_第2张图片

新建一个行为树

11月18日 虚幻争霸小兵缺少动画蓝图,让AI动起来与射击,无法解析的外部符号_第3张图片

11月18日 虚幻争霸小兵缺少动画蓝图,让AI动起来与射击,无法解析的外部符号_第4张图片

在BB内添加

11月18日 虚幻争霸小兵缺少动画蓝图,让AI动起来与射击,无法解析的外部符号_第5张图片

在BT内添加

11月18日 虚幻争霸小兵缺少动画蓝图,让AI动起来与射击,无法解析的外部符号_第6张图片

然后创建我们自己的控制器

11月18日 虚幻争霸小兵缺少动画蓝图,让AI动起来与射击,无法解析的外部符号_第7张图片

在控制器内添加我们的黑板树

在创建的小兵人物内添加Ai

11月18日 虚幻争霸小兵缺少动画蓝图,让AI动起来与射击,无法解析的外部符号_第8张图片

让Ai移动到我们的位置旁边

在黑版这里添加变量TargetActor,类型为Actor

11月18日 虚幻争霸小兵缺少动画蓝图,让AI动起来与射击,无法解析的外部符号_第9张图片

##Pawn发生了报错,隐藏了类声明

11月18日 虚幻争霸小兵缺少动画蓝图,让AI动起来与射击,无法解析的外部符号_第10张图片

已经解决,错误是发生了命名冲突

11月18日 虚幻争霸小兵缺少动画蓝图,让AI动起来与射击,无法解析的外部符号_第11张图片

重新编译并修改行为树

11月18日 虚幻争霸小兵缺少动画蓝图,让AI动起来与射击,无法解析的外部符号_第12张图片

让AI判断范围内是否有敌人

创建BT

11月18日 虚幻争霸小兵缺少动画蓝图,让AI动起来与射击,无法解析的外部符号_第13张图片

新增TickNode变量

##以下是一些知识点

如何找到需要的函数:

鼠标放在父类Public函数上,按Ctrl+鼠标左键即可进入父类内

11月18日 虚幻争霸小兵缺少动画蓝图,让AI动起来与射击,无法解析的外部符号_第14张图片

11月18日 虚幻争霸小兵缺少动画蓝图,让AI动起来与射击,无法解析的外部符号_第15张图片

在这里找到我们需要的

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

##报错:无法解析的外部符号

无法解析的外部符号 "public: virtual void __cdecl IGameplayTaskOwnerInterface::OnGameplayTaskActivated(class UGameplayTask &)" (?OnGameplayTaskActivated@IGameplayTaskOwnerInterface@@UEAAXAEAVUGameplayTask@@@Z)

这里可以看见是无法解析最外面的IGameplayTaskOwnerInterface这个函数

将头部I去掉,将GameplayTaskOwnerInterface放在Rider的全局搜索(Ctrl+Shift+F)内搜索

11月18日 虚幻争霸小兵缺少动画蓝图,让AI动起来与射击,无法解析的外部符号_第16张图片

在Project里选择UE5,拉到最下面找到UE5.vcxproj.filters这个路径

模组为GameplayTasks

在"项目名称".Build.cs的

PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });

这里添加GameplayTasks

11月18日 虚幻争霸小兵缺少动画蓝图,让AI动起来与射击,无法解析的外部符号_第17张图片

(可选)在这里添加"AIModule",因为我们的项目内用到了AI模组

PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" ,"AIModule", "GameplayTasks" });

修改BT函数

.h文件

protected: //创建一个选择键 UPROPERTY(EditAnywhere,Category="AI") FBlackboardKeySelector AttackRangeKey; virtual void TickNode(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds) override;

.cpp文件

void USBTService_CheckAtteckRange::TickNode(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds) { Super::TickNode(OwnerComp, NodeMemory, DeltaSeconds); //检查AI角色到玩家操控角色的距离 //这一步是确认这个角色是否拥有BlackboardComp UBlackboardComponent* BlackboardComp = OwnerComp.GetBlackboardComponent(); if(BlackboardComp) { //通过TargetActor变量获取到角色的Actor AActor* TargetActor = Cast(BlackboardComp->GetValueAsObject("TargetActor")); if(TargetActor) { //获取到角色Actor后从OwnerComp获得AI控制器 AAIController* MyController = OwnerComp.GetAIOwner(); if(ensure(MyController)) { //从AI控制器获取到AI的Pawn APawn* AIPawn = MyController->GetPawn(); if(ensure(AIPawn)) { //计算角色的位置和AI的位置 float DistanceTo = FVector::Distance(TargetActor->GetActorLocation() , AIPawn->GetActorLocation()); //当距离小于2000时判断为ture bool bWithinRange = DistanceTo < 2000.0f; //将bool返回给黑板 BlackboardComp->SetValueAsBool(AttackRangeKey.SelectedKeyName, bWithinRange); } } } } }

重新编译

在黑板内添加一个bool

11月18日 虚幻争霸小兵缺少动画蓝图,让AI动起来与射击,无法解析的外部符号_第18张图片

在行为树的序列这里添加我们自定义的服务

11月18日 虚幻争霸小兵缺少动画蓝图,让AI动起来与射击,无法解析的外部符号_第19张图片

在右边选择刚刚在黑板创建的AttackRange

11月18日 虚幻争霸小兵缺少动画蓝图,让AI动起来与射击,无法解析的外部符号_第20张图片

Interbal的意思是固定时间是0.5秒,Random的是在固定时间+0.1或者-0.1的范围内随机取值范围

11月18日 虚幻争霸小兵缺少动画蓝图,让AI动起来与射击,无法解析的外部符号_第21张图片

在moveto右键添加一个黑板

11月18日 虚幻争霸小兵缺少动画蓝图,让AI动起来与射击,无法解析的外部符号_第22张图片

在黑板的属性里选择黑板创建的布尔

11月18日 虚幻争霸小兵缺少动画蓝图,让AI动起来与射击,无法解析的外部符号_第23张图片

Key Query的set意思是设置为ture,not set的意思是false

##中间效果图忘记截图了

然后简单的修改一下

11月18日 虚幻争霸小兵缺少动画蓝图,让AI动起来与射击,无法解析的外部符号_第24张图片

修改Observer aborts的意思是当布尔值发生改变的时候立即重新执行行为树

11月18日 虚幻争霸小兵缺少动画蓝图,让AI动起来与射击,无法解析的外部符号_第25张图片

这一段的逻辑是:

判断玩家和ai的距离是否是2000米内,如果是,那么AttackRange变化为Ture,Within attack range?这一段判断为否,ai逻辑树到wait.如果Within attack range?这一段判断为ture,ai逻辑树到Move To.

当玩家一开始在范围内也就是Within attack range?这个为false的时候,ai执行wait,当玩家离开范围的时候,Within attack range?判断bool值修改了立即执行Move To,直到再次为false执行wait

效果图

远离的时候:

11月18日 虚幻争霸小兵缺少动画蓝图,让AI动起来与射击,无法解析的外部符号_第26张图片

在范围内的时候

11月18日 虚幻争霸小兵缺少动画蓝图,让AI动起来与射击,无法解析的外部符号_第27张图片

添加AI能否看见角色

void USBTService_CheckAtteckRange::TickNode(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds) { Super::TickNode(OwnerComp, NodeMemory, DeltaSeconds); //检查AI角色到玩家操控角色的距离 //这一步是确认这个角色是否拥有BlackboardComp UBlackboardComponent* BlackboardComp = OwnerComp.GetBlackboardComponent(); if(BlackboardComp) { //通过TargetActor变量获取到角色的Actor AActor* TargetActor = Cast(BlackboardComp->GetValueAsObject("TargetActor")); if(TargetActor) { //获取到角色Actor后从OwnerComp获得AI控制器 AAIController* MyController = OwnerComp.GetAIOwner(); if(ensure(MyController)) { //从AI控制器获取到AI的Pawn APawn* AIPawn = MyController->GetPawn(); if(ensure(AIPawn)) { //计算角色的位置和AI的位置 float DistanceTo = FVector::Distance(TargetActor->GetActorLocation() , AIPawn->GetActorLocation()); //当距离小于2000时判断为ture bool bWithinRange = DistanceTo < 2000.0f; //判断是否能看见角色,默认为看不见 bool bHasLOS = false; if(bWithinRange) { bHasLOS = MyController->LineOfSightTo(TargetActor); } //返回给黑板 BlackboardComp->SetValueAsBool(AttackRangeKey.SelectedKeyName, bWithinRange && bHasLOS); } } } } }

11月18日 虚幻争霸小兵缺少动画蓝图,让AI动起来与射击,无法解析的外部符号_第28张图片

完成

你可能感兴趣的:(UE5,斯坦福C++,上课记录,ue4,虚幻,学习)