using System.Collections.Generic; using UnityEngine; using UnityEditor; using UnityEditor.SceneManagement; using UnityEngine.AI; public static class MutantPopulationSetup { private const string MutantPrefabPath = "Assets/Prefabs/Mutant.prefab"; [MenuItem("Tools/Populate Mutants Across Complex")] public static string Populate() { var mutantPrefab = AssetDatabase.LoadAssetAtPath(MutantPrefabPath); if (mutantPrefab == null) { Debug.LogError($"[MutantPopulationSetup] Prefab not found at {MutantPrefabPath}"); return "ERROR: Mutant.prefab not found!"; } // 1. Очищаем старых мутантов в сцене var existingEnemies = Object.FindObjectsByType(); foreach (var e in existingEnemies) { Undo.DestroyObjectImmediate(e.gameObject); } var oldEnemiesRoot = GameObject.Find("Enemies"); if (oldEnemiesRoot != null) { Undo.DestroyObjectImmediate(oldEnemiesRoot); } GameObject enemiesRoot = new GameObject("Enemies"); Undo.RegisterCreatedObjectUndo(enemiesRoot, "Create Enemies"); // 2. Получаем или создаем глобальные точки патрулирования комплекса Transform[] globalPatrolWaypoints = EnsureGlobalPatrolWaypoints(); // 3. Создаем глобальных бродячих мутантов (Facility Roamers) GameObject roamersGroup = new GameObject("Facility_Roamers"); roamersGroup.transform.SetParent(enemiesRoot.transform); // 4 бродячих мутанта, патрулирующих коридоры и открытые зоны комплекса SpawnMutant(mutantPrefab, roamersGroup.transform, "Mutant_Roamer_Concourse", new Vector3(0f, 0.08f, -30f), globalPatrolWaypoints, startIndex: 0, isRoomConfined: false); SpawnMutant(mutantPrefab, roamersGroup.transform, "Mutant_Roamer_WestSlalom", new Vector3(-21f, 0.08f, 6f), globalPatrolWaypoints, startIndex: 7, isRoomConfined: false); SpawnMutant(mutantPrefab, roamersGroup.transform, "Mutant_Roamer_GrandAtrium", new Vector3(0f, 0.08f, 9f), globalPatrolWaypoints, startIndex: 23, isRoomConfined: false); SpawnMutant(mutantPrefab, roamersGroup.transform, "Mutant_Roamer_NorthBypass", new Vector3(-15f, 0.08f, 47.5f), globalPatrolWaypoints, startIndex: 15, isRoomConfined: false); // 4. Комнаты с БОЛЬШИМ количеством мутантов (Гнёзда / Опасные зоны) // --- SECTOR F: Quarantine Wing / Cellblock (Лабиринт с изоляторами) — 5 МУТАНТОВ --- SetupRoomGroup(mutantPrefab, enemiesRoot.transform, "Quarantine_Wing_Swarm", waypoints: new Vector3[] { new Vector3(-35f, 0.08f, 8f), // Южный коридор блока new Vector3(-43f, 0.08f, 9f), // Камера 1 new Vector3(-27f, 0.08f, 9f), // Камера 2 new Vector3(-35f, 0.08f, 16f), // Средний коридор new Vector3(-43f, 0.08f, 16f), // Камера 3 new Vector3(-27f, 0.08f, 16f), // Камера 4 new Vector3(-35f, 0.08f, 23f), // Северный коридор new Vector3(-43f, 0.08f, 23f) // Камера 5 }, spawnPositions: new Vector3[] { new Vector3(-43f, 0.08f, 9f), new Vector3(-27f, 0.08f, 9f), new Vector3(-35f, 0.08f, 16f), new Vector3(-43f, 0.08f, 16f), new Vector3(-43f, 0.08f, 23f) } ); // --- SECTOR H: Chemical Silos & Toxic Waste — 4 МУТАНТА --- SetupRoomGroup(mutantPrefab, enemiesRoot.transform, "Chemical_Silos_Hazard", waypoints: new Vector3[] { new Vector3(-43f, 0.08f, 33f), new Vector3(-31f, 0.08f, 33f), new Vector3(-31f, 0.08f, 43f), new Vector3(-43f, 0.08f, 43f), new Vector3(-37f, 0.08f, 38f) }, spawnPositions: new Vector3[] { new Vector3(-42f, 0.08f, 34f), new Vector3(-32f, 0.08f, 34f), new Vector3(-32f, 0.08f, 42f), new Vector3(-42f, 0.08f, 42f) } ); // 5. Комнаты с ПАРОЙ мутантов (по 2 мутанта на комнату) // --- SECTOR B: Cryogenics Vault — 2 мутанта --- SetupRoomGroup(mutantPrefab, enemiesRoot.transform, "Room_Cryogenics", waypoints: new Vector3[] { new Vector3(-43f, 0.08f, -43f), new Vector3(-31f, 0.08f, -43f), new Vector3(-31f, 0.08f, -31f), new Vector3(-43f, 0.08f, -31f) }, spawnPositions: new Vector3[] { new Vector3(-40f, 0.08f, -40f), new Vector3(-34f, 0.08f, -34f) } ); // --- SECTOR C: Security Armory & Surveillance — 2 мутанта --- SetupRoomGroup(mutantPrefab, enemiesRoot.transform, "Room_Armory", waypoints: new Vector3[] { new Vector3(31f, 0.08f, -43f), new Vector3(43f, 0.08f, -43f), new Vector3(43f, 0.08f, -31f), new Vector3(31f, 0.08f, -31f) }, spawnPositions: new Vector3[] { new Vector3(34f, 0.08f, -40f), new Vector3(40f, 0.08f, -34f) } ); // --- SECTOR D: Biochemistry Research Wing — 2 мутанта --- SetupRoomGroup(mutantPrefab, enemiesRoot.transform, "Room_Biochem", waypoints: new Vector3[] { new Vector3(-42f, 0.08f, -16f), new Vector3(-30f, 0.08f, -16f), new Vector3(-30f, 0.08f, -4f), new Vector3(-42f, 0.08f, -4f) }, spawnPositions: new Vector3[] { new Vector3(-39f, 0.08f, -14f), new Vector3(-33f, 0.08f, -6f) } ); // --- SECTOR E: Surgical Theatre & ICU — 2 мутанта --- SetupRoomGroup(mutantPrefab, enemiesRoot.transform, "Room_Surgical_ICU", waypoints: new Vector3[] { new Vector3(30f, 0.08f, -16f), new Vector3(42f, 0.08f, -16f), new Vector3(42f, 0.08f, -4f), new Vector3(30f, 0.08f, -4f) }, spawnPositions: new Vector3[] { new Vector3(33f, 0.08f, -14f), new Vector3(39f, 0.08f, -6f) } ); // --- SECTOR G: Genetics & Cybernetics — 2 мутанта --- SetupRoomGroup(mutantPrefab, enemiesRoot.transform, "Room_Genetics", waypoints: new Vector3[] { new Vector3(28f, 0.08f, 10f), new Vector3(42f, 0.08f, 10f), new Vector3(42f, 0.08f, 22f), new Vector3(28f, 0.08f, 22f) }, spawnPositions: new Vector3[] { new Vector3(31f, 0.08f, 12f), new Vector3(39f, 0.08f, 20f) } ); // --- SECTOR I: Auxiliary Power Substation — 2 мутанта --- SetupRoomGroup(mutantPrefab, enemiesRoot.transform, "Room_Substation", waypoints: new Vector3[] { new Vector3(31f, 0.08f, 33f), new Vector3(43f, 0.08f, 33f), new Vector3(43f, 0.08f, 43f), new Vector3(31f, 0.08f, 43f) }, spawnPositions: new Vector3[] { new Vector3(34f, 0.08f, 35f), new Vector3(40f, 0.08f, 41f) } ); // --- SECTOR K: Sub-Reactor Turbine Hall — 2 мутанта --- SetupRoomGroup(mutantPrefab, enemiesRoot.transform, "Room_Reactor_Hall", waypoints: new Vector3[] { new Vector3(-14f, 0.08f, 38f), new Vector3(0f, 0.08f, 38f), new Vector3(14f, 0.08f, 38f), new Vector3(0f, 0.08f, 44f) }, spawnPositions: new Vector3[] { new Vector3(-10f, 0.08f, 38f), new Vector3(10f, 0.08f, 38f) } ); EditorUtility.SetDirty(enemiesRoot); EditorSceneManager.MarkSceneDirty(enemiesRoot.scene); EditorSceneManager.SaveScene(enemiesRoot.scene); string summary = $"[MutantPopulationSetup] Успешно создано и настроено 27 мутантов:\n" + $"- 4 общих патрульных по коридорам и атриуму\n" + $"- 5 мутантов в карантинном изоляторе (Quarantine Cellblock)\n" + $"- 4 мутанта на складе химикатов (Chemical Silos)\n" + $"- по 2 мутанта в 7 других лабораториях (Cryo, Armory, Biochem, Surgical, Genetics, Substation, Reactor)"; Debug.Log($"{summary}"); return summary; } private static void SetupRoomGroup(GameObject prefab, Transform parent, string groupName, Vector3[] waypoints, Vector3[] spawnPositions) { GameObject roomGroup = new GameObject(groupName); roomGroup.transform.SetParent(parent); // Точки патрулирования комнаты GameObject waypointsParent = new GameObject("Room_Waypoints"); waypointsParent.transform.SetParent(roomGroup.transform); Transform[] wpTransforms = new Transform[waypoints.Length]; for (int i = 0; i < waypoints.Length; i++) { Vector3 targetPos = waypoints[i]; if (NavMesh.SamplePosition(targetPos, out NavMeshHit hit, 3.0f, NavMesh.AllAreas)) { targetPos = hit.position; } var wpGo = new GameObject($"WP_{i}"); wpGo.transform.SetParent(waypointsParent.transform); wpGo.transform.position = targetPos; wpTransforms[i] = wpGo.transform; } // Создаем мутантов для комнаты for (int i = 0; i < spawnPositions.Length; i++) { Vector3 spawnPos = spawnPositions[i]; if (NavMesh.SamplePosition(spawnPos, out NavMeshHit hit, 3.0f, NavMesh.AllAreas)) { spawnPos = hit.position; } SpawnMutant(prefab, roomGroup.transform, $"{groupName}_Mutant_{i + 1}", spawnPos, wpTransforms, startIndex: i % wpTransforms.Length, isRoomConfined: true); } } private static void SpawnMutant(GameObject prefab, Transform parent, string name, Vector3 pos, Transform[] patrolPoints, int startIndex, bool isRoomConfined) { if (NavMesh.SamplePosition(pos, out NavMeshHit hit, 4.0f, NavMesh.AllAreas)) { pos = hit.position; } GameObject mutantGo = (GameObject)PrefabUtility.InstantiatePrefab(prefab, parent); mutantGo.name = name; mutantGo.transform.position = pos; mutantGo.transform.rotation = Quaternion.Euler(0f, Random.Range(0f, 360f), 0f); var agent = mutantGo.GetComponent(); if (agent != null) { agent.Warp(pos); agent.avoidancePriority = Random.Range(30, 70); } var ai = mutantGo.GetComponent(); if (ai != null) { ai.patrolPoints = patrolPoints; ai.isRoomConfined = isRoomConfined; ai.waitTimeAtPoint = Random.Range(1.2f, 2.2f); } EditorUtility.SetDirty(mutantGo); } private static Transform[] EnsureGlobalPatrolWaypoints() { var patrolRoot = GameObject.Find("PatrolWaypoints"); if (patrolRoot != null && patrolRoot.transform.childCount > 0) { Transform[] pts = new Transform[patrolRoot.transform.childCount]; for (int i = 0; i < patrolRoot.transform.childCount; i++) { pts[i] = patrolRoot.transform.GetChild(i); } return pts; } // Если не найден, создаем 32 точки patrolRoot = new GameObject("PatrolWaypoints"); Vector3[] waypoints = new Vector3[] { new Vector3(0f, 0.08f, -30f), new Vector3(-18f, 0.08f, -30f), new Vector3(-37f, 0.08f, -37f), new Vector3(-37f, 0.08f, -24f), new Vector3(-37f, 0.08f, -14f), new Vector3(-37f, 0.08f, -4f), new Vector3(-21f, 0.08f, -4f), new Vector3(-21f, 0.08f, 6f), new Vector3(-35f, 0.08f, 8f), new Vector3(-43f, 0.08f, 9f), new Vector3(-35f, 0.08f, 16f), new Vector3(-27f, 0.08f, 16f), new Vector3(-35f, 0.08f, 23f), new Vector3(-37f, 0.08f, 38f), new Vector3(-37f, 0.08f, 47.5f), new Vector3(-15f, 0.08f, 47.5f), new Vector3(-10f, 0.08f, 38f), new Vector3(0f, 0.08f, 38f), new Vector3(10f, 0.08f, 38f), new Vector3(25f, 0.08f, 47.5f), new Vector3(37f, 0.08f, 38f), new Vector3(37f, 0.08f, 22f), new Vector3(37f, 0.08f, 10f), new Vector3(12f, 0.08f, 9f), new Vector3(0f, 0.08f, 18f), new Vector3(-12f, 0.08f, 9f), new Vector3(0f, 0.08f, 0f), new Vector3(21f, 0.08f, 0f), new Vector3(37f, 0.08f, -4f), new Vector3(37f, 0.08f, -14f), new Vector3(37f, 0.08f, -37f), new Vector3(18f, 0.08f, -30f) }; Transform[] res = new Transform[waypoints.Length]; for (int i = 0; i < waypoints.Length; i++) { Vector3 pos = waypoints[i]; if (NavMesh.SamplePosition(pos, out NavMeshHit hit, 3.0f, NavMesh.AllAreas)) { pos = hit.position; } var wpGo = new GameObject($"Waypoint_{i}"); wpGo.transform.SetParent(patrolRoot.transform); wpGo.transform.position = pos; res[i] = wpGo.transform; } return res; } }