Files
zeling_v2/Assets/_Game/Scripts/Enemies/AIBrain/Recipes/PerceptionRecipeSO.cs
T

67 lines
3.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections.Generic;
using UnityEngine;
using BaseGames.AI;
using BaseGames.Core;
namespace BaseGames.Enemies
{
/// <summary>
/// 感知型 AI 配方:一个 SO 类型覆盖所有走「未发现 → 警觉 → 交战」规则的敌人。
/// 两个下拉各选一个模块即可,无需写代码。有独门机制的敌人改写 AiScript 子类。
/// </summary>
[CreateAssetMenu(menuName = "BaseGames/AI/感知型 AI 配方", fileName = "ENM_")]
public sealed class PerceptionRecipeSO : AiRecipeSO, IValidatable
{
[Tooltip("未发现层:玩家尚未被发现时的行为形状")]
[SerializeReference, SubclassSelector] IUnawareModule _unaware = new SinglePost();
[Tooltip("交战层:发现玩家之后怎么打")]
[SerializeReference, SubclassSelector] IEngagementModule _engagement = new RushEngagement();
// 死亡不做成第三层可插拔构件:死亡归物理层,骨架自己声明 Death 终态。
// PerformDeath 先 ForceState(Dead) 再发 Died 信号,此后 IsControllable 永久为假,
// 死亡链里的条件边永不被求值——所以死亡不能做成可插拔层。
protected override void Build(BrainBuilder b)
=> PerceptionSkeleton.Add(b, _unaware, _engagement);
/// <summary>装配模块。供脚手架向导与 EditMode 测试使用,运行时不应调用
/// (本资产是 flyweight,运行时改它会影响所有引用该配方的敌人)。</summary>
public void AssignModules(IUnawareModule unaware, IEngagementModule engagement)
{
_unaware = unaware; _engagement = engagement;
InvalidateGraph();
}
/// <summary>SOValidationRunner 自动扫描调用。结构性校验(模块是否选、建图是否成功)
/// 由配方负责;模块自身的配置(能力引用、冷却语义等)委托给模块的 Validate()——
/// 新增一种打法不需要回来改这里。</summary>
public IEnumerable<ValidationResult> Validate()
{
string who = name;
if (_unaware == null)
yield return ValidationResult.Error($"{who}:未选择未发现层模块。");
if (_engagement == null)
yield return ValidationResult.Error($"{who}:未选择交战层模块。");
if (_unaware == null || _engagement == null) yield break;
foreach (var r in _engagement.Validate())
yield return new ValidationResult(r.Severity, $"{who}{r.Message}");
// 结构性校验:直接试建一次图,模块与骨架的建图期守卫会把问题抛出来
// (能力漏配、Rest 不在 States、态未声明、跨模块状态名冲突等)。
// 这是最彻底的检查——凡是运行时会炸的,这里就会炸。
ValidationResult? buildFailure = null;
try { GetOrBuildGraph(); }
catch (System.Exception e)
{
buildFailure = ValidationResult.Error($"{who}:建图失败 —— {e.Message}");
}
finally { InvalidateGraph(); } // 校验期建的图不留给运行时
if (buildFailure.HasValue) yield return buildFailure.Value;
}
}
}