diff --git a/Assets/Tests/EditMode/AI.meta b/Assets/Tests/EditMode/AI.meta new file mode 100644 index 00000000..b743eca7 --- /dev/null +++ b/Assets/Tests/EditMode/AI.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 32a983dffef38384280c2ff4b56d7e2a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Tests/EditMode/AI/BlackboardTests.cs b/Assets/Tests/EditMode/AI/BlackboardTests.cs new file mode 100644 index 00000000..306945de --- /dev/null +++ b/Assets/Tests/EditMode/AI/BlackboardTests.cs @@ -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("lastKnown")); + } + + [Test] + public void Get_MissingKey_ReturnsDefault() + { + var bb = new Blackboard(); + Assert.AreEqual(0f, bb.Get("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"]); + } + } +} diff --git a/Assets/Tests/EditMode/AI/BlackboardTests.cs.meta b/Assets/Tests/EditMode/AI/BlackboardTests.cs.meta new file mode 100644 index 00000000..74faf7d2 --- /dev/null +++ b/Assets/Tests/EditMode/AI/BlackboardTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 54506ee78297ac6488bbaefbd5678546 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Tests/EditMode/BaseGames.Tests.EditMode.asmdef b/Assets/Tests/EditMode/BaseGames.Tests.EditMode.asmdef index 714c534b..b60c3944 100644 --- a/Assets/Tests/EditMode/BaseGames.Tests.EditMode.asmdef +++ b/Assets/Tests/EditMode/BaseGames.Tests.EditMode.asmdef @@ -5,6 +5,7 @@ "BaseGames.Combat.StatusEffects", "BaseGames.Combat", "BaseGames.Core", + "BaseGames.AI", "BaseGames.Core.Events", "BaseGames.Core.Save", "BaseGames.EventChain", diff --git a/Assets/_Game/Scripts/AI.meta b/Assets/_Game/Scripts/AI.meta new file mode 100644 index 00000000..0b5f456f --- /dev/null +++ b/Assets/_Game/Scripts/AI.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1b4185e382aa90040a5f79472a37c424 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Game/Scripts/AI/AiSignal.cs b/Assets/_Game/Scripts/AI/AiSignal.cs new file mode 100644 index 00000000..b681bb6e --- /dev/null +++ b/Assets/_Game/Scripts/AI/AiSignal.cs @@ -0,0 +1,15 @@ +namespace BaseGames.AI +{ + /// 决策层的推送信号,用于事件驱动的状态转换(不靠轮询)。 + public enum AiSignal + { + Damaged, // 受到伤害 + Parried, // 被弹反 + Staggered, // 进入硬直 + KnockedUp, // 被击飞 + Died, // 死亡 + PlayerSpotted,// 首次侦测到玩家 + AbilityEnded, // 当前能力协程结束/被打断 + PhaseChanged // Boss 阶段变更 + } +} diff --git a/Assets/_Game/Scripts/AI/AiSignal.cs.meta b/Assets/_Game/Scripts/AI/AiSignal.cs.meta new file mode 100644 index 00000000..294700e2 --- /dev/null +++ b/Assets/_Game/Scripts/AI/AiSignal.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 58a00d0c7341ac44187efe5e28ebf2c6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Game/Scripts/AI/BaseGames.AI.asmdef b/Assets/_Game/Scripts/AI/BaseGames.AI.asmdef new file mode 100644 index 00000000..2115deb7 --- /dev/null +++ b/Assets/_Game/Scripts/AI/BaseGames.AI.asmdef @@ -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 +} diff --git a/Assets/_Game/Scripts/AI/BaseGames.AI.asmdef.meta b/Assets/_Game/Scripts/AI/BaseGames.AI.asmdef.meta new file mode 100644 index 00000000..4b54aa88 --- /dev/null +++ b/Assets/_Game/Scripts/AI/BaseGames.AI.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 024d079978973a44ebe11fb10cc081ad +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_Game/Scripts/AI/Blackboard.cs b/Assets/_Game/Scripts/AI/Blackboard.cs new file mode 100644 index 00000000..42b89e3c --- /dev/null +++ b/Assets/_Game/Scripts/AI/Blackboard.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using System.Globalization; + +namespace BaseGames.AI +{ + /// + /// 具名、可枚举的 AI 临时值容器(每敌人实例一份)。 + /// 保留"具名"是为了让调试器/MCP 能通用枚举当前值。 + /// + public sealed class Blackboard + { + readonly Dictionary _values = new Dictionary(); + + public void Set(string key, T value) => _values[key] = value; + + public T Get(string key) + => _values.TryGetValue(key, out var v) && v is T t ? t : default; + + public bool Has(string key) => _values.ContainsKey(key); + + public IReadOnlyCollection Keys => _values.Keys; + + public void Clear() => _values.Clear(); + + /// 供调试器/MCP 自省:key → 值的字符串表示。 + public Dictionary Snapshot() + { + var result = new Dictionary(_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; + } + } +} diff --git a/Assets/_Game/Scripts/AI/Blackboard.cs.meta b/Assets/_Game/Scripts/AI/Blackboard.cs.meta new file mode 100644 index 00000000..2b5f5982 --- /dev/null +++ b/Assets/_Game/Scripts/AI/Blackboard.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6a494477153510d4e8a976d437aac8b6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: