refactor(editor): 角色向导 Boss 页改产出 EnemyAbilitySO
该向导是 5 个空 BossSkillSO 资产的创建链路——不改则会持续产出旧轨资产。 招式表扩为带 soType / rangeRadius / cooldown / weight 的形式(与 GetEnemyAbilityDefs 对齐),阶段可用性移交 BossPhaseAbilityGate。 产出时强制 rangeRadius > 0,不把责任推给下游作者。 状态面板改查 EnemyAbilitySO,并新增 AI 图注册状态一行。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,6 @@ using UnityEditor;
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using BaseGames.Boss;
|
||||
using BaseGames.Combat;
|
||||
using BaseGames.Enemies;
|
||||
using BaseGames.Enemies.Abilities;
|
||||
@@ -76,8 +75,7 @@ namespace BaseGames.Editor
|
||||
// 动态内容区(类型切换时重建)
|
||||
private VisualElement _enemyContentArea;
|
||||
|
||||
// Boss 命名字段
|
||||
private string _bossId = "NewBoss"; // kept for legacy SkillSequenceSO queries if any
|
||||
// 命名字段
|
||||
private string _enemyId = "E001"; // kept for legacy status calls if any
|
||||
private string _playerId = "Player";
|
||||
|
||||
@@ -330,11 +328,12 @@ namespace BaseGames.Editor
|
||||
var factory = MakeActionGroup();
|
||||
factory.Add(MakeFactoryButton("ENM_ChaoFeng_Stats.asset", () => { CreateChaoFengStatsSO(); RefreshSOStatus(); }));
|
||||
factory.Add(MakeFactoryButton("ENM_ChaoFeng_AnimConfig.asset",() => { CreateChaoFengAnimConfigSO(); RefreshSOStatus(); }));
|
||||
foreach (var (skName, skId, skPhases, skWeight) in ChaoFengSkillDefs)
|
||||
foreach (var (abName, abId, soType, r, cd, w, ph) in ChaoFengAbilityDefs)
|
||||
{
|
||||
string cName = skName; string cId = skId; int[] cPhases = skPhases; float cWeight = skWeight;
|
||||
string cName = abName; string cId = abId; System.Type cType = soType;
|
||||
float cR = r, cCd = cd, cW = w; int cPh = ph;
|
||||
factory.Add(MakeFactoryButton($"ABL_ChaoFeng_{cName}.asset",
|
||||
() => { CreateChaoFengSkillSO(cName, cId, cPhases, cWeight); RefreshSOStatus(); }));
|
||||
() => { CreateChaoFengAbilitySO(cName, cId, cType, cR, cCd, cW, cPh); RefreshSOStatus(); }));
|
||||
}
|
||||
root.Add(factory);
|
||||
|
||||
@@ -345,7 +344,9 @@ namespace BaseGames.Editor
|
||||
|
||||
root.Add(MakeSeparator());
|
||||
root.Add(MakeSectionHeader("▶ 场景搭建"));
|
||||
root.Add(MakeHelpBox("放置嘲风完整组件树(ChaoFengBoss + 浮空控制器 + 击倒计数 + Phase1 HitBox × 4 + 炮口 × 3)。"));
|
||||
root.Add(MakeHelpBox("放置嘲风完整组件树(ChaoFengBoss + 浮空控制器 + 击倒计数 + " +
|
||||
"EnemyAiBrain + BossPhaseAbilityGate + 6 个能力组件 + " +
|
||||
"Phase1 HitBox × 4 + 炮口 × 3)。"));
|
||||
|
||||
var bossSpriteField = new UnityEditor.UIElements.ObjectField("默认外观 Sprite(碰撞体尺寸依据,可留空)")
|
||||
{ objectType = typeof(Sprite), allowSceneObjects = false, value = _defaultSprite };
|
||||
@@ -362,9 +363,8 @@ namespace BaseGames.Editor
|
||||
root.Add(MakeSectionHeader("▶ 专项编辑器"));
|
||||
|
||||
var jumpGroup = MakeActionGroup();
|
||||
jumpGroup.Add(MakeJumpButton("Boss 技能序列查看器", BossSkillSequenceWindow.OpenWindow));
|
||||
jumpGroup.Add(MakeJumpButton("武器 HitBox 向导", WeaponHitBoxWizard.Open));
|
||||
jumpGroup.Add(MakeJumpButton("Data Hub(Boss技能)", DataHubWindow.Open));
|
||||
jumpGroup.Add(MakeJumpButton("Data Hub(敌人 / 能力)", DataHubWindow.Open));
|
||||
jumpGroup.Add(MakeJumpButton("SO 全局校验", SOValidationRunner.ValidateMenu));
|
||||
root.Add(jumpGroup);
|
||||
|
||||
@@ -689,41 +689,72 @@ namespace BaseGames.Editor
|
||||
EditorScaffoldUtils.CreateSOAsset<EnemyAnimationConfigSO>(dir, "ENM_ChaoFeng_AnimConfig");
|
||||
}
|
||||
|
||||
private static void CreateChaoFengSkillSO(string skillName, string skillId, int[] phaseIndices, float weight)
|
||||
private static void CreateChaoFengAbilitySO(
|
||||
string abilityName, string abilityId, System.Type soType,
|
||||
float rangeRadius, float cooldown, float weight, int phase)
|
||||
{
|
||||
string dir = "Assets/_Game/Data/Enemies/ChaoFeng/Abilities";
|
||||
string name = $"ABL_ChaoFeng_{skillName}";
|
||||
var so = EditorScaffoldUtils.CreateSOAsset<BossSkillSO>(dir, name);
|
||||
if (so != null)
|
||||
const string dir = "Assets/_Game/Data/Enemies/ChaoFeng/Abilities";
|
||||
string name = $"ABL_ChaoFeng_{abilityName}";
|
||||
|
||||
var so = EditorScaffoldUtils.CreateSOAsset(soType, dir, name) as EnemyAbilitySO;
|
||||
if (so == null) return; // 已存在则不覆盖
|
||||
|
||||
so.abilityId = abilityId;
|
||||
so.designNote = phase < 0
|
||||
? "入场演出,不进选招池"
|
||||
: $"阶段 {phase} 招式;阶段可用性由 BossPhaseAbilityGate 配置";
|
||||
so.cooldown = cooldown;
|
||||
|
||||
if (phase < 0)
|
||||
{
|
||||
so.skillId = skillId;
|
||||
so.displayName = skillName;
|
||||
so.availablePhaseIndices = phaseIndices;
|
||||
so.category = AbilityCategory.None;
|
||||
so.rangeRadius = 0f;
|
||||
so.weight = 0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
so.category = AbilityCategory.Attack;
|
||||
so.rangeRadius = rangeRadius; // 必须 > 0,否则选招器永远选不中
|
||||
so.weight = weight;
|
||||
}
|
||||
|
||||
EditorUtility.SetDirty(so);
|
||||
AssetDatabase.SaveAssets();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>嘲风技能集(计划):Phase0 四技能加权随机 + Phase1 风石。</summary>
|
||||
private static readonly (string name, string id, int[] phases, float weight)[] ChaoFengSkillDefs =
|
||||
/// <summary>
|
||||
/// 嘲风能力集。阶段可用性不在 SO 上——由 BossPhaseAbilityGate 承载
|
||||
/// (见放置工具 PlaceChaoFeng),这里只记录供说明文本使用。
|
||||
/// rangeRadius 必须 > 0:category==Attack 且射程为 0 的招永远够不着玩家,
|
||||
/// EnemyAbilitySO.Validate 与 EnemyBase.BuildAttackSelector 都会显式报错。
|
||||
/// </summary>
|
||||
private static readonly (string name, string id, System.Type soType,
|
||||
float rangeRadius, float cooldown, float weight, int phase)[]
|
||||
ChaoFengAbilityDefs =
|
||||
{
|
||||
("Boomerang", "boomerang", new[] { 0 }, 1.0f),
|
||||
("FanCombo", "fan_combo", new[] { 0 }, 1.5f),
|
||||
("TornadoSmall", "tornado_small", new[] { 0 }, 1.2f),
|
||||
("TornadoLarge", "tornado_large", new[] { 0 }, 0.8f),
|
||||
("WindStone", "wind_stone", new[] { 1 }, 1.0f),
|
||||
("Intro", "chaofeng_intro", typeof(PlayClipAbilitySO), 0f, 0f, 0f, -1),
|
||||
("Boomerang", "boomerang", typeof(PlayClipAbilitySO), 9f, 4.0f, 1.0f, 0),
|
||||
("FanCombo", "fan_combo", typeof(EnemyAbilitySO), 2.5f, 2.5f, 1.5f, 0),
|
||||
("TornadoSmall", "tornado_small", typeof(PlayClipAbilitySO), 8f, 3.5f, 1.2f, 0),
|
||||
("TornadoLarge", "tornado_large", typeof(PlayClipAbilitySO), 12f, 6.0f, 0.8f, 0),
|
||||
("WindStone", "wind_stone", typeof(PlayClipAbilitySO), 12f, 3.0f, 1.0f, 1),
|
||||
};
|
||||
|
||||
private static void CreateAllChaoFengSOs()
|
||||
{
|
||||
CreateChaoFengStatsSO();
|
||||
CreateChaoFengAnimConfigSO();
|
||||
foreach (var (n, id, phases, weight) in ChaoFengSkillDefs)
|
||||
CreateChaoFengSkillSO(n, id, phases, weight);
|
||||
foreach (var (n, id, t, r, cd, w, ph) in ChaoFengAbilityDefs)
|
||||
CreateChaoFengAbilitySO(n, id, t, r, cd, w, ph);
|
||||
AssetDatabase.SaveAssets();
|
||||
EditorUtility.DisplayDialog("创建完成",
|
||||
"全部嘲风 SO 已创建(已存在的跳过)。\n放置到场景后检查 BossSkillExecutor._skills 绑定。", "确定");
|
||||
"全部嘲风 SO 已创建(已存在的跳过)。\n" +
|
||||
"接下来:\n" +
|
||||
"1. 用「放置嘲风到场景并绑定 SO」生成组件树;\n" +
|
||||
"2. 检查 EnemyAiBrain._definitionId = ChaoFeng;\n" +
|
||||
"3. 检查各能力组件的 _config 已绑定对应 ABL_ 资产;\n" +
|
||||
"4. 在 BossPhaseAbilityGate 上确认阶段表(地面四招=阶段0,风石=阶段1)。",
|
||||
"确定");
|
||||
}
|
||||
|
||||
// ── 场景搭建(已移至 RefreshEnemyTabContent 内的内联按钮) ─────────────
|
||||
@@ -794,10 +825,16 @@ namespace BaseGames.Editor
|
||||
("ENM_ChaoFeng_Stats", FindAtPath<EnemyStatsSO>($"{dir}/ENM_ChaoFeng_Stats.asset")),
|
||||
("ENM_ChaoFeng_AnimConfig",FindAtPath<EnemyAnimationConfigSO>($"{dir}/ENM_ChaoFeng_AnimConfig.asset")),
|
||||
};
|
||||
foreach (var (skName, _, _, _) in ChaoFengSkillDefs)
|
||||
checks.Add(($"ABL_ChaoFeng_{skName}", FindAtPath<BossSkillSO>($"{ablDir}/ABL_ChaoFeng_{skName}.asset")));
|
||||
foreach (var (abName, _, _, _, _, _, _) in ChaoFengAbilityDefs)
|
||||
checks.Add(($"ABL_ChaoFeng_{abName}",
|
||||
FindAtPath<EnemyAbilitySO>($"{ablDir}/ABL_ChaoFeng_{abName}.asset")));
|
||||
|
||||
// AI 图是代码定义的(定制路径),没有资产可查——用注册表确认它被反射收集到了
|
||||
bool hasAiGraph = BaseGames.AI.AiDefinitionRegistry.Has("ChaoFeng");
|
||||
_bossStatusPanel.Add(MakeStatusGrid(checks.ToArray()));
|
||||
_bossStatusPanel.Add(new Label(
|
||||
hasAiGraph ? "✔ AI 图 ChaoFengAi 已注册(定制路径 _definitionId = ChaoFeng)"
|
||||
: "✘ AI 图 ChaoFengAi 未注册——检查 [AiDefinition(\"ChaoFeng\")] 特性"));
|
||||
}
|
||||
|
||||
// ── 辅助:状态格 ─────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user