[!IMPORTANT] 核心理念: AI 不应该只是“处于”某种状态 (State),而应该根据当前环境评估所有可能行为的“效用” (Utility),并选择最优解。
Utility AI (效用 AI) 是一种基于评分 (Scoring) 的决策架构。与传统的 FSM (有限状态机) 或行为树相比,它在处理模糊逻辑和多目标权衡时表现出极高的涌现性 (Emergent Behavior)。
IF (Health < 30%) THEN Transition(Retreat)Score(Retreat) = Curve(Health) * Curve(EnemyThreat) * Curve(CoverDistance)Utility AI 的核心是将所有“考虑因素” (Considerations) 归一化为 0.0 到 1.0 之间的浮点数。
输入通常是原始游戏数据 (距离、血量、时间),输出是 效用 (Utility)。我们需要通过曲线来映射这种关系。
| 曲线类型 | 形状描述 | 典型应用 |
|---|---|---|
| Linear (线性) | / 或 \ |
简单的比例关系。如:金币越多越富有。 |
| Quadratic (二次) | J 型 |
极端值才重要。如:只有极度靠近悬崖时,恐惧感才急剧上升。 |
| Logistic (S形) | S 型 |
阈值敏感。如:血量在 40%-60% 之间时,治疗欲望从低急剧变高。 |
| Logit (对数) | 倒 J 型 |
边际递减。如:前 100 金币很珍贵,之后的一百万金币效用递减。 |
如何将多个因素组合成一个最终分数?
在 Unity 中,我们可以使用 ScriptableObject 构建高度模块化的 Utility 系统。
ContextAnimationCurve (响应曲线)0-1 的 floatConsideration。Consideration 的乘积。Action。Action。// 1. 考虑因素基类
public abstract class Consideration : ScriptableObject {
public AnimationCurve responseCurve;
public abstract float Score(AIContext context);
protected float Map(float rawValue) {
return responseCurve.Evaluate(Mathf.Clamp01(rawValue));
}
}
// 2. 具体实现:我的血量
[CreateAssetMenu(menuName = "AI/Considerations/My Health")]
public class HealthConsideration : Consideration {
public override float Score(AIContext context) {
// 归一化血量
float rawHealth = context.self.currentHealth / context.self.maxHealth;
// 如果曲线是反向的(血越少分越高),在编辑器里画一条从左上(0,1)到右下(1,0)的线
return Map(rawHealth);
}
}
// 3. 行为定义
[CreateAssetMenu(menuName = "AI/Action")]
public class UtilityAction : ScriptableObject {
public string actionName;
public List<Consideration> considerations;
public float Evaluate(AIContext context) {
float score = 1f;
foreach (var con in considerations) {
score *= con.Score(context);
if (score == 0) return 0; // 剪枝优化
}
return score;
}
}
为了防止 AI 在两个分数相近的行为之间疯狂切换 (抖动),需要引入“惯性”。
Utility AI 负责决策 (Decision Making),FSM/行为树负责执行 (Execution)。