文章目录

  • 移动流程概述
  • 调整方向
  • 关于路径
  • UPathFollowingComponent
    • 收到移动请求
    • 更新路径
    • 执行移动

移动流程概述

拉起一个UAITask_MoveTo,设置好InMoveRequest后,调用UAITask_MoveTo::PerformMove,内部转到AAIController::MoveTo
判断是否到达,如果没有到达,就转到AAIController::RequestMove开始请求移动,内部创建一条路径后,传给UPathFollowingComponent::RequestMove,由UPathFollowingComponent完成一条路径的移动。
RequestMove调用SetMoveSegment处理出移动线段的信息。最后在Tick内通过这些线段完成移动。

void UGameplayTask::PerformActivation()
void UAITask_MoveTo::Activate()
void UAITask_MoveTo::ConditionalPerformMove()
void UAITask_MoveTo::PerformMove()
FPathFollowingRequestResult AAIController::MoveTo(const FAIMoveRequest& MoveRequest, FNavPathSharedPtr* OutPath)
FAIRequestID AAIController::RequestMove(const FAIMoveRequest& MoveRequest, FNavPathSharedPtr Path)
FAIRequestID UPathFollowingComponent::RequestMove(const FAIMoveRequest& RequestData, FNavPathSharedPtr InPath)Path = InPath;
void UPathFollowingComponent::SetMoveSegment(int32 SegmentStartIndex)void UPathFollowingComponent::UpdateMoveFocus()FVector UPathFollowingComponent::GetMoveFocus(bool bAllowStrafe) constvoid AAIController::SetFocalPoint(FVector NewFocus, EAIFocusPriority::Type InPriority)

在Tick内,调用FollowPathSegment,借助移动组件来完成Pawn的移动

void UPathFollowingComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction)
void UPathFollowingComponent::FollowPathSegment(float DeltaTime)MovementComp->RequestPathMove(CurrentMoveInput);MovementComp->RequestDirectMove(MoveVelocity, bNotFollowingLastSegment);

如果使用了UCrowdFollowingComponent,则调用链则是:

void UCrowdManager::Tick(float DeltaTime)
void UCrowdManager::ApplyVelocity(UCrowdFollowingComponent* AgentComponent, int32 AgentIndex) const
void UCrowdFollowingComponent::ApplyCrowdAgentVelocity(const FVector& NewVelocity, const FVector& DestPathCorner, bool bTraversingLink, bool bIsNearEndOfPath)MovementComp->RequestPathMove(CurrentMoveInput);MovementComp->RequestDirectMove(MoveVelocity, bNotFollowingLastSegment);

调整方向

在过程中,会持续调用UpdateMoveFocus,进行任务朝向的设置

void UPathFollowingComponent::UpdateMoveFocus()
void AAIController::SetFocalPoint(FVector NewFocus, EAIFocusPriority::Type InPriority)

AAIController在Tick时进行旋转

void AAIController::Tick(float DeltaTime)
void AAIController::UpdateControlRotation(float DeltaTime, bool bUpdatePawn)

关于路径

初始路径在AAIController::MoveTo内确定,调用了找路径函数:

FPathFollowingRequestResult AAIController::MoveTo(const FAIMoveRequest& MoveRequest, FNavPathSharedPtr* OutPath)void AAIController::FindPathForMoveRequest(const FAIMoveRequest& MoveRequest, FPathFindingQuery& Query, FNavPathSharedPtr& OutPath) constUNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(GetWorld());if (NavSys){FPathFindingResult PathResult = NavSys->FindPathSync(Query);

找到路径后调用AAIController::RequestMove,转到UPathFollowingComponent::RequestMove

const FAIRequestID RequestID = Path.IsValid() ? RequestMove(MoveRequest, Path) : FAIRequestID::InvalidRequest;PathFollowingComponent->RequestMove(MoveRequest, Path);

UPathFollowingComponent使用这个路径,完成实际移动逻辑的控制

UPathFollowingComponent

收到移动请求

FAIRequestID UPathFollowingComponent::RequestMove(const FAIMoveRequest& RequestData, FNavPathSharedPtr InPath) // 那条线段可能开始减速UpdateDecelerationData();// 细节优化,前面两个点选哪个作为起点const uint32 CurrentSegment = DetermineStartingPathPoint(InPath.Get());// 设置线段信息为起点SetMoveSegment(CurrentSegment);

设置线段信息

void UPathFollowingComponent::SetMoveSegment(int32 SegmentStartIndex)// 获取起点和终点const FVector SegmentStart = *PathInstance->GetPathPointLocation(MoveSegmentStartIndex);FVector SegmentEnd = *CurrentDestination;// 移动方向MoveSegmentDirection = (SegmentEnd - SegmentStart).GetSafeNormal();// 判断是否使用了NavLinkif (PathPt0.CustomLinkId){UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(GetWorld());INavLinkCustomInterface* CustomNavLink = NavSys->GetCustomLink(PathPt0.CustomLinkId);StartUsingCustomLink(CustomNavLink, SegmentEnd);}// 跟新移动焦点UpdateMoveFocus();

跟新移动焦点

void UPathFollowingComponent::UpdateMoveFocus()// 计算焦点const FVector MoveFocus = GetMoveFocus(AIOwner->bAllowStrafe);if (bAllowStrafe && DestinationActor.IsValid()){MoveFocus = DestinationActor->GetActorLocation();}else{const FVector CurrentMoveDirection = GetCurrentDirection();// 会往前挪5米MoveFocus = *CurrentDestination + (CurrentMoveDirection * FAIConfig::Navigation::FocalPointDistance);}// 设置到AIController上AIOwner->SetFocalPoint(MoveFocus, EAIFocusPriority::Move);

更新路径

void UPathFollowingComponent::UpdatePathSegment()//路径失效的处理if (!Path->IsValid())// 到达:碰撞if (bCollidedWithGoal)// 到达:到达检查可接受半径的线段else if (MoveSegmentEndIndex > PreciseAcceptanceRadiusCheckStartNodeIndex && HasReachedDestination(CurrentLocation))// 最后一段,且是MoveToGoal,直接走过去else if (bFollowingLastSegment && bMoveToGoalOnLastSegment && bLastPathChunk)CurrentDestination.Set(NULL, GoalLocation);UpdateMoveFocus();// 到达else if (HasReachedCurrentTarget(CurrentLocation))// 阻塞检测const bool bHasNewSample = UpdateBlockDetection();if (bHasNewSample && IsBlocked())OnPathFinished(EPathFollowingResult::Blocked, FPathFollowingResultFlags::None);

执行移动

void UPathFollowingComponent::FollowPathSegment(float DeltaTime)// 判断是否需要减速const bool bAccelerationBased = MovementComp->UseAccelerationForPathFollowing();if (bAccelerationBased)if (MoveSegmentStartIndex >= DecelerationSegmentIndex)         if (bShouldDecelerate)const float SpeedPct = FMath::Clamp(FMath::Sqrt(DistToEndSq) / CachedBrakingDistance, 0.0f, 1.0f);CurrentMoveInput *= SpeedPct;MovementComp->RequestPathMove(CurrentMoveInput);// 直接移动FVector MoveVelocity = (CurrentTarget - CurrentLocation) / DeltaTime;PostProcessMove.ExecuteIfBound(this, MoveVelocity);MovementComp->RequestDirectMove(MoveVelocity, bNotFollowingLastSegment);

UE4:AI‘s MoveTo——代码分析相关推荐

  1. 海思AI芯片(Hi3519A/3559A)方案学习(十七)开发板上运行yolo3模型的代码分析

    前言 前面的博客系列 已经介绍了如何将caffemodel转换成wk文件,如何将jpg文件转成bgr格式数据以及如何在PC上仿真模型推理等,基于这些基础,本文来结合代码分析如何在板子上推理yolov3 ...

  2. AI 生成的代码可信吗?编写的代码有 Bug 吗?

    编译 | 禾木木 出品 | AI科技大本营(ID:rgznai100) 即使是帮助开发人员编写软件的工具也会产生类似的bug. 目前,大部分的软件开发人员会让 AI 帮助开发者们编写代码,但是开发人员 ...

  3. 控制元素显示和隐藏的方式及区别、内容溢出处理(区域滚动)、透明性、字体图标、常见字体、自定义字体设计、网站图标、CSS代码分析

    元素的显示与隐藏: 常见控制元素的显示和隐藏的属性有display.visibility.overflow,需要清楚的理解三者之间的区别. display显示: 当值为none时为销毁对象,不保留原位 ...

  4. 管理Discuz!代码分析的收集整理

    管理Discuz!代码分析的收集整理 1.后台结构 @�L^SD+k#G0 后台首页提供了常用操作:用户(组)编辑,论坛基本备份等. k XS7]+mB8H0 2.PHPChina 开源社区门户&qu ...

  5. Java调用百度AI实现人体属性分析

    Java调用百度AI实现人体属性分析 好久没有更新了...闲来无事发一下模仿百度AI的人体属性分析. 百度AI效果图如下: 本人开发效果图如下: 界面大家可以忽略........下面讲讲代码实现 1. ...

  6. 未来属于无代码分析:每个人都能成为数据科学家

    全文共1769字,预计学习时长6分钟 图源:unsplash 互联网诞生早期,创建网站是一门高端技术活.而现在,Wordpress这样的无代码工具让每个人都能迅速地创建一个网站.如今已有超50亿的网站 ...

  7. RPA与AI、低代码、BPM既同场竞技,又融合共生

    <中智观察>第1714篇推送 作者:赵满满 编辑:益韩 编审:杨小天 头图来源:RPA中国/达观数据 如今,越来越多企业正在投资CRM,以便顺利运营并"取悦"自己的客户 ...

  8. 无代码六月大事件|2022无代码探索者大会即将召开;AI增强型无代码工具推出...

    栏目导读:无代码资讯栏目从全球视角出发,带您了解无代码相关最新资讯. TOP 3 大事件 1.Neptune Software 在其 SAP 友好型开发平台中添加 AI 增强型无代码工具 6月23日, ...

  9. AI低代码平台遍地开花,AI对于低代码到底是帮手还是对手?

    AI对于低代码平台到底是帮手还是对手? 近日,CSDN举办的新程序员大会中,对于AI在代码领域的能力进行了5个层级的定义.并且进行了大量的测试,发现当下的AI已经可以去到初级程序员了,而更为强大的GP ...

最新文章

  1. Vue 增加动态路由功能 【在原有系统上增加】
  2. windows10 查看 nvidia driver cuda 版本
  3. 八天学会MongoDB:第三天 细说高级操作
  4. 【收藏】OGC标准服务 WMS WCS WFS WPS
  5. go语言json解析的坑 注意事项
  6. 发现在创建云服务器ecs实例的磁盘快照时_玩转ECS第7讲|ECS数据保护-数据备份新特性与最佳实践...
  7. Android 系统(138 )---Mtk平台 Android 打包解包*.img ,修改system.img 参数
  8. java使用内部类的好处及其初始化
  9. Tensor:索引操作
  10. div contenteditable 富文本字数限制_知网查重是如何统计字数的?
  11. Spring中定义Bean的6种方式(声明式+编程式)
  12. win7计算机里没有网络图标,Win7网络图标不见了?找回网络图标的方法
  13. 移动安全工具:fastboot
  14. 获取非行内样式的兼容
  15. 上海交通大学学生生存手册
  16. 羚数智能入选 IDC关于中国制造执行系统(MES)的市场2021年度份额报告
  17. JavaWeb_07_Ajax
  18. Spring源码阅读笔记(一):整体架构与核心技术
  19. Codasip通过收购Cerberus增强RISC-V处理器设计的安全性
  20. 高NA镜头系统中的高级PSF计算

热门文章

  1. 51单片机PCB实物DCDC可调负电源负压+12V输入-2.5V~-9V输出500MA电流
  2. 【常见电路】稳压电路以及元器件的选型
  3. Django 上传文件出现 OSError Permission denied的解决方法
  4. 车载通信——LIN总线
  5. 哪个 DB2 9.7 发行版适合您?
  6. springboot消费kafka设置topics 以及 groupId
  7. 【算法学习】最小生成树
  8. Java调用Python:实现两大语言的无缝对接
  9. [转]Java中文处理学习笔记——Hello Unicode
  10. HTMlEncode和HTMLDecode、UrlEncode和 UrlDecode 定义和用法