AI选敌:不要在排序比较器里寻路

自动关联目录:AI选敌:不要在排序比较器里寻路

核心判断:候选排序应比较已经计算好的分数。把同步寻路和全场 AI 枚举放进比较或候选循环,会把一次“选最近目标”放大成不可控的 DS 尖峰。

一、业务冲突:既要选得合理,又不能让所有怪同时选同一人

多人 PVE 通常要按距离、可达性、玩家状态、上一个目标和已被追击数量选敌。欧氏距离便宜但可能隔墙;路径距离更准确却昂贵;限制追击数能改善体验,却需要共享全局占用信息。

二、实际实现:规则完整,计算位置却不对

现有 BT Task 先过滤失效目标,再可选地按距离排序,支持最小/最大范围、排除 Tag、排除状态、避开上一目标和每玩家最大追击数。这些业务规则是完整的。

问题在于启用路径距离后,排序比较器每比较两个候选就同步调用两次 GetPathLength,且没有处理查询失败;选定候选前,又逐个调用“当前多少 AI 正在追此玩家”,其内部会 GetAllActorsOfClass 枚举全场 NPC。若候选数为 C、AI 数为 M,一次重选近似包含 O(C log C) 次路径查询和 O(C*M) 次扫描,还会因 AI 执行顺序产生先到先得偏差。

flowchart LR
    P[Perception candidates] --> C[Cheap filters]
    C --> K[Euclidean Top-K]
    K --> Q[Budgeted reachability queries]
    Q --> S[Cached score snapshot]
    S --> L[Target slot lease]
    L --> B[Commit Blackboard target]

三、值得保留:过滤条件数据化,范围使用平方距离

把排除状态、Tag、上一目标与追击上限暴露成任务配置,便于复用;范围过滤使用 DistSquared 避免开方,候选用弱引用并在使用前验证,也都值得保留。设置目标时同时更新 Blackboard 和角色上的 ChaseTarget,使后续规则能观察选择结果,方向同样正确。

四、结构性缺陷:排序阶段重复做昂贵且可能失败的工作

比较器应满足稳定、廉价、无副作用。路径查询既昂贵又可能因动态 NavMesh 返回失败值;失败结果若保留默认长度,反而可能被排到最前。全场枚举追击者没有缓存,也无法表达“本轮已经预留但尚未提交”的槽位。多个 AI 同帧重选时,即使游戏线程串行,也会形成顺序偏置和路径查询洪峰。

五、目标设计:共享 Assignment Service 统一分配预算

服务维护 TargetId -> ActiveLeaseCount,AI 注册/注销和换目标时增量更新,不再枚举世界。选择先做阵营、状态、直线距离等廉价过滤,只对 Top-K 发起限额可达性查询;结果缓存键必须包含 NavRevision、AgentType 和起终点网格。异步结果携带 SelectionRevision,过期即丢弃。

void RequestAssignment(AIHandle ai, CandidateSnapshot candidates)
{
    SelectionRevision rev = ++ai.selectionRevision;
    auto top = CheapScore(candidates).TakeTopK(pathBudgetPerAI);
    PathBudget.Enqueue(ai, rev, top, [=](PathScores scores) {
        if (!ai.IsCurrent() || ai.selectionRevision != rev) return;
        TargetHandle target = PickWithAvailableSlot(scores, SlotLedger);
        TargetLease lease = SlotLedger.TryReserve(ai, target);
        if (lease) CommitTarget(ai, lease, rev);
    });
}

六、决策规则:准确性必须按阶段购买

阶段允许的计算目标
候选召回Perception/空间索引不漏掉附近可能目标
廉价过滤阵营、存活、Tag、平方距离快速缩小工作集
Top-K 粗排距离、仇恨、任务权重只保留少量高价值候选
可达性限额路径测试、缓存不在排序比较器中重复执行
槽位仲裁共享计数与 Lease避免全场扫描和超卖
提交Revision 校验拒绝迟到异步结果

这里的核心优化不是把某个查询改快,而是把每只 AI 私有的重复计算改成共享、可预算、可失效的分配服务。