UE AI Perception的Sense解析

UAISense的辅助结构

UAISenseEvent事件结构

  • UAISenseEvent本身更多的是充当类似于接口的功能,最关键的函数定义是GetSenseID,这个函数交由继承的子类负责实现,而子类会通过UAISense::GetSenseID(UAISense_XXX)获取全局唯一的实例SenseID,GetSenseID函数最终会调用GetDefaultObject里的SenseID,GetSenseID获取到的ID可以作为获取实例的索引,在感知系统中,通过传入的UAISenseEvent获取ID,再遍历Sense调用指定Sense的事件注册函数,转到Sense中时,会尝试转换为自身定义的事件类型,添加到事件结构里,等待Update循环遍历处理
  • 从整个执行的流程来看UAISenseEvent主要为了完成向UAISense投递数据,无论是从Sense本身,还是从感知系统,最终会把事件投递到Sense里的事件数组里,比如UAISense_HearingTArray<FAINoiseEvent> NoiseEventsUAISense_Damage里的TArray<FAIDamageEvent> RegisteredEvents
  • 感知系统里维护了三个事件相关的模板函数OnEvent``OnEventBatch``static OnEvent以及两个蓝图可调用的两个函数ReportEventstatic ReportPerceptionEvent,这些函数最终会索引到指定的Sense实例,转调Sense里的注册事件函数,与感知系统相对应,Sense类定义的同义的函数。如果有注册事件的需求,那就可以实现UAISense基类里的RegisterWrappedEvent或者对应感知系统里的事件函数,接收事件并处理即可

UAISenseConfig辅助配置结构

  • UAISenseConfig本身为UAISense提供了调试颜色,过期遗忘控制变量,开始时启动,感知名缓存,获取感知ID方法等
  • 继承自UAISenseConfig的子类充当该Listener感知Sense的参数配置,通过这些配置完成一个实例Listener的定制化需求
  • 比较典型的配置是UAISenseConfig_Sight,视觉配置的参数在AIHelpers.h里的CheckIsTargetInSightCone函数调用中使用,而该函数正是在UAISenseConfig_SightUpdate函数中被调用

UAISense各种Sense具体实现

UAISense里为继承的子类完成了哪些内容并且不需要子类实现?

  • 基类实现关于Tick更新的机制,这些机制依赖于感知系统的Tick函数,并通过自身的ProgressTime函数处理计时问题
  • 实现了Listener变动处理的函数调用框架,这些Listener的函数都是被感知系统调用,进而把Listener的变动通知给具体的Sense实例
  • 同样,实现了操作刺激源Actor的函数框架及调用逻辑
  • 实现了对Sense操作的辅助函数,这些函数可以直接被使用并不需要被重写操作
  • 定义了变动通知的控制变量及函数获取方法

UAISense的那些东西需要子类实现?

  • 与框架定义相对应,子类要完成自身的Update函数功能,来持续的向Listener刷新数据
  • 需要完成具体的事件处理函数,无论时存储到自身的临时缓存结构里还是其他的一些处理,你会发现这些事件处理函数都很有用,当然,这些事件处理函数不是必须的,根据自身定义的Sense需求酌情处理
  • 需要处理来自于感知系统的Listener和Source数据,这些可参考其他的Sense实例
  • 参考UAISense的虚函数及感知系统对Sense的各种调用,或者已经实现的感知Sense都能达到目的

UAISenseConfig_TouchUAISense_Touch

  • FAITouchEvent很简单,定义了三个参数:触觉接受的对象Listener,触觉来源Actor,触觉传来的位置坐标
  • UAISense_Touch本身也很简单顶一个了一个RegisterEvent函数,被感知系统调用,定义了一个时间缓存数组TArray<FAITouchEvent> RegisteredEvents存放来自于感知系统的触觉事件
  • 重写的Update函数中对缓存的事件进行迭代,并查找触觉Sense里的Listener,调用RegisterStimulus函数发送刺激源消息给指定的Listener,然后清空事件数组,完成整个事件流程

UAISenseConfig_BlueprintUAISense_Blueprint

  • UAISenseConfig_Blueprint仅包含配置UAISense_Blueprint的属性及获取接口
  • UAISense_Blueprint为蓝图实现一种Sense提供的范本基类,事实上通过看这个类的实现函数就可以知道,定义一个自身的需要的Sense类需要那些内容:OnUpdate,OnListenerUpdated,OnListenerRegistered,OnListenerUnregistered,K2_OnNewPawn
  • UAISense_Blueprint整体上对UAISense必须要处理的问题的框架封装,然后转交给蓝图实现

FAITeamStimulusEventUAISense_Team

  • UAISense_Team是一个用来向其他同阵营成员通知刺激消息的Sense,本身功能非常简单,可以用来转发该AI接受到的刺激消息,比如受到攻击,听到有敌对成员靠近,进而告诉同阵营成员做出策略反应
  • UAISense_Team本身逻辑非常简单,添加了一个维护自身消息的结构数组,同时实现了接受事件的函数RegisterEvent以及维持消息循环迭代发送刺激消息的函数UpdateUpdate函数里循环迭代了Listener以及RegisteredEvents
  • FAITeamStimulusEvent里定义了TeamIdentifier,被通知的对象,要通知的成员,成员的缓存位置,有效通知范围用于校验是否被通知

UAISense_PredictionFAIPredictionEvent

UAISense_Prediction预测一个Actor指定时间段内的位置,这依赖于这个Actor实体的速度及Event中传递的TimeToPredict时间值,UAISense_Prediction本身代码非常简单,提取FAIPredictionEvent里的被预测对象计算时间位置并向请求对象发送刺激源消息

UAISense_DamageFAIDamageEvent

  • FAIDamageEvent:属性内容:伤害量,位置,击中位置,伤害来源(Actor),Tag标签
  • UAISense_Damage本身实现了RegisterEvent``RegisterWrappedEvent``ReportDamageEvent函数,用于注册消息,而更新函数里只是遍历查询,把刺激消息投递掉指定的Listener里

UAISense_Hearing,FAINoiseEventUAISenseConfig_Hearing

  • UAISenseConfig_Hearing里的配置参数:
    属性名定义 用途
    HearingRange 听力范围
    LoSHearingRange 声音丢失范围
    bUseLoSHearing 是否使用声源丢失参数,有运行时消耗提示
    DetectionByAffiliation 检测过滤,敌对关系过滤
  • FAINoiseEvent参数配置
    属性名定义 用途
    Age 过期标识变量
    NoiseLocation 噪声源产生位置
    Loudness 声源系数,作用到HearingRangeSq,进而影响听力范围
    MaxRange 最大的听力范围
    Instigator 噪声源Actor
    Tag 事件附加标签
    TeamIdentifier 团队阵营归属
  • UAISense_Hearing里也维护了事件缓存数组结构,在Update里进行迭代处理并重置,声音感知排除一些系数和衰减控制外,最核心的计算是感知位置与噪声位置的距离和配置里设置的听力范围的比较,在听力范围内的,会向Listener发送一个延迟刺激源消息

UAISense_SightUAISenseConfig_Sight

  • UAISenseConfig_Sight中的配置设置
    属性 用途
    SightRadius 可视化半径
    LoseSightRadius 失焦半径
    PeripheralVisionAngleDegress 外围可视角度,用于判定是否超过两侧视域
    DetectionByAffiliation 同盟阵营检测
    PointOfViewBackwardOffset 视锥体后移距离
    NearClippingRadius 近裁剪视锥体可见半径
    AutoSuccessRangeFromLastSeenLocation 上一次看到的位置是否自动返回可视结果
  • FAISightEvent事件属性
    属性 用途
    EventType 事件类型是收到可视状态,还是丢失可视状态
    SeenActor 被看到的对象
    Observer 观察者对象
    Age 留存时间
  • UAISense_Sight的实现
  1. 在AIHelpers文件里有一个函数CheckIsTargetInSightCone,该函数用来判断一个Actor是否处于观察者的视野内,而UAISense_Sight里的辅助结构FDigestedSightProperties正是为了辅助完成视野计算而存在的
  2. 知道了视觉判定,接下来需要知道的是,为了减少视觉循环迭代的性能消耗,把可视查询分为了两部分内容,TArray<FAISightQuery> SightQueriesOutOfRangeTArray<FAISightQuery> SightQueriesInRange,超出视觉范围和视觉范围内两部分,每次查询结构时,都是经过排序的有序数据结构结构,因此通过NextOutOfRangeIndex索引游标很轻松找到下一个超出范围的成员索引
  3. 可视化Sense要比其他的几个实现复杂,性能消耗也较高,如果对复杂的可视Sense不感冒,可以自己整一个简化版

一些关于写自定义Sense的注意事项

  • 如果你使用关于感知系统里的事件注册模板函数,那么一些定义必不可少,比如事件结构里的typedef class UAISense_XXX FSenseClass;缺了它,OnEvent的模板函数将无法识别你事件结构类型
  • 如果Update的返回值为SuspendNextUpdate,那意味着你需要手动添加事件驱动Sense更新,而且必须调用RequestImmediateUpdate函数使得刺激源消息得到更新发送
  • 怎样执行Update的更新策略这取决于你的需求,一般情况下Sense不会主动发起更新的,比如说Damage,Touch,Hearing这些都是惰性Sense,需要主动发起事件请求才会奏效,而这最核心的函数调用是RequestImmediateUpdate这会使Sense立即刷新,如果满足刺激源消息发送,则会向指定的Listener发送刺激源消息
  • StimulusStrength不要小于0,这会影响刺激源消息的激活状态判定及Age的过期计算,进而影响到刺激源消息的更新
  • Sense的事件,Listener的注册与更新,Source注册与取消实现都不是必须的,它取决于你的实现需求

猜你喜欢

转载自blog.csdn.net/u011047958/article/details/125674229
今日推荐