using System.Collections.Generic; using System.Linq; using UnityEngine; /// /// 战斗场景的出战生成:开战前按阵型数据在对应格位生成英雄。 /// 优先使用阵型编排场景保存的数据;没有编排数据时按名单使用默认阵型(近战前排 / 远程后排)。 /// public class BattleFormationSpawner : MonoBehaviour { [Header("出战英雄名单(没有编排数据时的默认来源)")] public HeroRoster roster; [Header("生成到哪个父节点(留空则放在场景根)")] public Transform heroParent; [Header("玩家阵营 ID")] public int playerTeamId = 0; private void Start() { spawnedHeroCount = 0; // 重置计数器 SpawnHeroes(); } private void SpawnHeroes() { // 1. 优先从 PlayerData.json 读取保存的阵型 if (PlayerDataManager.Instance != null) { SavedFormationData formationData = PlayerDataManager.Instance.LoadFormation(); if (formationData != null && formationData.characterIds != null && formationData.characterIds.Length > 0) { Debug.Log($"从 PlayerData.json 加载阵型,共 {formationData.characterIds.Length} 个英雄"); SpawnFromSavedFormation(formationData); return; } } // 2. 回退到 FormationData(场景间临时传递的数据) if (FormationData.HasCustomFormation && FormationData.HeroPrefabs != null && FormationData.HeroPrefabs.Length > 0) { for (int i = 0; i < FormationData.HeroPrefabs.Length; i++) { int cell = i < FormationData.CellIndices.Length ? FormationData.CellIndices[i] : -1; if (FormationData.HeroPrefabs[i] == null || !DeployGrid.IsValidIndex(cell)) { continue; } Spawn(FormationData.HeroPrefabs[i], cell); } return; } // 3. 没有任何编排数据:使用默认阵型 SpawnDefaultFormation(); } /// /// 从保存的阵型数据生成英雄 /// private void SpawnFromSavedFormation(SavedFormationData formationData) { for (int i = 0; i < formationData.characterIds.Length; i++) { string characterId = formationData.characterIds[i]; int cell = i < formationData.cellIndices.Length ? formationData.cellIndices[i] : -1; if (string.IsNullOrEmpty(characterId) || !DeployGrid.IsValidIndex(cell)) { continue; } // 根据 characterId 找到对应的 Prefab GameObject prefab = FindPrefabByCharacterId(characterId); if (prefab != null) { Spawn(prefab, cell); } else { Debug.LogWarning($"未找到 characterId={characterId} 对应的 Prefab"); } } } /// /// 根据 characterId 查找对应的 Prefab /// private GameObject FindPrefabByCharacterId(string characterId) { var allData = Resources.LoadAll("Data"); foreach (var data in allData) { if (data.characterId == characterId) { return data.unitPrefab; } } return null; } private void SpawnDefaultFormation() { if (roster == null || roster.heroes == null) return; int meleeTotal = 0, rangedTotal = 0; foreach (HeroEntry entry in roster.heroes) { if (entry == null) continue; if (entry.isMelee) meleeTotal++; else rangedTotal++; } var used = new HashSet(); int meleeIndex = 0, rangedIndex = 0; foreach (HeroEntry entry in roster.heroes) { if (entry == null || entry.prefab == null) continue; int cell = entry.isMelee ? DeployGrid.DefaultCell(true, meleeIndex++, meleeTotal) : DeployGrid.DefaultCell(false, rangedIndex++, rangedTotal); if (used.Contains(cell)) { cell = NextFreeCell(cell, used); } if (cell < 0) continue; used.Add(cell); Spawn(entry.prefab, cell); } } private static int NextFreeCell(int from, HashSet used) { for (int i = 0; i < DeployGrid.CellCount; i++) { int candidate = (from + i) % DeployGrid.CellCount; if (!used.Contains(candidate)) return candidate; } return -1; } private int spawnedHeroCount = 0; // 记录已生成英雄数量(改为实例变量) private void Spawn(GameObject prefab, int cell) { CharacterData characterData = FindCharacterDataForPrefab(prefab); Vector3 spawnPos = DeployGrid.CellPosition(cell); GameObject unit = Instantiate(prefab, spawnPos, Quaternion.identity); unit.name = "英雄_" + prefab.name; if (heroParent != null) { unit.transform.SetParent(heroParent, true); } UnitTeam team = unit.GetComponent(); if (team != null) { team.teamId = playerTeamId; } UnitBase unitBase = unit.GetComponent(); if (unitBase != null) { unitBase.returnToAnchorWhenIdle = true; unitBase.anchorArrivalDistance = 0.35f; } if (characterData != null && unitBase != null) { PlayerCharacterData playerData = PlayerDataManager.Instance != null ? PlayerDataManager.Instance.GetCharacterData(characterData.characterId) : null; int level = playerData != null ? playerData.level : 1; unitBase.InitializeFromPlayerData( characterData.GetMaxHealth(level), characterData.GetAttackPower(level), characterData.GetMoveSpeed(level), level); } // 设置友方英雄可复活 WorldHealthBar healthBar = unit.GetComponent(); if (healthBar != null && playerTeamId == 0) { healthBar.canRevive = true; } // 绑定到英雄卡片UI BindHeroToCard(unit, characterData, spawnPos); } private void BindHeroToCard(GameObject heroUnit, CharacterData characterData, Vector3 spawnPos) { if (spawnedHeroCount >= 5) { Debug.LogWarning($"已达到最大英雄数量5,跳过绑定 {heroUnit.name}"); return; // 最多5个英雄 } // 查找 TowerDefenseCanvas GameObject canvasObj = GameObject.Find("TowerDefenseCanvas"); if (canvasObj == null) { Debug.LogError("BindHeroToCard: 未找到 TowerDefenseCanvas"); return; } Transform heroPanel = canvasObj.transform.Find("BottomUI/HeroCardsPanel"); if (heroPanel == null) { Debug.LogError("BindHeroToCard: 未找到 BottomUI/HeroCardsPanel"); return; } string cardName = $"HeroCard{spawnedHeroCount + 1}"; Transform cardObj = heroPanel.Find(cardName); if (cardObj == null) { Debug.LogError($"BindHeroToCard: 未找到 {cardName}"); return; } HeroCardUI heroCardUI = cardObj.GetComponent(); if (heroCardUI == null) { Debug.LogError($"BindHeroToCard: {cardName} 缺少 HeroCardUI 组件"); return; } // 获取英雄单位组件 UnitBase unitBase = heroUnit.GetComponent(); if (unitBase == null) { Debug.LogError($"BindHeroToCard: {heroUnit.name} 缺少 UnitBase 组件"); return; } // 加载对应的头像 UnityEngine.Sprite icon = characterData != null ? characterData.cardIcon : null; // 绑定英雄到卡片 heroCardUI.SetHero(unitBase, icon, spawnPos, characterData); spawnedHeroCount++; Debug.Log($"✅ {cardName} 已绑定英雄: {heroUnit.name}(第 {spawnedHeroCount} 个)"); } private CharacterData FindCharacterDataForPrefab(GameObject prefab) { if (prefab == null) return null; return Resources.LoadAll("Data") .FirstOrDefault(data => data != null && data.unitPrefab == prefab); } }