Refactor code structure for improved readability and maintainability
This commit is contained in:
@@ -1,11 +1,16 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Animancer;
|
||||
using BaseGames.Boss;
|
||||
using BaseGames.Camera;
|
||||
using BaseGames.Combat;
|
||||
using BaseGames.Combat.StatusEffects;
|
||||
using BaseGames.Dialogue;
|
||||
using BaseGames.Enemies;
|
||||
using BaseGames.Enemies.Abilities;
|
||||
using BaseGames.Enemies.Boss;
|
||||
using BaseGames.Enemies.Navigation;
|
||||
using BaseGames.Enemies.Perception;
|
||||
using BaseGames.Equipment;
|
||||
using BaseGames.Parry;
|
||||
using BaseGames.Player;
|
||||
@@ -376,6 +381,741 @@ namespace BaseGames.Editor
|
||||
MarkDirtyAndLog("Boss Enemy", go, report);
|
||||
}
|
||||
|
||||
// ══ 具体敌人快速放置 ════════════════════════════════════════════════════
|
||||
|
||||
[MenuItem("BaseGames/Scene/Place/Enemy E001 (草蛭)", priority = 111)]
|
||||
public static void PlaceE001_CaoZhi()
|
||||
{
|
||||
var report = new List<string>();
|
||||
int undoGroup = Undo.GetCurrentGroup();
|
||||
Undo.SetCurrentGroupName("Place E001 草蛭");
|
||||
|
||||
GameObject go = new GameObject("ENM_CaoZhi");
|
||||
Undo.RegisterCreatedObjectUndo(go, "Place E001");
|
||||
go.transform.position = GetDropPosition();
|
||||
SetLayer(go, "Enemy", report);
|
||||
|
||||
Rigidbody2D rb = GetOrAddComponent<Rigidbody2D>(go);
|
||||
rb.bodyType = RigidbodyType2D.Dynamic;
|
||||
rb.gravityScale = 2f;
|
||||
rb.constraints = RigidbodyConstraints2D.FreezeRotation;
|
||||
rb.collisionDetectionMode = CollisionDetectionMode2D.Continuous;
|
||||
|
||||
CapsuleCollider2D body = GetOrAddComponent<CapsuleCollider2D>(go);
|
||||
body.size = new Vector2(0.6f, 0.8f);
|
||||
|
||||
GetOrAddComponent<Animator>(go);
|
||||
AnimancerComponent animancer = GetOrAddComponent<AnimancerComponent>(go);
|
||||
SpriteRenderer sr1 = SetupSpriteRenderer(go);
|
||||
|
||||
EnemyBase enemyBase = GetOrAddComponent<EnemyBase>(go);
|
||||
EnemyStats enemyStats = GetOrAddComponent<EnemyStats>(go);
|
||||
EnemyMovement movement = GetOrAddComponent<EnemyMovement>(go);
|
||||
GetOrAddComponent<EnemyNavAgent>(go);
|
||||
GetOrAddComponent<NavAgent>(go);
|
||||
EnemySensorHub sensorHub = GetOrAddComponent<EnemySensorHub>(go);
|
||||
|
||||
Transform hurtBoxT = GetOrCreateChild(go.transform, "HurtBox");
|
||||
SetLayer(hurtBoxT.gameObject, "EnemyHurtBox", report);
|
||||
CapsuleCollider2D hurtCap = GetOrAddComponent<CapsuleCollider2D>(hurtBoxT.gameObject);
|
||||
hurtCap.isTrigger = true;
|
||||
hurtCap.size = new Vector2(0.55f, 0.75f);
|
||||
HurtBox hurtBox = GetOrAddComponent<HurtBox>(hurtBoxT.gameObject);
|
||||
|
||||
Transform contactT = GetOrCreateChild(go.transform, "ContactDamageZone");
|
||||
SetLayer(contactT.gameObject, "EnemyHitBox", report);
|
||||
CircleCollider2D contactCol = GetOrAddComponent<CircleCollider2D>(contactT.gameObject);
|
||||
contactCol.isTrigger = true;
|
||||
contactCol.radius = 0.4f;
|
||||
HitBox contactHitBox = GetOrAddComponent<HitBox>(contactT.gameObject);
|
||||
BodyContactDamage bodyContact = GetOrAddComponent<BodyContactDamage>(contactT.gameObject);
|
||||
|
||||
Transform abilitiesT = GetOrCreateChild(go.transform, "Abilities");
|
||||
Transform alertT = GetOrCreateChild(abilitiesT, "PlayClipAbility_Alert");
|
||||
PlayClipAbility alertAbility = GetOrAddComponent<PlayClipAbility>(alertT.gameObject);
|
||||
Transform chaseT = GetOrCreateChild(abilitiesT, "ContactChaseAbility_Chase");
|
||||
ContactChaseAbility chaseAbility = GetOrAddComponent<ContactChaseAbility>(chaseT.gameObject);
|
||||
|
||||
// SOs — assign first so OnValidate doesn't warn during wiring
|
||||
AssignAsset(enemyBase, "_statsSO", report, false, "ENM_E001_Stats");
|
||||
AssignAsset(enemyBase, "_animConfig", report, false, "ENM_E001_AnimConfig");
|
||||
|
||||
// Component wiring
|
||||
AssignReference(enemyBase, "_stats", enemyStats, report);
|
||||
AssignReference(enemyBase, "_movement", movement, report);
|
||||
AssignReference(enemyBase, "_animancer", animancer, report);
|
||||
AssignReference(enemyBase, "_hurtBox", hurtBox, report);
|
||||
AssignAsset(enemyBase, "_onEnemyDied", report, false, "EVT_EnemyDied");
|
||||
AssignAsset(enemyBase, "_onPlayerSpawned", report, false, "EVT_PlayerSpawned");
|
||||
AssignAsset(enemyStats, "_onDifficultyChanged", report, false, "EVT_DifficultyChanged");
|
||||
AssignAsset(hurtBox, "_onDamageDealt", report, false, "EVT_DamageDealt");
|
||||
AssignAsset(hurtBox, "_onHitConfirmed", report, false, "EVT_HitConfirmed");
|
||||
|
||||
AssignAsset(movement, "_config", report, false, "ENM_E001_Stats");
|
||||
AssignAsset(movement, "_animConfig", report, false, "ENM_E001_AnimConfig");
|
||||
AssignReference(movement, "_animancer", animancer, report);
|
||||
AssignReference(movement, "_spriteRenderer", sr1, report);
|
||||
|
||||
AssignAsset(alertAbility, "_config", report, false, "ABL_E001_Alert");
|
||||
AssignAsset(chaseAbility, "_config", report, false, "ABL_E001_Chase");
|
||||
AssignReference(chaseAbility, "_contactDamage", bodyContact, report);
|
||||
AssignReference(chaseAbility, "_sensorHub", sensorHub, report);
|
||||
|
||||
Object dmgSrc = FindFirstAsset("CMB_DS_EnemyBody");
|
||||
if (dmgSrc != null) AssignReference(contactHitBox, "_defaultSource", dmgSrc, report);
|
||||
|
||||
SetupSensorHubSlotNames(sensorHub, new[] { "aggro", "wall_ahead", "ledge" }, report);
|
||||
report.Add("★ 在 EnemySensorHub Inspector 中绑定 Sensor 子节点(aggro/wall_ahead/ledge)。");
|
||||
report.Add("★ 挂载行为树 BehaviorTree 组件,指定 E001_CaoZhi.asset。");
|
||||
|
||||
Undo.CollapseUndoOperations(undoGroup);
|
||||
Selection.activeGameObject = go;
|
||||
MarkDirtyAndLog("E001 草蛭", go, report);
|
||||
}
|
||||
|
||||
[MenuItem("BaseGames/Scene/Place/Enemy E002 (簧蛭)", priority = 112)]
|
||||
public static void PlaceE002_HuangZhi()
|
||||
{
|
||||
var report = new List<string>();
|
||||
int undoGroup = Undo.GetCurrentGroup();
|
||||
Undo.SetCurrentGroupName("Place E002 簧蛭");
|
||||
|
||||
GameObject go = new GameObject("ENM_HuangZhi");
|
||||
Undo.RegisterCreatedObjectUndo(go, "Place E002");
|
||||
go.transform.position = GetDropPosition();
|
||||
SetLayer(go, "Enemy", report);
|
||||
|
||||
Rigidbody2D rb = GetOrAddComponent<Rigidbody2D>(go);
|
||||
rb.bodyType = RigidbodyType2D.Kinematic;
|
||||
rb.gravityScale = 0f;
|
||||
|
||||
CapsuleCollider2D body = GetOrAddComponent<CapsuleCollider2D>(go);
|
||||
body.size = new Vector2(0.5f, 0.7f);
|
||||
|
||||
GetOrAddComponent<Animator>(go);
|
||||
AnimancerComponent animancer = GetOrAddComponent<AnimancerComponent>(go);
|
||||
SetupSpriteRenderer(go);
|
||||
|
||||
EnemyBase enemyBase = GetOrAddComponent<EnemyBase>(go);
|
||||
EnemyStats enemyStats = GetOrAddComponent<EnemyStats>(go);
|
||||
EnemySensorHub sensorHub = GetOrAddComponent<EnemySensorHub>(go);
|
||||
|
||||
// HurtBox(初始禁用,附着天花板时不受伤)
|
||||
Transform hurtBoxT = GetOrCreateChild(go.transform, "HurtBox");
|
||||
SetLayer(hurtBoxT.gameObject, "EnemyHurtBox", report);
|
||||
CapsuleCollider2D hurtCap = GetOrAddComponent<CapsuleCollider2D>(hurtBoxT.gameObject);
|
||||
hurtCap.isTrigger = true;
|
||||
hurtCap.size = new Vector2(0.45f, 0.65f);
|
||||
HurtBox hurtBox = GetOrAddComponent<HurtBox>(hurtBoxT.gameObject);
|
||||
hurtBoxT.gameObject.SetActive(false);
|
||||
|
||||
// AttackHitBox(下坠发动时由能力启用)
|
||||
Transform atkT = GetOrCreateChild(go.transform, "AttackHitBox");
|
||||
SetLayer(atkT.gameObject, "EnemyHitBox", report);
|
||||
BoxCollider2D atkCol = GetOrAddComponent<BoxCollider2D>(atkT.gameObject);
|
||||
atkCol.isTrigger = true;
|
||||
atkCol.size = new Vector2(0.5f, 0.5f);
|
||||
HitBox atkHitBox = GetOrAddComponent<HitBox>(atkT.gameObject);
|
||||
atkT.gameObject.SetActive(false);
|
||||
|
||||
Transform abilitiesT = GetOrCreateChild(go.transform, "Abilities");
|
||||
Transform strikeT = GetOrCreateChild(abilitiesT, "CeilingHangStrikeAbility");
|
||||
CeilingHangStrikeAbility strikeAbility = GetOrAddComponent<CeilingHangStrikeAbility>(strikeT.gameObject);
|
||||
|
||||
// SOs — assign first so OnValidate doesn't warn during wiring
|
||||
AssignAsset(enemyBase, "_statsSO", report, false, "ENM_E002_Stats");
|
||||
AssignAsset(enemyBase, "_animConfig", report, false, "ENM_E002_AnimConfig");
|
||||
|
||||
AssignReference(enemyBase, "_stats", enemyStats, report);
|
||||
AssignReference(enemyBase, "_animancer", animancer, report);
|
||||
AssignReference(enemyBase, "_hurtBox", hurtBox, report);
|
||||
AssignAsset(enemyBase, "_onEnemyDied", report, false, "EVT_EnemyDied");
|
||||
AssignAsset(enemyBase, "_onPlayerSpawned", report, false, "EVT_PlayerSpawned");
|
||||
AssignAsset(enemyStats, "_onDifficultyChanged", report, false, "EVT_DifficultyChanged");
|
||||
AssignAsset(hurtBox, "_onDamageDealt", report, false, "EVT_DamageDealt");
|
||||
AssignAsset(hurtBox, "_onHitConfirmed", report, false, "EVT_HitConfirmed");
|
||||
|
||||
AssignAsset(strikeAbility, "_config", report, false, "ABL_E002_Strike");
|
||||
AssignReference(strikeAbility, "_attackHitBox", atkHitBox, report);
|
||||
AssignReference(strikeAbility, "_hurtBox", hurtBox, report);
|
||||
|
||||
Object dmgSrc = FindFirstAsset("CMB_DS_EnemyBody");
|
||||
if (dmgSrc != null) AssignReference(atkHitBox, "_defaultSource", dmgSrc, report);
|
||||
|
||||
SetupSensorHubSlotNames(sensorHub, new[] { "attack_range" }, report);
|
||||
report.Add("★ 将此对象放置于天花板,调整位置使 CapsuleCollider 正好贴合天花板底面。");
|
||||
report.Add("★ 挂载行为树 BehaviorTree 组件,指定 E002_HuangZhi.asset。");
|
||||
|
||||
Undo.CollapseUndoOperations(undoGroup);
|
||||
Selection.activeGameObject = go;
|
||||
MarkDirtyAndLog("E002 簧蛭", go, report);
|
||||
}
|
||||
|
||||
[MenuItem("BaseGames/Scene/Place/Enemy E003 (幼蛭)", priority = 113)]
|
||||
public static void PlaceE003_YouZhi_Enemy()
|
||||
{
|
||||
var report = new List<string>();
|
||||
int undoGroup = Undo.GetCurrentGroup();
|
||||
Undo.SetCurrentGroupName("Place E003 幼蛭");
|
||||
|
||||
GameObject go = new GameObject("ENM_YouZhi");
|
||||
Undo.RegisterCreatedObjectUndo(go, "Place E003");
|
||||
go.transform.position = GetDropPosition();
|
||||
SetLayer(go, "Enemy", report);
|
||||
|
||||
Rigidbody2D rb = GetOrAddComponent<Rigidbody2D>(go);
|
||||
rb.bodyType = RigidbodyType2D.Kinematic;
|
||||
rb.gravityScale = 0f;
|
||||
|
||||
CapsuleCollider2D body = GetOrAddComponent<CapsuleCollider2D>(go);
|
||||
body.size = new Vector2(0.5f, 0.6f);
|
||||
|
||||
GetOrAddComponent<Animator>(go);
|
||||
AnimancerComponent animancer = GetOrAddComponent<AnimancerComponent>(go);
|
||||
SpriteRenderer sr3 = SetupSpriteRenderer(go);
|
||||
|
||||
E003_YouZhi enemyBase = GetOrAddComponent<E003_YouZhi>(go);
|
||||
EnemyStats enemyStats = GetOrAddComponent<EnemyStats>(go);
|
||||
EnemyMovement movement = GetOrAddComponent<EnemyMovement>(go);
|
||||
GetOrAddComponent<EnemyNavAgent>(go);
|
||||
GetOrAddComponent<NavAgent>(go);
|
||||
EnemySensorHub sensorHub = GetOrAddComponent<EnemySensorHub>(go);
|
||||
|
||||
Transform hurtBoxT = GetOrCreateChild(go.transform, "HurtBox");
|
||||
SetLayer(hurtBoxT.gameObject, "EnemyHurtBox", report);
|
||||
CapsuleCollider2D hurtCap = GetOrAddComponent<CapsuleCollider2D>(hurtBoxT.gameObject);
|
||||
hurtCap.isTrigger = true;
|
||||
hurtCap.size = new Vector2(0.45f, 0.55f);
|
||||
HurtBox hurtBox = GetOrAddComponent<HurtBox>(hurtBoxT.gameObject);
|
||||
|
||||
Transform contactT = GetOrCreateChild(go.transform, "ContactDamageZone");
|
||||
SetLayer(contactT.gameObject, "EnemyHitBox", report);
|
||||
CircleCollider2D contactCol = GetOrAddComponent<CircleCollider2D>(contactT.gameObject);
|
||||
contactCol.isTrigger = true;
|
||||
contactCol.radius = 0.35f;
|
||||
HitBox contactHitBox = GetOrAddComponent<HitBox>(contactT.gameObject);
|
||||
BodyContactDamage bodyContact = GetOrAddComponent<BodyContactDamage>(contactT.gameObject);
|
||||
|
||||
Transform abilitiesT = GetOrCreateChild(go.transform, "Abilities");
|
||||
Transform fallT = GetOrCreateChild(abilitiesT, "AnimatedCeilingDropAbility");
|
||||
AnimatedCeilingDropAbility fallAbility = GetOrAddComponent<AnimatedCeilingDropAbility>(fallT.gameObject);
|
||||
|
||||
// SOs — assign first so OnValidate doesn't warn during wiring
|
||||
AssignAsset(enemyBase, "_statsSO", report, false, "ENM_E003_Stats");
|
||||
AssignAsset(enemyBase, "_animConfig", report, false, "ENM_E003_AnimConfig");
|
||||
|
||||
AssignReference(enemyBase, "_stats", enemyStats, report);
|
||||
AssignReference(enemyBase, "_movement", movement, report);
|
||||
AssignReference(enemyBase, "_animancer", animancer, report);
|
||||
AssignReference(enemyBase, "_hurtBox", hurtBox, report);
|
||||
AssignAsset(enemyBase, "_onEnemyDied", report, false, "EVT_EnemyDied");
|
||||
AssignAsset(enemyBase, "_onPlayerSpawned", report, false, "EVT_PlayerSpawned");
|
||||
AssignAsset(enemyStats, "_onDifficultyChanged", report, false, "EVT_DifficultyChanged");
|
||||
AssignAsset(hurtBox, "_onDamageDealt", report, false, "EVT_DamageDealt");
|
||||
AssignAsset(hurtBox, "_onHitConfirmed", report, false, "EVT_HitConfirmed");
|
||||
|
||||
AssignAsset(movement, "_config", report, false, "ENM_E003_Stats");
|
||||
AssignAsset(movement, "_animConfig", report, false, "ENM_E003_AnimConfig");
|
||||
AssignReference(movement, "_animancer", animancer, report);
|
||||
AssignReference(movement, "_spriteRenderer", sr3, report);
|
||||
|
||||
AssignAsset(fallAbility, "_config", report, false, "ABL_E003_Fall");
|
||||
AssignReference(fallAbility, "_contactDamage", bodyContact, report);
|
||||
|
||||
Object dmgSrc = FindFirstAsset("CMB_DS_EnemyBody");
|
||||
if (dmgSrc != null) AssignReference(contactHitBox, "_defaultSource", dmgSrc, report);
|
||||
|
||||
SetupSensorHubSlotNames(sensorHub, new[] { "aggro" }, report);
|
||||
report.Add("★ 将此对象放置于天花板下方,E003_YouZhi 会在 OnSpawn/ActivateFromCeiling 时执行下坠。");
|
||||
report.Add("★ 挂载行为树 BehaviorTree 组件,指定 E003_YouZhi.asset。");
|
||||
|
||||
Undo.CollapseUndoOperations(undoGroup);
|
||||
Selection.activeGameObject = go;
|
||||
MarkDirtyAndLog("E003 幼蛭", go, report);
|
||||
}
|
||||
|
||||
[MenuItem("BaseGames/Scene/Place/Enemy E004 (蛭母)", priority = 114)]
|
||||
public static void PlaceE004_ZhiMu_Enemy()
|
||||
{
|
||||
var report = new List<string>();
|
||||
int undoGroup = Undo.GetCurrentGroup();
|
||||
Undo.SetCurrentGroupName("Place E004 蛭母");
|
||||
|
||||
GameObject go = new GameObject("ENM_ZhiMu");
|
||||
Undo.RegisterCreatedObjectUndo(go, "Place E004");
|
||||
go.transform.position = GetDropPosition();
|
||||
SetLayer(go, "Enemy", report);
|
||||
|
||||
Rigidbody2D rb = GetOrAddComponent<Rigidbody2D>(go);
|
||||
rb.bodyType = RigidbodyType2D.Dynamic;
|
||||
rb.gravityScale = 2f;
|
||||
rb.constraints = RigidbodyConstraints2D.FreezeRotation;
|
||||
rb.collisionDetectionMode = CollisionDetectionMode2D.Continuous;
|
||||
|
||||
CapsuleCollider2D body = GetOrAddComponent<CapsuleCollider2D>(go);
|
||||
body.size = new Vector2(0.8f, 1.2f);
|
||||
|
||||
GetOrAddComponent<Animator>(go);
|
||||
AnimancerComponent animancer = GetOrAddComponent<AnimancerComponent>(go);
|
||||
SpriteRenderer sr4 = SetupSpriteRenderer(go);
|
||||
|
||||
E004_ZhiMu enemyBase = GetOrAddComponent<E004_ZhiMu>(go);
|
||||
EnemyStats enemyStats = GetOrAddComponent<EnemyStats>(go);
|
||||
EnemyFeedback feedback = GetOrAddComponent<EnemyFeedback>(go);
|
||||
EnemyMovement movement = GetOrAddComponent<EnemyMovement>(go);
|
||||
GetOrAddComponent<EnemyNavAgent>(go);
|
||||
GetOrAddComponent<NavAgent>(go);
|
||||
EnemySensorHub sensorHub = GetOrAddComponent<EnemySensorHub>(go);
|
||||
|
||||
Transform hurtBoxT = GetOrCreateChild(go.transform, "HurtBox");
|
||||
SetLayer(hurtBoxT.gameObject, "EnemyHurtBox", report);
|
||||
CapsuleCollider2D hurtCap = GetOrAddComponent<CapsuleCollider2D>(hurtBoxT.gameObject);
|
||||
hurtCap.isTrigger = true;
|
||||
hurtCap.size = new Vector2(0.75f, 1.1f);
|
||||
HurtBox hurtBox = GetOrAddComponent<HurtBox>(hurtBoxT.gameObject);
|
||||
|
||||
Transform biteT = GetOrCreateChild(go.transform, "BiteHitBox");
|
||||
SetLayer(biteT.gameObject, "EnemyHitBox", report);
|
||||
BoxCollider2D biteCol = GetOrAddComponent<BoxCollider2D>(biteT.gameObject);
|
||||
biteCol.isTrigger = true;
|
||||
biteCol.size = new Vector2(0.6f, 0.4f);
|
||||
HitBox biteHitBox = GetOrAddComponent<HitBox>(biteT.gameObject);
|
||||
biteT.gameObject.SetActive(false);
|
||||
|
||||
Transform slamT = GetOrCreateChild(go.transform, "SlamHitBox");
|
||||
SetLayer(slamT.gameObject, "EnemyHitBox", report);
|
||||
CircleCollider2D slamCol = GetOrAddComponent<CircleCollider2D>(slamT.gameObject);
|
||||
slamCol.isTrigger = true;
|
||||
slamCol.radius = 0.7f;
|
||||
HitBox slamHitBox = GetOrAddComponent<HitBox>(slamT.gameObject);
|
||||
slamT.gameObject.SetActive(false);
|
||||
|
||||
Transform chargeHitBoxT = GetOrCreateChild(go.transform, "ChargeHitBox");
|
||||
SetLayer(chargeHitBoxT.gameObject, "EnemyHitBox", report);
|
||||
BoxCollider2D chargeHitCol = GetOrAddComponent<BoxCollider2D>(chargeHitBoxT.gameObject);
|
||||
chargeHitCol.isTrigger = true;
|
||||
chargeHitCol.size = new Vector2(0.9f, 0.8f);
|
||||
HitBox chargeHitBox = GetOrAddComponent<HitBox>(chargeHitBoxT.gameObject);
|
||||
chargeHitBoxT.gameObject.SetActive(false);
|
||||
|
||||
Transform acidMuzzleT = GetOrCreateChild(go.transform, "AcidMuzzle");
|
||||
|
||||
Transform abilitiesT = GetOrCreateChild(go.transform, "Abilities");
|
||||
Transform biteAblT = GetOrCreateChild(abilitiesT, "MeleeAttackAbility_Bite");
|
||||
MeleeAttackAbility biteAbl = GetOrAddComponent<MeleeAttackAbility>(biteAblT.gameObject);
|
||||
Transform slamAblT = GetOrCreateChild(abilitiesT, "RepeatSlamAbility");
|
||||
RepeatSlamAbility slamAbl = GetOrAddComponent<RepeatSlamAbility>(slamAblT.gameObject);
|
||||
Transform acidAblT = GetOrCreateChild(abilitiesT, "ProjectileAttackAbility_Acid");
|
||||
ProjectileAttackAbility acidAbl = GetOrAddComponent<ProjectileAttackAbility>(acidAblT.gameObject);
|
||||
Transform chargeAblT = GetOrCreateChild(abilitiesT, "ChargeAbility");
|
||||
ChargeAbility chargeAbl = GetOrAddComponent<ChargeAbility>(chargeAblT.gameObject);
|
||||
Transform chaseAblT = GetOrCreateChild(abilitiesT, "ContactChaseAbility");
|
||||
ContactChaseAbility chaseAbl = GetOrAddComponent<ContactChaseAbility>(chaseAblT.gameObject);
|
||||
|
||||
// SOs — assign first so OnValidate doesn't warn during wiring
|
||||
AssignAsset(enemyBase, "_statsSO", report, false, "ENM_E004_Stats");
|
||||
AssignAsset(enemyBase, "_animConfig", report, false, "ENM_E004_AnimConfig");
|
||||
|
||||
AssignReference(enemyBase, "_stats", enemyStats, report);
|
||||
AssignReference(enemyBase, "_movement", movement, report);
|
||||
AssignReference(enemyBase, "_animancer", animancer, report);
|
||||
AssignReference(enemyBase, "_feedback", feedback, report);
|
||||
AssignReference(enemyBase, "_hurtBox", hurtBox, report);
|
||||
AssignAsset(enemyBase, "_onEnemyDied", report, false, "EVT_EnemyDied");
|
||||
AssignAsset(enemyBase, "_onPlayerSpawned", report, false, "EVT_PlayerSpawned");
|
||||
AssignAsset(enemyStats, "_onDifficultyChanged", report, false, "EVT_DifficultyChanged");
|
||||
AssignAsset(hurtBox, "_onDamageDealt", report, false, "EVT_DamageDealt");
|
||||
AssignAsset(hurtBox, "_onHitConfirmed", report, false, "EVT_HitConfirmed");
|
||||
|
||||
AssignAsset(movement, "_config", report, false, "ENM_E004_Stats");
|
||||
AssignAsset(movement, "_animConfig", report, false, "ENM_E004_AnimConfig");
|
||||
AssignReference(movement, "_animancer", animancer, report);
|
||||
AssignReference(movement, "_spriteRenderer", sr4, report);
|
||||
|
||||
AssignAsset(biteAbl, "_config", report, false, "ABL_E004_Bite");
|
||||
AssignAsset(slamAbl, "_config", report, false, "ABL_E004_Slam");
|
||||
AssignAsset(acidAbl, "_config", report, false, "ABL_E004_Acid");
|
||||
AssignAsset(chargeAbl, "_config", report, false, "ABL_E004_Charge");
|
||||
AssignAsset(chaseAbl, "_config", report, false, "ABL_E004_Chase");
|
||||
|
||||
AssignMeleeHitBoxSlots(biteAbl, new[] { ("bite", biteHitBox) }, report);
|
||||
AssignReference(slamAbl, "_hitBox", slamHitBox, report);
|
||||
AssignReference(acidAbl, "_muzzle", acidMuzzleT, report);
|
||||
AssignReference(chargeAbl, "_chargeHitBox", chargeHitBox, report);
|
||||
AssignReference(chaseAbl, "_sensorHub", sensorHub, report);
|
||||
|
||||
Object dmgSrc = FindFirstAsset("CMB_DS_EnemyBody");
|
||||
if (dmgSrc != null)
|
||||
{
|
||||
AssignReference(biteHitBox, "_defaultSource", dmgSrc, report);
|
||||
AssignReference(slamHitBox, "_defaultSource", dmgSrc, report);
|
||||
AssignReference(chargeHitBox, "_defaultSource", dmgSrc, report);
|
||||
}
|
||||
|
||||
SetupSensorHubSlotNames(sensorHub, new[] { "aggro", "los" }, report);
|
||||
report.Add("★ 挂载行为树 BehaviorTree 组件,指定 E004_ZhiMu.asset。");
|
||||
|
||||
Undo.CollapseUndoOperations(undoGroup);
|
||||
Selection.activeGameObject = go;
|
||||
MarkDirtyAndLog("E004 蛭母", go, report);
|
||||
}
|
||||
|
||||
[MenuItem("BaseGames/Scene/Place/Enemy E005 (肥蛭)", priority = 115)]
|
||||
public static void PlaceE005_FeiZhi_Enemy()
|
||||
{
|
||||
var report = new List<string>();
|
||||
int undoGroup = Undo.GetCurrentGroup();
|
||||
Undo.SetCurrentGroupName("Place E005 肥蛭");
|
||||
|
||||
GameObject go = new GameObject("ENM_FeiZhi");
|
||||
Undo.RegisterCreatedObjectUndo(go, "Place E005");
|
||||
go.transform.position = GetDropPosition();
|
||||
SetLayer(go, "Enemy", report);
|
||||
|
||||
Rigidbody2D rb = GetOrAddComponent<Rigidbody2D>(go);
|
||||
rb.bodyType = RigidbodyType2D.Dynamic;
|
||||
rb.gravityScale = 2f;
|
||||
rb.constraints = RigidbodyConstraints2D.FreezeRotation;
|
||||
rb.collisionDetectionMode = CollisionDetectionMode2D.Continuous;
|
||||
|
||||
CapsuleCollider2D body = GetOrAddComponent<CapsuleCollider2D>(go);
|
||||
body.size = new Vector2(0.9f, 1.0f);
|
||||
|
||||
GetOrAddComponent<Animator>(go);
|
||||
AnimancerComponent animancer = GetOrAddComponent<AnimancerComponent>(go);
|
||||
SpriteRenderer sr5 = SetupSpriteRenderer(go);
|
||||
|
||||
E005_FeiZhi enemyBase = GetOrAddComponent<E005_FeiZhi>(go);
|
||||
EnemyStats enemyStats = GetOrAddComponent<EnemyStats>(go);
|
||||
EnemyMovement movement = GetOrAddComponent<EnemyMovement>(go);
|
||||
GetOrAddComponent<EnemyNavAgent>(go);
|
||||
GetOrAddComponent<NavAgent>(go);
|
||||
EnemySensorHub sensorHub = GetOrAddComponent<EnemySensorHub>(go);
|
||||
|
||||
Transform hurtBoxT = GetOrCreateChild(go.transform, "HurtBox");
|
||||
SetLayer(hurtBoxT.gameObject, "EnemyHurtBox", report);
|
||||
CapsuleCollider2D hurtCap = GetOrAddComponent<CapsuleCollider2D>(hurtBoxT.gameObject);
|
||||
hurtCap.isTrigger = true;
|
||||
hurtCap.size = new Vector2(0.85f, 0.95f);
|
||||
HurtBox hurtBox = GetOrAddComponent<HurtBox>(hurtBoxT.gameObject);
|
||||
|
||||
Transform biteT = GetOrCreateChild(go.transform, "BiteHitBox");
|
||||
SetLayer(biteT.gameObject, "EnemyHitBox", report);
|
||||
BoxCollider2D biteCol = GetOrAddComponent<BoxCollider2D>(biteT.gameObject);
|
||||
biteCol.isTrigger = true;
|
||||
biteCol.size = new Vector2(0.7f, 0.45f);
|
||||
HitBox biteHitBox = GetOrAddComponent<HitBox>(biteT.gameObject);
|
||||
biteT.gameObject.SetActive(false);
|
||||
|
||||
Transform acidMuzzleT = GetOrCreateChild(go.transform, "AcidMuzzle");
|
||||
|
||||
Transform abilitiesT = GetOrCreateChild(go.transform, "Abilities");
|
||||
Transform biteAblT = GetOrCreateChild(abilitiesT, "MeleeAttackAbility_Bite");
|
||||
MeleeAttackAbility biteAbl = GetOrAddComponent<MeleeAttackAbility>(biteAblT.gameObject);
|
||||
Transform acidAblT = GetOrCreateChild(abilitiesT, "ProjectileAttackAbility_Acid");
|
||||
ProjectileAttackAbility acidAbl = GetOrAddComponent<ProjectileAttackAbility>(acidAblT.gameObject);
|
||||
|
||||
// SOs — assign first so OnValidate doesn't warn during wiring
|
||||
AssignAsset(enemyBase, "_statsSO", report, false, "ENM_E005_Stats");
|
||||
AssignAsset(enemyBase, "_animConfig", report, false, "ENM_E005_AnimConfig");
|
||||
|
||||
AssignReference(enemyBase, "_stats", enemyStats, report);
|
||||
AssignReference(enemyBase, "_movement", movement, report);
|
||||
AssignReference(enemyBase, "_animancer", animancer, report);
|
||||
AssignReference(enemyBase, "_hurtBox", hurtBox, report);
|
||||
AssignAsset(enemyBase, "_onEnemyDied", report, false, "EVT_EnemyDied");
|
||||
AssignAsset(enemyBase, "_onPlayerSpawned", report, false, "EVT_PlayerSpawned");
|
||||
AssignAsset(enemyStats, "_onDifficultyChanged", report, false, "EVT_DifficultyChanged");
|
||||
AssignAsset(hurtBox, "_onDamageDealt", report, false, "EVT_DamageDealt");
|
||||
AssignAsset(hurtBox, "_onHitConfirmed", report, false, "EVT_HitConfirmed");
|
||||
|
||||
AssignAsset(movement, "_config", report, false, "ENM_E005_Stats");
|
||||
AssignAsset(movement, "_animConfig", report, false, "ENM_E005_AnimConfig");
|
||||
AssignReference(movement, "_animancer", animancer, report);
|
||||
AssignReference(movement, "_spriteRenderer", sr5, report);
|
||||
|
||||
AssignAsset(biteAbl, "_config", report, false, "ABL_E005_Bite");
|
||||
AssignAsset(acidAbl, "_config", report, false, "ABL_E005_Acid");
|
||||
|
||||
AssignMeleeHitBoxSlots(biteAbl, new[] { ("bite", biteHitBox) }, report);
|
||||
AssignReference(acidAbl, "_muzzle", acidMuzzleT, report);
|
||||
|
||||
Object dmgSrc = FindFirstAsset("CMB_DS_EnemyBody");
|
||||
if (dmgSrc != null) AssignReference(biteHitBox, "_defaultSource", dmgSrc, report);
|
||||
|
||||
SetupSensorHubSlotNames(sensorHub, new[] { "aggro" }, report);
|
||||
report.Add("★ 在 E005_FeiZhi._deathPreClip 上添加 AnimationEvent 调用 SpawnProjectile(\"spawn_e003\")。");
|
||||
report.Add("★ 挂载行为树 BehaviorTree 组件,指定 E005_FeiZhi.asset。");
|
||||
|
||||
Undo.CollapseUndoOperations(undoGroup);
|
||||
Selection.activeGameObject = go;
|
||||
MarkDirtyAndLog("E005 肥蛭", go, report);
|
||||
}
|
||||
|
||||
[MenuItem("BaseGames/Scene/Place/Enemy E006 (讙)", priority = 116)]
|
||||
public static void PlaceE006_Huan()
|
||||
{
|
||||
var report = new List<string>();
|
||||
int undoGroup = Undo.GetCurrentGroup();
|
||||
Undo.SetCurrentGroupName("Place E006 讙");
|
||||
|
||||
GameObject go = new GameObject("ENM_Huan");
|
||||
Undo.RegisterCreatedObjectUndo(go, "Place E006");
|
||||
go.transform.position = GetDropPosition();
|
||||
SetLayer(go, "Enemy", report);
|
||||
|
||||
Rigidbody2D rb = GetOrAddComponent<Rigidbody2D>(go);
|
||||
rb.bodyType = RigidbodyType2D.Dynamic;
|
||||
rb.gravityScale = 2f;
|
||||
rb.constraints = RigidbodyConstraints2D.FreezeRotation;
|
||||
rb.collisionDetectionMode = CollisionDetectionMode2D.Continuous;
|
||||
|
||||
CapsuleCollider2D body = GetOrAddComponent<CapsuleCollider2D>(go);
|
||||
body.size = new Vector2(0.7f, 1.0f);
|
||||
|
||||
GetOrAddComponent<Animator>(go);
|
||||
AnimancerComponent animancer = GetOrAddComponent<AnimancerComponent>(go);
|
||||
SpriteRenderer sr6 = SetupSpriteRenderer(go);
|
||||
|
||||
EnemyBase enemyBase = GetOrAddComponent<EnemyBase>(go);
|
||||
EnemyStats enemyStats = GetOrAddComponent<EnemyStats>(go);
|
||||
EnemyMovement movement = GetOrAddComponent<EnemyMovement>(go);
|
||||
GetOrAddComponent<EnemyNavAgent>(go);
|
||||
GetOrAddComponent<NavAgent>(go);
|
||||
EnemySensorHub sensorHub = GetOrAddComponent<EnemySensorHub>(go);
|
||||
|
||||
Transform hurtBoxT = GetOrCreateChild(go.transform, "HurtBox");
|
||||
SetLayer(hurtBoxT.gameObject, "EnemyHurtBox", report);
|
||||
CapsuleCollider2D hurtCap = GetOrAddComponent<CapsuleCollider2D>(hurtBoxT.gameObject);
|
||||
hurtCap.isTrigger = true;
|
||||
hurtCap.size = new Vector2(0.65f, 0.95f);
|
||||
HurtBox hurtBox = GetOrAddComponent<HurtBox>(hurtBoxT.gameObject);
|
||||
|
||||
Transform contactT = GetOrCreateChild(go.transform, "ContactDamageZone");
|
||||
SetLayer(contactT.gameObject, "EnemyHitBox", report);
|
||||
CircleCollider2D contactCol = GetOrAddComponent<CircleCollider2D>(contactT.gameObject);
|
||||
contactCol.isTrigger = true;
|
||||
contactCol.radius = 0.4f;
|
||||
HitBox contactHitBox = GetOrAddComponent<HitBox>(contactT.gameObject);
|
||||
BodyContactDamage bodyContact = GetOrAddComponent<BodyContactDamage>(contactT.gameObject);
|
||||
|
||||
Transform landT = GetOrCreateChild(go.transform, "LandingHitBox");
|
||||
SetLayer(landT.gameObject, "EnemyHitBox", report);
|
||||
CircleCollider2D landCol = GetOrAddComponent<CircleCollider2D>(landT.gameObject);
|
||||
landCol.isTrigger = true;
|
||||
landCol.radius = 0.8f;
|
||||
HitBox landHitBox = GetOrAddComponent<HitBox>(landT.gameObject);
|
||||
landT.gameObject.SetActive(false);
|
||||
|
||||
Transform abilitiesT = GetOrCreateChild(go.transform, "Abilities");
|
||||
Transform leapT = GetOrCreateChild(abilitiesT, "LeapAttackAbility");
|
||||
LeapAttackAbility leapAbl = GetOrAddComponent<LeapAttackAbility>(leapT.gameObject);
|
||||
Transform chaseT = GetOrCreateChild(abilitiesT, "ContactChaseAbility");
|
||||
ContactChaseAbility chaseAbl = GetOrAddComponent<ContactChaseAbility>(chaseT.gameObject);
|
||||
|
||||
// SOs — assign first so OnValidate doesn't warn during wiring
|
||||
AssignAsset(enemyBase, "_statsSO", report, false, "ENM_E006_Stats");
|
||||
AssignAsset(enemyBase, "_animConfig", report, false, "ENM_E006_AnimConfig");
|
||||
|
||||
AssignReference(enemyBase, "_stats", enemyStats, report);
|
||||
AssignReference(enemyBase, "_movement", movement, report);
|
||||
AssignReference(enemyBase, "_animancer", animancer, report);
|
||||
AssignReference(enemyBase, "_hurtBox", hurtBox, report);
|
||||
AssignAsset(enemyBase, "_onEnemyDied", report, false, "EVT_EnemyDied");
|
||||
AssignAsset(enemyBase, "_onPlayerSpawned", report, false, "EVT_PlayerSpawned");
|
||||
AssignAsset(enemyStats, "_onDifficultyChanged", report, false, "EVT_DifficultyChanged");
|
||||
AssignAsset(hurtBox, "_onDamageDealt", report, false, "EVT_DamageDealt");
|
||||
AssignAsset(hurtBox, "_onHitConfirmed", report, false, "EVT_HitConfirmed");
|
||||
|
||||
AssignAsset(movement, "_config", report, false, "ENM_E006_Stats");
|
||||
AssignAsset(movement, "_animConfig", report, false, "ENM_E006_AnimConfig");
|
||||
AssignReference(movement, "_animancer", animancer, report);
|
||||
AssignReference(movement, "_spriteRenderer", sr6, report);
|
||||
|
||||
AssignAsset(leapAbl, "_config", report, false, "ABL_E006_Leap");
|
||||
AssignAsset(chaseAbl, "_config", report, false, "ABL_E006_Chase");
|
||||
|
||||
AssignReference(leapAbl, "_landingHitBox", landHitBox, report);
|
||||
AssignReference(chaseAbl, "_contactDamage", bodyContact, report);
|
||||
AssignReference(chaseAbl, "_sensorHub", sensorHub, report);
|
||||
|
||||
Object dmgSrc = FindFirstAsset("CMB_DS_EnemyBody");
|
||||
if (dmgSrc != null)
|
||||
{
|
||||
AssignReference(contactHitBox, "_defaultSource", dmgSrc, report);
|
||||
AssignReference(landHitBox, "_defaultSource", dmgSrc, report);
|
||||
}
|
||||
|
||||
SetupSensorHubSlotNames(sensorHub, new[] { "aggro", "wall_ahead", "ledge" }, report);
|
||||
report.Add("★ 挂载行为树 BehaviorTree 组件,指定 E006_Huan.asset。");
|
||||
|
||||
Undo.CollapseUndoOperations(undoGroup);
|
||||
Selection.activeGameObject = go;
|
||||
MarkDirtyAndLog("E006 讙", go, report);
|
||||
}
|
||||
|
||||
[MenuItem("BaseGames/Scene/Place/Boss 嘲风 (ChaoFeng)", priority = 117)]
|
||||
public static void PlaceChaoFeng()
|
||||
{
|
||||
var report = new List<string>();
|
||||
int undoGroup = Undo.GetCurrentGroup();
|
||||
Undo.SetCurrentGroupName("Place Boss 嘲风");
|
||||
|
||||
GameObject go = new GameObject("ENM_ChaoFeng");
|
||||
Undo.RegisterCreatedObjectUndo(go, "Place ChaoFeng");
|
||||
go.transform.position = GetDropPosition();
|
||||
SetLayer(go, "Enemy", report);
|
||||
|
||||
Rigidbody2D rb = GetOrAddComponent<Rigidbody2D>(go);
|
||||
rb.bodyType = RigidbodyType2D.Dynamic;
|
||||
rb.gravityScale = 2f;
|
||||
rb.constraints = RigidbodyConstraints2D.FreezeRotation;
|
||||
rb.collisionDetectionMode = CollisionDetectionMode2D.Continuous;
|
||||
rb.interpolation = RigidbodyInterpolation2D.Interpolate;
|
||||
|
||||
CapsuleCollider2D body = GetOrAddComponent<CapsuleCollider2D>(go);
|
||||
body.size = new Vector2(1.2f, 2.0f);
|
||||
|
||||
GetOrAddComponent<Animator>(go);
|
||||
AnimancerComponent animancer = GetOrAddComponent<AnimancerComponent>(go);
|
||||
SpriteRenderer srBoss = SetupSpriteRenderer(go);
|
||||
|
||||
ChaoFengBoss bossBase = GetOrAddComponent<ChaoFengBoss>(go);
|
||||
EnemyStats bossStats = GetOrAddComponent<EnemyStats>(go);
|
||||
EnemyFeedback feedback = GetOrAddComponent<EnemyFeedback>(go);
|
||||
EnemyMovement movement = GetOrAddComponent<EnemyMovement>(go);
|
||||
GetOrAddComponent<EnemyNavAgent>(go);
|
||||
GetOrAddComponent<NavAgent>(go);
|
||||
BossSkillExecutor skillExec = GetOrAddComponent<BossSkillExecutor>(go);
|
||||
ChaoFengFloatController floatCtrl = GetOrAddComponent<ChaoFengFloatController>(go);
|
||||
ChaoFengKnockdownCounter knockdown = GetOrAddComponent<ChaoFengKnockdownCounter>(go);
|
||||
EnemySensorHub sensorHub = GetOrAddComponent<EnemySensorHub>(go);
|
||||
|
||||
// HurtBox
|
||||
Transform hurtBoxT = GetOrCreateChild(go.transform, "HurtBox");
|
||||
SetLayer(hurtBoxT.gameObject, "EnemyHurtBox", report);
|
||||
CapsuleCollider2D hurtCap = GetOrAddComponent<CapsuleCollider2D>(hurtBoxT.gameObject);
|
||||
hurtCap.isTrigger = true;
|
||||
hurtCap.size = new Vector2(1.1f, 1.9f);
|
||||
HurtBox hurtBox = GetOrAddComponent<HurtBox>(hurtBoxT.gameObject);
|
||||
|
||||
// Phase1 attack hitboxes (disabled by default; abilities enable/disable as needed)
|
||||
HitBox biteHB = CreateDisabledHitBox(go.transform, "Phase1_BiteHitBox", "EnemyHitBox",
|
||||
true, report, size: new Vector2(0.8f, 0.5f));
|
||||
HitBox swipeR = CreateDisabledHitBox(go.transform, "Phase1_SwipeHitBox_R","EnemyHitBox",
|
||||
true, report, size: new Vector2(1.2f, 0.4f));
|
||||
HitBox swipeL = CreateDisabledHitBox(go.transform, "Phase1_SwipeHitBox_L","EnemyHitBox",
|
||||
true, report, size: new Vector2(1.2f, 0.4f));
|
||||
HitBox stompHB = CreateDisabledHitBox(go.transform, "Phase1_StompHitBox", "EnemyHitBox",
|
||||
false, report, radius: 1.0f);
|
||||
|
||||
// Muzzle transforms for Phase 2 skills
|
||||
GetOrCreateChild(go.transform, "WindBladeMuzzle");
|
||||
GetOrCreateChild(go.transform, "TornadoMuzzle");
|
||||
GetOrCreateChild(go.transform, "SummonSpawnPoint");
|
||||
|
||||
// SOs — assign first so OnValidate doesn't warn during wiring
|
||||
AssignAsset(bossBase, "_statsSO", report, false, "ENM_ChaoFeng_Stats");
|
||||
AssignAsset(bossBase, "_animConfig", report, false, "ENM_ChaoFeng_AnimConfig");
|
||||
|
||||
// Component wiring
|
||||
AssignReference(bossBase, "_stats", bossStats, report);
|
||||
AssignReference(bossBase, "_movement", movement, report);
|
||||
AssignReference(bossBase, "_animancer", animancer, report);
|
||||
AssignReference(bossBase, "_feedback", feedback, report);
|
||||
AssignReference(bossBase, "_hurtBox", hurtBox, report);
|
||||
AssignReference(skillExec, "_animancer", animancer, report);
|
||||
|
||||
AssignAsset(bossBase, "_onEnemyDied", report, false, "EVT_EnemyDied");
|
||||
AssignAsset(bossBase, "_onPlayerSpawned", report, false, "EVT_PlayerSpawned");
|
||||
AssignAsset(bossBase, "_onBossFightEnded", report, false, "EVT_BossFightEnded");
|
||||
AssignAsset(bossBase, "_onBossPhaseChanged", report, false, "EVT_BossPhaseChanged");
|
||||
AssignAsset(bossStats, "_onDifficultyChanged",report, false, "EVT_DifficultyChanged");
|
||||
AssignAsset(hurtBox, "_onDamageDealt", report, false, "EVT_DamageDealt");
|
||||
AssignAsset(hurtBox, "_onHitConfirmed", report, false, "EVT_HitConfirmed");
|
||||
|
||||
AssignAsset(movement, "_config", report, false, "ENM_ChaoFeng_Stats");
|
||||
AssignAsset(movement, "_animConfig", report, false, "ENM_ChaoFeng_AnimConfig");
|
||||
AssignReference(movement, "_animancer", animancer, report);
|
||||
AssignReference(movement, "_spriteRenderer", srBoss, report);
|
||||
|
||||
// Collect BossSkillSOs and assign to executor
|
||||
var skillAssets = new System.Collections.Generic.List<Object>();
|
||||
foreach (var n in new[] { "ABL_ChaoFeng_Idle", "ABL_ChaoFeng_Slam", "ABL_ChaoFeng_Sweep",
|
||||
"ABL_ChaoFeng_WindBlade", "ABL_ChaoFeng_Summon" })
|
||||
{
|
||||
Object sk = FindFirstAsset(n);
|
||||
if (sk != null) skillAssets.Add(sk);
|
||||
else report.Add($"未找到 BossSkillSO:{n},请先一键创建 SO 后再重新运行此放置操作。");
|
||||
}
|
||||
if (skillAssets.Count > 0)
|
||||
AssignObjectArray(skillExec, "_skills", skillAssets.ToArray(), report);
|
||||
|
||||
Object dmgSrc = FindFirstAsset("CMB_DS_BossBody", "CMB_DS_EnemyBody");
|
||||
if (dmgSrc != null)
|
||||
{
|
||||
foreach (var hb in new[] { biteHB, swipeR, swipeL, stompHB })
|
||||
if (hb != null) AssignReference(hb, "_defaultSource", dmgSrc, report);
|
||||
}
|
||||
|
||||
SetupSensorHubSlotNames(sensorHub, new[] { "aggro", "attack_melee", "attack_range", "los" }, report);
|
||||
|
||||
report.Add("★ 设置 BossSkillExecutor._bossId = \"ChaoFeng\"。");
|
||||
report.Add("★ 将各 Phase1 HitBox 引用拖入 BossSkillExecutor._hitBoxes 数组。");
|
||||
report.Add("★ 将 WindBladeMuzzle / TornadoMuzzle / SummonSpawnPoint 拖入对应 BossSkillSO 字段。");
|
||||
report.Add("★ 挂载行为树 BehaviorTree 组件,指定 Boss_ChaoFeng.asset。");
|
||||
|
||||
Undo.CollapseUndoOperations(undoGroup);
|
||||
Selection.activeGameObject = go;
|
||||
MarkDirtyAndLog("Boss 嘲风 (ChaoFeng)", go, report);
|
||||
}
|
||||
|
||||
// ══ 敌人放置辅助方法 ═══════════════════════════════════════════════════
|
||||
|
||||
/// <summary>
|
||||
/// 创建禁用的 HitBox 子节点(Box 或 Circle 碰撞体)。
|
||||
/// </summary>
|
||||
private static HitBox CreateDisabledHitBox(Transform parent, string childName, string layer,
|
||||
bool isBox, List<string> report,
|
||||
Vector2 size = default, float radius = 0.5f)
|
||||
{
|
||||
Transform t = GetOrCreateChild(parent, childName);
|
||||
SetLayer(t.gameObject, layer, report);
|
||||
if (isBox)
|
||||
{
|
||||
BoxCollider2D col = GetOrAddComponent<BoxCollider2D>(t.gameObject);
|
||||
col.isTrigger = true;
|
||||
col.size = size == default ? new Vector2(0.5f, 0.5f) : size;
|
||||
}
|
||||
else
|
||||
{
|
||||
CircleCollider2D col = GetOrAddComponent<CircleCollider2D>(t.gameObject);
|
||||
col.isTrigger = true;
|
||||
col.radius = radius;
|
||||
}
|
||||
HitBox hb = GetOrAddComponent<HitBox>(t.gameObject);
|
||||
t.gameObject.SetActive(false);
|
||||
return hb;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置 EnemySensorHub._slots 的 slotName 字段(Sensor 引用需在 Inspector 中手工绑定)。
|
||||
/// </summary>
|
||||
private static void SetupSensorHubSlotNames(EnemySensorHub hub, string[] slotNames, List<string> report)
|
||||
{
|
||||
var so = new SerializedObject(hub);
|
||||
var slots = so.FindProperty("_slots");
|
||||
if (slots == null || !slots.isArray)
|
||||
{
|
||||
report?.Add("EnemySensorHub._slots 字段未找到,传感器槽位需手工配置。");
|
||||
return;
|
||||
}
|
||||
slots.arraySize = slotNames.Length;
|
||||
for (int i = 0; i < slotNames.Length; i++)
|
||||
slots.GetArrayElementAtIndex(i).FindPropertyRelative("slotName").stringValue = slotNames[i];
|
||||
so.ApplyModifiedPropertiesWithoutUndo();
|
||||
}
|
||||
|
||||
[MenuItem("BaseGames/Scene/Place/Hazard (LethalTrap)", priority = 120)]
|
||||
public static void PlaceLethalTrap()
|
||||
{
|
||||
@@ -1084,6 +1824,30 @@ namespace BaseGames.Editor
|
||||
so.ApplyModifiedPropertiesWithoutUndo();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 为 MeleeAttackAbility._hitBoxSlots 赋值(struct 数组 {slotName, hitBox})。
|
||||
/// </summary>
|
||||
private static void AssignMeleeHitBoxSlots(MeleeAttackAbility ability, (string slot, HitBox hb)[] slots, List<string> report)
|
||||
{
|
||||
if (ability == null) return;
|
||||
var so = new SerializedObject(ability);
|
||||
var prop = so.FindProperty("_hitBoxSlots");
|
||||
if (prop == null || !prop.isArray)
|
||||
{
|
||||
report?.Add($"[WARN] MeleeAttackAbility._hitBoxSlots 属性未找到,请检查字段名。");
|
||||
return;
|
||||
}
|
||||
prop.arraySize = slots.Length;
|
||||
for (int i = 0; i < slots.Length; i++)
|
||||
{
|
||||
var elem = prop.GetArrayElementAtIndex(i);
|
||||
elem.FindPropertyRelative("slotName").stringValue = slots[i].slot;
|
||||
elem.FindPropertyRelative("hitBox").objectReferenceValue = slots[i].hb;
|
||||
}
|
||||
so.ApplyModifiedPropertiesWithoutUndo();
|
||||
report?.Add($"[OK] MeleeAttackAbility._hitBoxSlots 已配置 {slots.Length} 个槽位。");
|
||||
}
|
||||
|
||||
private static Object FindFirstAsset(params string[] candidates)
|
||||
{
|
||||
foreach (string candidate in candidates)
|
||||
|
||||
Reference in New Issue
Block a user