feat(enemy): BossPhaseAbilityGate——阶段即换招池
按阶段启停能力组件,被禁用的招经 CanUse 自动退出选招候选, 阶段门不需要碰选招器。取代 BossSkillSO.availablePhaseIndices。 EnterPhase 先换池后广播;OnSpawn 回阶段 0(对象池复用)。
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
@@ -54,5 +55,71 @@ namespace BaseGames.Tests.EditMode.Enemies
|
||||
ab.enabled = false;
|
||||
Assert.IsFalse(ab.CanUse, "禁用的能力组件不可用——否则选招器会选中一个启不动招的招");
|
||||
}
|
||||
|
||||
// 阶段门的 _entries 是私有序列化字段——与放置脚手架同样用反射写入。
|
||||
// 反射只用来喂入这份配置数据,ApplyPhase 的判定逻辑走的仍是生产代码。
|
||||
private static void SetEntries(BossPhaseAbilityGate gate,
|
||||
params (EnemyAbilityBase ab, int[] phases)[] items)
|
||||
{
|
||||
var arr = new BossPhaseAbilityGate.PhaseEntry[items.Length];
|
||||
for (int i = 0; i < items.Length; i++)
|
||||
arr[i] = new BossPhaseAbilityGate.PhaseEntry { ability = items[i].ab, phases = items[i].phases };
|
||||
typeof(BossPhaseAbilityGate)
|
||||
.GetField("_entries", BindingFlags.NonPublic | BindingFlags.Instance)
|
||||
.SetValue(gate, arr);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ApplyPhase_EnablesOnlyAbilitiesAllowedInThatPhase()
|
||||
{
|
||||
_host = new GameObject("boss");
|
||||
var gate = _host.AddComponent<BossPhaseAbilityGate>();
|
||||
var p0 = _host.AddComponent<StubAbility>();
|
||||
// EnemyAbilityBase 是 [DisallowMultipleComponent],第二个能力必须另起子节点
|
||||
// (挂在 _host 下,TearDown 会连带销毁)
|
||||
var p1Go = new GameObject("p1"); p1Go.transform.SetParent(_host.transform);
|
||||
var p1 = p1Go.AddComponent<StubAbility>();
|
||||
|
||||
SetEntries(gate, (p0, new[] { 0 }), (p1, new[] { 1 }));
|
||||
|
||||
gate.ApplyPhase(0);
|
||||
Assert.IsTrue (p0.enabled, "阶段 0 的招应在阶段 0 启用");
|
||||
Assert.IsFalse(p1.enabled, "阶段 1 的招不应在阶段 0 启用");
|
||||
|
||||
gate.ApplyPhase(1);
|
||||
Assert.IsFalse(p0.enabled, "换阶段后旧池的招应被禁用");
|
||||
Assert.IsTrue (p1.enabled, "换阶段后新池的招应被启用");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ApplyPhase_EmptyPhaseArrayMeansAllPhases()
|
||||
{
|
||||
_host = new GameObject("boss");
|
||||
var gate = _host.AddComponent<BossPhaseAbilityGate>();
|
||||
var any = _host.AddComponent<StubAbility>();
|
||||
|
||||
SetEntries(gate, (any, new int[0]));
|
||||
|
||||
gate.ApplyPhase(0);
|
||||
Assert.IsTrue(any.enabled, "空阶段数组 = 全阶段可用");
|
||||
gate.ApplyPhase(7);
|
||||
Assert.IsTrue(any.enabled, "空阶段数组在任意阶段都应保持启用");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ApplyPhase_UnlistedAbilityIsUntouched()
|
||||
{
|
||||
_host = new GameObject("boss");
|
||||
var gate = _host.AddComponent<BossPhaseAbilityGate>();
|
||||
var listed = _host.AddComponent<StubAbility>();
|
||||
var otherGo = new GameObject("unlisted"); otherGo.transform.SetParent(_host.transform);
|
||||
var unlisted = otherGo.AddComponent<StubAbility>();
|
||||
|
||||
SetEntries(gate, (listed, new[] { 1 }));
|
||||
|
||||
gate.ApplyPhase(0);
|
||||
Assert.IsFalse(listed.enabled, "登记的能力应被阶段门管控");
|
||||
Assert.IsTrue (unlisted.enabled, "未登记的能力不受阶段门影响");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user