feat(enemy): EnemyAiBrain 支持配方资产/AiScript id 二选一解析
This commit is contained in:
@@ -57,6 +57,16 @@ namespace BaseGames.AI
|
|||||||
return script.GetOrBuildGraph();
|
return script.GetOrBuildGraph();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>取 id 对应的定义;不存在则显式抛错(根因暴露,不做兜底)。</summary>
|
||||||
|
public static IAiDefinition GetDefinition(string id)
|
||||||
|
{
|
||||||
|
EnsureBuilt();
|
||||||
|
if (!_byId.TryGetValue(id, out var script))
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"AiDefinitionRegistry: 未找到 AI 定义 id '{id}'。请确认存在 [AiDefinition(\"{id}\")] 的 AiScript 子类。");
|
||||||
|
return script;
|
||||||
|
}
|
||||||
|
|
||||||
public static IEnumerable<string> Ids
|
public static IEnumerable<string> Ids
|
||||||
{
|
{
|
||||||
get { EnsureBuilt(); return _byId.Keys; }
|
get { EnsureBuilt(); return _byId.Keys; }
|
||||||
|
|||||||
@@ -11,14 +11,17 @@ namespace BaseGames.Enemies
|
|||||||
[RequireComponent(typeof(EnemyBase))]
|
[RequireComponent(typeof(EnemyBase))]
|
||||||
public sealed class EnemyAiBrain : MonoBehaviour
|
public sealed class EnemyAiBrain : MonoBehaviour
|
||||||
{
|
{
|
||||||
[Tooltip("对应 [AiDefinition(id)] 的敌人 AI 定义 id,例如 E001")]
|
[Tooltip("配方路径(约 95% 的敌人):直接引用 AI 配方资产")]
|
||||||
|
[SerializeField] AiRecipeSO _recipe;
|
||||||
|
|
||||||
|
[Tooltip("定制路径(约 5% 的敌人):[AiDefinition(id)] 的 AiScript 子类 id。与配方二选一")]
|
||||||
[SerializeField] string _definitionId;
|
[SerializeField] string _definitionId;
|
||||||
|
|
||||||
EnemyBase _enemy;
|
EnemyBase _enemy;
|
||||||
EnemyBrainContext _context;
|
EnemyBrainContext _context;
|
||||||
AiRuntime _runtime;
|
AiRuntime _runtime;
|
||||||
|
|
||||||
public string DefinitionId => _definitionId;
|
public string DefinitionId => _recipe != null ? _recipe.name : _definitionId;
|
||||||
public string CurrentStateName => _runtime != null ? _runtime.CurrentStateName : "(none)";
|
public string CurrentStateName => _runtime != null ? _runtime.CurrentStateName : "(none)";
|
||||||
public bool IsSuspended => _runtime != null && _runtime.IsSuspended;
|
public bool IsSuspended => _runtime != null && _runtime.IsSuspended;
|
||||||
public AiRuntime Runtime => _runtime;
|
public AiRuntime Runtime => _runtime;
|
||||||
@@ -26,10 +29,15 @@ namespace BaseGames.Enemies
|
|||||||
void Awake()
|
void Awake()
|
||||||
{
|
{
|
||||||
_enemy = GetComponent<EnemyBase>();
|
_enemy = GetComponent<EnemyBase>();
|
||||||
if (string.IsNullOrEmpty(_definitionId))
|
|
||||||
|
bool hasRecipe = _recipe != null;
|
||||||
|
bool hasId = !string.IsNullOrEmpty(_definitionId);
|
||||||
|
if (hasRecipe == hasId) // 都配了 或 都没配
|
||||||
{
|
{
|
||||||
// 根因暴露:漏配 id 直接报错,不静默兜底。
|
// 根因暴露:配置歧义 / 漏配直接报错,不静默兜底。
|
||||||
Debug.LogError($"EnemyAiBrain 未配置 _definitionId:{name}", this);
|
Debug.LogError(
|
||||||
|
$"EnemyAiBrain 必须且只能配置一项:_recipe(配方资产)或 _definitionId(AiScript id)。当前 recipe={(hasRecipe ? _recipe.name : "空")}, id='{_definitionId}':{name}",
|
||||||
|
this);
|
||||||
enabled = false;
|
enabled = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -38,7 +46,10 @@ namespace BaseGames.Enemies
|
|||||||
// 再触发入口状态 OnEnter(其会声明 locomotion 意图)。所有 Awake 先于任一 Start 执行。
|
// 再触发入口状态 OnEnter(其会声明 locomotion 意图)。所有 Awake 先于任一 Start 执行。
|
||||||
void Start()
|
void Start()
|
||||||
{
|
{
|
||||||
var graph = AiDefinitionRegistry.GetGraph(_definitionId); // 不存在则抛异常
|
IAiDefinition definition = _recipe != null
|
||||||
|
? (IAiDefinition)_recipe
|
||||||
|
: AiDefinitionRegistry.GetDefinition(_definitionId); // 不存在则抛异常
|
||||||
|
var graph = definition.GetOrBuildGraph();
|
||||||
_context = new EnemyBrainContext(_enemy);
|
_context = new EnemyBrainContext(_enemy);
|
||||||
_runtime = new AiRuntime(graph, _context);
|
_runtime = new AiRuntime(graph, _context);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user