using System.Collections.Generic; using UnityEngine; /// /// 红方城堡自动出兵 AI:独立能量、三路目标评估、低费试探与高费推进。 /// public class EnemyCastleAI : MonoBehaviour { [Header("AI 阵营")] [SerializeField] private int teamId = 1; [SerializeField] private int maxMana = 10; [SerializeField] private float manaRegenInterval = 3f; [SerializeField] private float decisionInterval = 1.2f; [SerializeField] private float minimumSpawnInterval = 1.4f; [Header("三路目标")] [SerializeField] private float leftLaneX = -10f; [SerializeField] private float centerLaneX = 0f; [SerializeField] private float rightLaneX = 10f; [SerializeField] private float laneHalfWidth = 4f; [SerializeField] private float resourceThreatWeight = 2.5f; [SerializeField] private float enemyUnitWeight = 1.5f; [SerializeField] private float laneRotationWeight = 0.7f; [Header("卡组")] [SerializeField] private CharacterData[] deck; private Transform redSpawnPoint; private AttackTargetController targetController; private float currentMana; private float manaTimer; private float decisionTimer; private float spawnTimer; private int lastLane = 1; private int consecutiveLaneSpawns; private bool initialized; private void Start() { redSpawnPoint = FindRedSpawnPoint(); targetController = AttackTargetController.Instance; currentMana = maxMana; if (deck == null || deck.Length == 0) deck = Resources.LoadAll("Data"); initialized = redSpawnPoint != null && deck != null && deck.Length > 0; if (!initialized) Debug.LogWarning("EnemyCastleAI 初始化失败:缺少红方出兵点或角色卡组。"); } private void Update() { if (!initialized) return; manaTimer += Time.deltaTime; while (manaTimer >= manaRegenInterval) { manaTimer -= manaRegenInterval; currentMana = Mathf.Min(maxMana, currentMana + 1f); } decisionTimer -= Time.deltaTime; spawnTimer -= Time.deltaTime; if (decisionTimer > 0f || spawnTimer > 0f) return; decisionTimer = decisionInterval; int lane = ChooseLane(); CharacterData card = ChooseCard(lane); if (card == null || card.manaCost > currentMana) return; if (Spawn(card, lane)) { currentMana -= card.manaCost; spawnTimer = minimumSpawnInterval; if (lane == lastLane) consecutiveLaneSpawns++; else consecutiveLaneSpawns = 1; lastLane = lane; } } private int ChooseLane() { float left = ScoreLane(leftLaneX, 0); float center = ScoreLane(centerLaneX, 1); float right = ScoreLane(rightLaneX, 2); if (consecutiveLaneSpawns >= 2) { if (lastLane == 0) left -= 3f; if (lastLane == 1) center -= 3f; if (lastLane == 2) right -= 3f; } float best = Mathf.Max(left, Mathf.Max(center, right)); if (Mathf.Approximately(best, left)) return 0; if (Mathf.Approximately(best, right)) return 2; return 1; } private float ScoreLane(float laneX, int lane) { float score = 1f; score += lane == 1 ? 0.8f : 0f; score += lane == lastLane ? laneRotationWeight : 0f; foreach (var unit in FindObjectsOfType()) { if (unit == null || unit.teamId != 0) continue; Vector3 p = unit.transform.position; if (Mathf.Abs(p.x - laneX) <= laneHalfWidth) score += enemyUnitWeight; } foreach (var mine in FindObjectsOfType()) { if (mine == null) continue; Vector3 p = mine.transform.position; if (Mathf.Abs(p.x - laneX) > laneHalfWidth * 1.8f) continue; UnitTeam team = mine.GetComponent(); if (team == null || team.teamId != teamId) score += resourceThreatWeight; } return score; } private CharacterData ChooseCard(int lane) { CharacterData best = null; float bestScore = float.NegativeInfinity; foreach (var card in deck) { if (card == null || card.unitPrefab == null || card.manaCost > currentMana) continue; float score = Random.Range(0f, 1f); if (card.manaCost <= 2) score += 2f; if (currentMana >= 7 && card.manaCost >= 5) score += 2f; if (lane != 1 && card.manaCost <= 4) score += 0.5f; if (score > bestScore) { bestScore = score; best = card; } } return best; } private bool Spawn(CharacterData data, int lane) { GameObject unit = Instantiate(data.unitPrefab, redSpawnPoint.position, redSpawnPoint.rotation); UnitTeam team = unit.GetComponent(); if (team != null) team.teamId = teamId; unit.tag = "Enemy"; UnitBase unitBase = unit.GetComponent(); if (unitBase != null) { unitBase.InitializeFromPlayerData(data.GetMaxHealth(1), data.GetAttackPower(1), data.GetMoveSpeed(1)); } if (targetController != null) { targetController.redTarget = FindLaneTarget(lane); } return true; } private GameObject FindLaneTarget(int lane) { float x = lane == 0 ? leftLaneX : lane == 2 ? rightLaneX : centerLaneX; GameObject best = null; float bestDistance = float.PositiveInfinity; foreach (var mine in FindObjectsOfType()) { if (Mathf.Abs(mine.transform.position.x - x) < laneHalfWidth * 2f) { float d = Mathf.Abs(mine.transform.position.z - redSpawnPoint.position.z); if (d < bestDistance) { bestDistance = d; best = mine.gameObject; } } } return best != null ? best : targetController?.GetEnemyCastleOfTeam(teamId); } private Transform FindRedSpawnPoint() { var manager = GetComponent(); if (manager != null && manager.redSpawnPoint != null) return manager.redSpawnPoint; var castles = GameObject.Find("红色城堡"); return castles != null ? castles.transform.Find("出兵点") : null; } }