feat(ai): BrainGraph 核心程序集 + AiSignal + Blackboard(可自省)

This commit is contained in:
2026-07-03 13:56:11 +08:00
parent 2339b5cd87
commit db5bd019f8
11 changed files with 177 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 32a983dffef38384280c2ff4b56d7e2a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,51 @@
using NUnit.Framework;
using UnityEngine;
using BaseGames.AI;
namespace BaseGames.Tests.EditMode.AI
{
public class BlackboardTests
{
[Test]
public void SetThenGet_ReturnsValue()
{
var bb = new Blackboard();
bb.Set("lastKnown", new Vector2(3f, 4f));
Assert.AreEqual(new Vector2(3f, 4f), bb.Get<Vector2>("lastKnown"));
}
[Test]
public void Get_MissingKey_ReturnsDefault()
{
var bb = new Blackboard();
Assert.AreEqual(0f, bb.Get<float>("nope"));
}
[Test]
public void Keys_EnumeratesAllSetKeys()
{
var bb = new Blackboard();
bb.Set("a", 1);
bb.Set("b", 2);
CollectionAssert.AreEquivalent(new[] { "a", "b" }, bb.Keys);
}
[Test]
public void Clear_RemovesAll()
{
var bb = new Blackboard();
bb.Set("a", 1);
bb.Clear();
CollectionAssert.IsEmpty(bb.Keys);
}
[Test]
public void Snapshot_ReturnsKeyToStringMap_ForIntrospection()
{
var bb = new Blackboard();
bb.Set("hp", 0.5f);
var snap = bb.Snapshot();
Assert.AreEqual("0.5", snap["hp"]);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 54506ee78297ac6488bbaefbd5678546
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -5,6 +5,7 @@
"BaseGames.Combat.StatusEffects", "BaseGames.Combat.StatusEffects",
"BaseGames.Combat", "BaseGames.Combat",
"BaseGames.Core", "BaseGames.Core",
"BaseGames.AI",
"BaseGames.Core.Events", "BaseGames.Core.Events",
"BaseGames.Core.Save", "BaseGames.Core.Save",
"BaseGames.EventChain", "BaseGames.EventChain",
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1b4185e382aa90040a5f79472a37c424
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+15
View File
@@ -0,0 +1,15 @@
namespace BaseGames.AI
{
/// <summary>决策层的推送信号,用于事件驱动的状态转换(不靠轮询)。</summary>
public enum AiSignal
{
Damaged, // 受到伤害
Parried, // 被弹反
Staggered, // 进入硬直
KnockedUp, // 被击飞
Died, // 死亡
PlayerSpotted,// 首次侦测到玩家
AbilityEnded, // 当前能力协程结束/被打断
PhaseChanged // Boss 阶段变更
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 58a00d0c7341ac44187efe5e28ebf2c6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,16 @@
{
"name": "BaseGames.AI",
"rootNamespace": "BaseGames.AI",
"references": [
"BaseGames.Core"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 024d079978973a44ebe11fb10cc081ad
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+38
View File
@@ -0,0 +1,38 @@
using System.Collections.Generic;
using System.Globalization;
namespace BaseGames.AI
{
/// <summary>
/// 具名、可枚举的 AI 临时值容器(每敌人实例一份)。
/// 保留"具名"是为了让调试器/MCP 能通用枚举当前值。
/// </summary>
public sealed class Blackboard
{
readonly Dictionary<string, object> _values = new Dictionary<string, object>();
public void Set<T>(string key, T value) => _values[key] = value;
public T Get<T>(string key)
=> _values.TryGetValue(key, out var v) && v is T t ? t : default;
public bool Has(string key) => _values.ContainsKey(key);
public IReadOnlyCollection<string> Keys => _values.Keys;
public void Clear() => _values.Clear();
/// <summary>供调试器/MCP 自省:key → 值的字符串表示。</summary>
public Dictionary<string, string> Snapshot()
{
var result = new Dictionary<string, string>(_values.Count);
foreach (var kv in _values)
{
result[kv.Key] = kv.Value is System.IFormattable f
? f.ToString(null, CultureInfo.InvariantCulture)
: kv.Value?.ToString() ?? "null";
}
return result;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6a494477153510d4e8a976d437aac8b6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: