using UnityEngine; using UnityEditor; using UnityEditor.SceneManagement; using UnityEngine.UI; using Unity.AI.Navigation; using UnityEngine.AI; public static class Level2SceneBuilder { [MenuItem("Tools/Synthesia/Build Level 2 (SubLevel Complex)")] public static void BuildLevel2Scene() { Debug.Log("[Level 2] Начало сборки 2-го уровня..."); // 1. Открываем SampleScene как шаблон string samplePath = "Assets/Scenes/SampleScene.unity"; string level2Path = "Assets/Scenes/Level2.unity"; var scene = EditorSceneManager.OpenScene(samplePath, OpenSceneMode.Single); // 2. Сохраняем сцену под новым именем Level2.unity bool savedAs = EditorSceneManager.SaveScene(scene, level2Path); if (!savedAs) { Debug.LogError("[Level 2] Не удалось сохранить сцену как Level2.unity!"); return; } scene = EditorSceneManager.OpenScene(level2Path, OpenSceneMode.Single); // 3. Очищаем объекты 1-го уровня string[] toRemove = new string[] { "Laboratory_Complex", "Cosmic_Retro_Laboratory", "Elevator_Level2_Zone", "StoryNotes_Container", "Enemies", "StoryManager", "SubLevel2_Complex", "Enemies_Level2" }; foreach (var name in toRemove) { var go = GameObject.Find(name); if (go != null) Undo.DestroyObjectImmediate(go); } // Удаляем старые тестовые коробки патронов var allBoxes = Object.FindObjectsByType(FindObjectsInactive.Include, FindObjectsSortMode.None); foreach (var b in allBoxes) { Undo.DestroyObjectImmediate(b.gameObject); } // 4. Загрузка материалов и префабов Material echoMat = AssetDatabase.LoadAssetAtPath("Assets/EchoCloudMat.mat"); if (echoMat == null) echoMat = AssetDatabase.LoadAssetAtPath("Assets/EchoMat.mat"); GameObject mutantPrefab = AssetDatabase.LoadAssetAtPath("Assets/Prefabs/Mutant.prefab"); Font defaultFont = Resources.GetBuiltinResource("LegacyRuntime.ttf"); // 5. Создаем контейнер SubLevel2_Complex GameObject level2Root = new GameObject("SubLevel2_Complex"); level2Root.transform.position = Vector3.zero; // Позиционируем игрока в стартовом лифте прибытия (0, 0.1, -22) GameObject playerGo = GameObject.FindWithTag("Player"); if (playerGo == null) playerGo = GameObject.Find("Player"); if (playerGo != null) { playerGo.transform.position = new Vector3(0f, 0.15f, -22f); playerGo.transform.rotation = Quaternion.identity; } // --- ГЕОМЕТРИЯ 2-ГО УРОВНЯ --- // А. Шахта лифта прибытия (Arrival Chamber): (0, 0, -22), размер 6x6 BuildRoom(level2Root.transform, "Room_ArrivalElevator", new Vector3(0f, 0f, -22f), new Vector3(6f, 0.2f, 6f), 3.8f, echoMat, hasNorthDoor: true, hasSouthDoor: false, hasWestDoor: false, hasEastDoor: false); // Рама лифта прибытия BuildElevatorShaft(level2Root.transform, new Vector3(0f, 0f, -22.5f), echoMat); // Б. Южный шлюзовой коридор: (0, 0, -12.5), размер 4x13 BuildCorridor(level2Root.transform, "Corridor_South", new Vector3(0f, 0f, -12.5f), new Vector3(4f, 0.2f, 13f), 3.8f, echoMat, isNS: true); // В. Центральный узел (Central Hub): (0, 0, 0), размер 12x12 BuildRoom(level2Root.transform, "Room_CentralHub", new Vector3(0f, 0f, 0f), new Vector3(12f, 0.2f, 12f), 3.8f, echoMat, hasNorthDoor: true, hasSouthDoor: true, hasWestDoor: true, hasEastDoor: true); // Колонны в Центральном узле BuildPillar(level2Root.transform, new Vector3(-3.5f, 1.9f, -3.5f), new Vector3(1.2f, 3.8f, 1.2f), echoMat); BuildPillar(level2Root.transform, new Vector3(3.5f, 1.9f, -3.5f), new Vector3(1.2f, 3.8f, 1.2f), echoMat); BuildPillar(level2Root.transform, new Vector3(-3.5f, 1.9f, 3.5f), new Vector3(1.2f, 3.8f, 1.2f), echoMat); BuildPillar(level2Root.transform, new Vector3(3.5f, 1.9f, 3.5f), new Vector3(1.2f, 3.8f, 1.2f), echoMat); // Г. Западный сектор: Крио-изолятор и виварий (-17, 0, 0), размер 14x14 BuildCorridor(level2Root.transform, "Corridor_West", new Vector3(-8f, 0f, 0f), new Vector3(4f, 0.2f, 4f), 3.8f, echoMat, isNS: false); BuildRoom(level2Root.transform, "Room_CryoIsolation", new Vector3(-17f, 0f, 0f), new Vector3(14f, 0.2f, 14f), 3.8f, echoMat, hasNorthDoor: false, hasSouthDoor: false, hasWestDoor: false, hasEastDoor: true); // Д. Восточный сектор: Био-синтез и химические реакторы (17, 0, 0), размер 14x14 BuildCorridor(level2Root.transform, "Corridor_East", new Vector3(8f, 0f, 0f), new Vector3(4f, 0.2f, 4f), 3.8f, echoMat, isNS: false); BuildRoom(level2Root.transform, "Room_BioSynthesis", new Vector3(17f, 0f, 0f), new Vector3(14f, 0.2f, 14f), 3.8f, echoMat, hasNorthDoor: false, hasSouthDoor: false, hasWestDoor: true, hasEastDoor: false); // Е. Северный переход к архиву и реактору (0, 0, 9), размер 4x6 BuildCorridor(level2Root.transform, "Corridor_North", new Vector3(0f, 0f, 9f), new Vector3(4f, 0.2f, 6f), 3.8f, echoMat, isNS: true); // Ж. Сектор архивов и серверной (-11, 0, 15), размер 10x10 BuildCorridor(level2Root.transform, "Corridor_ArchivesBranch", new Vector3(-4.5f, 0f, 9f), new Vector3(5f, 0.2f, 4f), 3.8f, echoMat, isNS: false); BuildRoom(level2Root.transform, "Room_SecurityArchives", new Vector3(-11f, 0f, 15f), new Vector3(10f, 0.2f, 10f), 3.8f, echoMat, hasNorthDoor: false, hasSouthDoor: true, hasWestDoor: false, hasEastDoor: false); // З. Главный реакторный отсек и эвакуационный шлюз (0, 0, 26), просторная арена 26x26 м BuildRoom(level2Root.transform, "Room_ReactorAirlock", new Vector3(0f, 0f, 26f), new Vector3(26f, 0.2f, 26f), 4.5f, echoMat, hasNorthDoor: false, hasSouthDoor: true, hasWestDoor: false, hasEastDoor: false); // Массивные реакторные колонны-укрытия на арене босса BuildPillar(level2Root.transform, new Vector3(-6.5f, 2.25f, 20f), new Vector3(1.6f, 4.5f, 1.6f), echoMat); BuildPillar(level2Root.transform, new Vector3(6.5f, 2.25f, 20f), new Vector3(1.6f, 4.5f, 1.6f), echoMat); BuildPillar(level2Root.transform, new Vector3(-6.5f, 2.25f, 31f), new Vector3(1.6f, 4.5f, 1.6f), echoMat); BuildPillar(level2Root.transform, new Vector3(6.5f, 2.25f, 31f), new Vector3(1.6f, 4.5f, 1.6f), echoMat); // Финальный терминал эвакуации и шлюз на севере арены (0, 0, 38.2) BuildFinalEscapeAirlock(level2Root.transform, new Vector3(0f, 0f, 38.2f), echoMat); // Атмосферное аварийное освещение (тусклые маяки) BuildBeacon(level2Root.transform, new Vector3(0f, 2.5f, -22f), new Color(0.2f, 0.6f, 0.9f), 1.8f, 8f); BuildBeacon(level2Root.transform, new Vector3(0f, 2.8f, 0f), new Color(1.0f, 0.75f, 0.2f), 2.2f, 12f); BuildBeacon(level2Root.transform, new Vector3(-17f, 2.8f, 0f), new Color(0.1f, 0.8f, 0.9f), 1.8f, 10f); BuildBeacon(level2Root.transform, new Vector3(17f, 2.8f, 0f), new Color(1.0f, 0.45f, 0.1f), 1.8f, 10f); BuildBeacon(level2Root.transform, new Vector3(-11f, 2.5f, 15f), new Color(0.3f, 0.8f, 0.4f), 1.5f, 8f); BuildBeacon(level2Root.transform, new Vector3(-8f, 3.2f, 22f), new Color(1.0f, 0.2f, 0.2f), 2.2f, 14f); BuildBeacon(level2Root.transform, new Vector3(8f, 3.2f, 22f), new Color(1.0f, 0.2f, 0.2f), 2.2f, 14f); BuildBeacon(level2Root.transform, new Vector3(-8f, 3.2f, 31f), new Color(1.0f, 0.2f, 0.2f), 2.2f, 14f); BuildBeacon(level2Root.transform, new Vector3(8f, 3.2f, 31f), new Color(1.0f, 0.2f, 0.2f), 2.2f, 14f); // Патроны на уровне 2 CreateAmmoBox(new Vector3(-18f, 0.3f, 4f), 14); CreateAmmoBox(new Vector3(18f, 0.3f, -4f), 21); CreateAmmoBox(new Vector3(-12f, 0.3f, 16f), 14); // Физические предметы для бросков (отвлечение мутантов) CreateThrowableProp(new Vector3(-2f, 0.5f, -2f), "Distraction_Flask_1"); CreateThrowableProp(new Vector3(2f, 0.5f, -1f), "Distraction_Flask_2"); CreateThrowableProp(new Vector3(-16f, 0.5f, 2f), "Distraction_Flask_3"); CreateThrowableProp(new Vector3(16f, 0.5f, 2f), "Distraction_Flask_4"); // 6. Противники и Босс Уровня 2 GameObject enemiesContainer = new GameObject("Enemies_Level2"); if (mutantPrefab != null) { SpawnMutant(mutantPrefab, enemiesContainer.transform, new Vector3(0f, 0.1f, 3f), "Mutant_Central_Hub"); SpawnMutant(mutantPrefab, enemiesContainer.transform, new Vector3(-17f, 0.1f, 0f), "Mutant_CryoVault"); SpawnMutant(mutantPrefab, enemiesContainer.transform, new Vector3(17f, 0.1f, 0f), "Mutant_BioCore"); SpawnMutant(mutantPrefab, enemiesContainer.transform, new Vector3(-11f, 0.1f, 15f), "Mutant_Archives"); // Уникальный Босс 2-го уровня в центре расширенной реакторной арены GameObject bossObj = SpawnTitanBoss(mutantPrefab, enemiesContainer.transform, new Vector3(0f, 0.15f, 28f), "Titan_Boss_Alpha"); BuildBossArenaLockdown(level2Root.transform, new Vector3(0f, 0f, 13f), echoMat, bossObj); // Боеприпасы и тактические колбы на арене босса CreateAmmoBox(new Vector3(-9.5f, 0.3f, 18f), 21); CreateAmmoBox(new Vector3(9.5f, 0.3f, 18f), 21); CreateAmmoBox(new Vector3(-9.5f, 0.3f, 32f), 21); CreateAmmoBox(new Vector3(9.5f, 0.3f, 32f), 14); CreateThrowableProp(new Vector3(-6.5f, 0.5f, 25f), "Arena_Distraction_Flask_1"); CreateThrowableProp(new Vector3(6.5f, 0.5f, 25f), "Arena_Distraction_Flask_2"); CreateThrowableProp(new Vector3(0f, 0.5f, 34f), "Arena_Distraction_Flask_3"); } // 7. Настройка UI (Финальная победа, полоса здоровья босса, оверлей ослепления) SetupFinalVictoryUI(); // 8. Настраиваем и запекаем NavMesh для Уровня 2 BakeLevel2NavMesh(); // 9. Регистрация сцены в Build Settings RegisterSceneInBuildSettings(level2Path); // 10. Сохранение сцены EditorSceneManager.MarkSceneDirty(scene); EditorSceneManager.SaveScene(scene); Debug.Log("[Level 2] Сборка 2-го уровня полностью завершена!"); } private static void BuildRoom(Transform parent, string name, Vector3 center, Vector3 floorSize, float height, Material mat, bool hasNorthDoor, bool hasSouthDoor, bool hasWestDoor, bool hasEastDoor) { GameObject room = new GameObject(name); room.transform.SetParent(parent); room.transform.position = center; // Пол GameObject floor = GameObject.CreatePrimitive(PrimitiveType.Cube); floor.name = "Floor"; floor.transform.SetParent(room.transform); floor.transform.localPosition = Vector3.zero; floor.transform.localScale = floorSize; if (mat != null) floor.GetComponent().sharedMaterial = mat; // Потолок GameObject roof = GameObject.CreatePrimitive(PrimitiveType.Cube); roof.name = "Ceiling"; roof.transform.SetParent(room.transform); roof.transform.localPosition = new Vector3(0f, height, 0f); roof.transform.localScale = floorSize; if (mat != null) roof.GetComponent().sharedMaterial = mat; float halfX = floorSize.x * 0.5f; float halfZ = floorSize.z * 0.5f; float wallThick = 0.35f; // Северная стена BuildWallWithDoor(room.transform, new Vector3(0f, height * 0.5f, halfZ), floorSize.x, height, wallThick, hasNorthDoor, mat, false); // Южная стена BuildWallWithDoor(room.transform, new Vector3(0f, height * 0.5f, -halfZ), floorSize.x, height, wallThick, hasSouthDoor, mat, false); // Западная стена BuildWallWithDoor(room.transform, new Vector3(-halfX, height * 0.5f, 0f), floorSize.z, height, wallThick, hasWestDoor, mat, true); // Восточная стена BuildWallWithDoor(room.transform, new Vector3(halfX, height * 0.5f, 0f), floorSize.z, height, wallThick, hasEastDoor, mat, true); } private static void BuildWallWithDoor(Transform parent, Vector3 pos, float length, float height, float thick, bool hasDoor, Material mat, bool rotate90) { Quaternion rot = rotate90 ? Quaternion.Euler(0f, 90f, 0f) : Quaternion.identity; if (!hasDoor) { GameObject wall = GameObject.CreatePrimitive(PrimitiveType.Cube); wall.name = "SolidWall"; wall.transform.SetParent(parent); wall.transform.localPosition = pos; wall.transform.localRotation = rot; wall.transform.localScale = new Vector3(length, height, thick); if (mat != null) wall.GetComponent().sharedMaterial = mat; } else { float doorWidth = 3.6f; float sideWidth = Mathf.Max((length - doorWidth) * 0.5f, 0.5f); // Левый сегмент GameObject leftPart = GameObject.CreatePrimitive(PrimitiveType.Cube); leftPart.name = "Wall_PartL"; leftPart.transform.SetParent(parent); Vector3 offsetL = rotate90 ? new Vector3(0f, 0f, -(doorWidth + sideWidth) * 0.5f) : new Vector3(-(doorWidth + sideWidth) * 0.5f, 0f, 0f); leftPart.transform.localPosition = pos + offsetL; leftPart.transform.localRotation = rot; leftPart.transform.localScale = new Vector3(sideWidth, height, thick); if (mat != null) leftPart.GetComponent().sharedMaterial = mat; // Правый сегмент GameObject rightPart = GameObject.CreatePrimitive(PrimitiveType.Cube); rightPart.name = "Wall_PartR"; rightPart.transform.SetParent(parent); Vector3 offsetR = rotate90 ? new Vector3(0f, 0f, (doorWidth + sideWidth) * 0.5f) : new Vector3((doorWidth + sideWidth) * 0.5f, 0f, 0f); rightPart.transform.localPosition = pos + offsetR; rightPart.transform.localRotation = rot; rightPart.transform.localScale = new Vector3(sideWidth, height, thick); if (mat != null) rightPart.GetComponent().sharedMaterial = mat; // Верхняя перемычка GameObject topLintel = GameObject.CreatePrimitive(PrimitiveType.Cube); topLintel.name = "Wall_TopLintel"; topLintel.transform.SetParent(parent); Vector3 offsetTop = new Vector3(0f, height * 0.38f, 0f); topLintel.transform.localPosition = pos + offsetTop; topLintel.transform.localRotation = rot; topLintel.transform.localScale = new Vector3(doorWidth, height * 0.25f, thick); if (mat != null) topLintel.GetComponent().sharedMaterial = mat; } } private static void BuildCorridor(Transform parent, string name, Vector3 pos, Vector3 floorSize, float height, Material mat, bool isNS) { GameObject corr = new GameObject(name); corr.transform.SetParent(parent); corr.transform.position = pos; GameObject floor = GameObject.CreatePrimitive(PrimitiveType.Cube); floor.name = "Floor"; floor.transform.SetParent(corr.transform); floor.transform.localPosition = Vector3.zero; floor.transform.localScale = floorSize; if (mat != null) floor.GetComponent().sharedMaterial = mat; GameObject roof = GameObject.CreatePrimitive(PrimitiveType.Cube); roof.name = "Ceiling"; roof.transform.SetParent(corr.transform); roof.transform.localPosition = new Vector3(0f, height, 0f); roof.transform.localScale = floorSize; if (mat != null) roof.GetComponent().sharedMaterial = mat; float thick = 0.35f; if (isNS) { // Стены слева и справа float halfW = floorSize.x * 0.5f; GameObject wL = GameObject.CreatePrimitive(PrimitiveType.Cube); wL.name = "Wall_L"; wL.transform.SetParent(corr.transform); wL.transform.localPosition = new Vector3(-halfW, height * 0.5f, 0f); wL.transform.localScale = new Vector3(thick, height, floorSize.z); if (mat != null) wL.GetComponent().sharedMaterial = mat; GameObject wR = GameObject.CreatePrimitive(PrimitiveType.Cube); wR.name = "Wall_R"; wR.transform.SetParent(corr.transform); wR.transform.localPosition = new Vector3(halfW, height * 0.5f, 0f); wR.transform.localScale = new Vector3(thick, height, floorSize.z); if (mat != null) wR.GetComponent().sharedMaterial = mat; } else { // Стены спереди и сзади float halfL = floorSize.z * 0.5f; GameObject wN = GameObject.CreatePrimitive(PrimitiveType.Cube); wN.name = "Wall_N"; wN.transform.SetParent(corr.transform); wN.transform.localPosition = new Vector3(0f, height * 0.5f, halfL); wN.transform.localScale = new Vector3(floorSize.x, height, thick); if (mat != null) wN.GetComponent().sharedMaterial = mat; GameObject wS = GameObject.CreatePrimitive(PrimitiveType.Cube); wS.name = "Wall_S"; wS.transform.SetParent(corr.transform); wS.transform.localPosition = new Vector3(0f, height * 0.5f, -halfL); wS.transform.localScale = new Vector3(floorSize.x, height, thick); if (mat != null) wS.GetComponent().sharedMaterial = mat; } } private static void BuildPillar(Transform parent, Vector3 pos, Vector3 size, Material mat) { GameObject p = GameObject.CreatePrimitive(PrimitiveType.Cube); p.name = "Structural_Pillar"; p.transform.SetParent(parent); p.transform.localPosition = pos; p.transform.localScale = size; if (mat != null) p.GetComponent().sharedMaterial = mat; } private static void BuildElevatorShaft(Transform parent, Vector3 pos, Material mat) { GameObject shaft = new GameObject("Arrival_Elevator_Shaft"); shaft.transform.SetParent(parent); shaft.transform.position = pos; Vector3[] corners = new Vector3[] { new Vector3(-2.2f, 1.9f, -2.2f), new Vector3(2.2f, 1.9f, -2.2f), new Vector3(-2.2f, 1.9f, 2.2f), new Vector3(2.2f, 1.9f, 2.2f) }; for (int i = 0; i < corners.Length; i++) { GameObject col = GameObject.CreatePrimitive(PrimitiveType.Cube); col.name = $"Shaft_Pillar_{i}"; col.transform.SetParent(shaft.transform); col.transform.localPosition = corners[i]; col.transform.localScale = new Vector3(0.25f, 3.8f, 0.25f); if (mat != null) col.GetComponent().sharedMaterial = mat; } } private static void BuildFinalEscapeAirlock(Transform parent, Vector3 pos, Material mat) { GameObject airlock = new GameObject("Final_Escape_Airlock_Zone"); airlock.transform.SetParent(parent); airlock.transform.position = pos; // Массивная стальная рама шлюза GameObject hatch = GameObject.CreatePrimitive(PrimitiveType.Cube); hatch.name = "Airlock_BlastDoor"; hatch.transform.SetParent(airlock.transform); hatch.transform.localPosition = new Vector3(0f, 2.1f, 0f); hatch.transform.localScale = new Vector3(5f, 4.2f, 0.8f); if (mat != null) hatch.GetComponent().sharedMaterial = mat; // Консоль управления шлюзом (терминал) GameObject console = GameObject.CreatePrimitive(PrimitiveType.Cube); console.name = "FinalExit_Terminal_Console"; console.transform.SetParent(airlock.transform); console.transform.localPosition = new Vector3(0f, 0.6f, -2.5f); console.transform.localScale = new Vector3(0.9f, 1.2f, 0.5f); if (mat != null) console.GetComponent().sharedMaterial = mat; // Экран терминала GameObject screen = GameObject.CreatePrimitive(PrimitiveType.Cube); screen.name = "Terminal_Screen"; screen.transform.SetParent(console.transform); screen.transform.localPosition = new Vector3(0f, 0.35f, 0.05f); screen.transform.localRotation = Quaternion.Euler(25f, 0f, 0f); screen.transform.localScale = new Vector3(0.7f, 0.4f, 0.15f); if (mat != null) screen.GetComponent().sharedMaterial = mat; // Световой маяк GameObject lightObj = new GameObject("Airlock_StatusLight"); lightObj.transform.SetParent(console.transform); lightObj.transform.localPosition = new Vector3(0f, 0.75f, 0f); Light sl = lightObj.AddComponent(); sl.type = LightType.Point; sl.color = new Color(1f, 0.35f, 0.1f); sl.intensity = 2.5f; sl.range = 6f; // Скрипт финала var terminalComp = console.AddComponent(); terminalComp.statusLight = sl; terminalComp.screenRenderer = screen.GetComponent(); terminalComp.interactionDistance = 3.5f; } private static void BuildBeacon(Transform parent, Vector3 pos, Color color, float intensity, float range) { GameObject beacon = new GameObject("Emergency_Beacon"); beacon.transform.SetParent(parent); beacon.transform.position = pos; Light l = beacon.AddComponent(); l.type = LightType.Point; l.color = color; l.intensity = intensity; l.range = range; } private static void CreateAmmoBox(Vector3 pos, int count) { GameObject box = GameObject.CreatePrimitive(PrimitiveType.Cube); box.name = $"AmmoBox_({count})"; box.transform.position = pos; box.transform.localScale = new Vector3(0.6f, 0.35f, 0.45f); var pickup = box.AddComponent(); pickup.ammoAmount = count; pickup.pickupOnTouch = true; } private static void CreateThrowableProp(Vector3 pos, string name) { GameObject prop = GameObject.CreatePrimitive(PrimitiveType.Cylinder); prop.name = name; prop.transform.position = pos; prop.transform.localScale = new Vector3(0.3f, 0.35f, 0.3f); var rb = prop.AddComponent(); rb.mass = 2.5f; prop.layer = LayerMask.NameToLayer("Default"); } private static void SpawnMutant(GameObject prefab, Transform parent, Vector3 pos, string name) { GameObject mutant = PrefabUtility.InstantiatePrefab(prefab) as GameObject; if (mutant == null) mutant = Object.Instantiate(prefab); mutant.name = name; mutant.transform.SetParent(parent); mutant.transform.position = pos; } private static GameObject SpawnTitanBoss(GameObject prefab, Transform parent, Vector3 pos, string name) { GameObject boss = PrefabUtility.InstantiatePrefab(prefab) as GameObject; if (boss == null) boss = Object.Instantiate(prefab); boss.name = name; boss.transform.SetParent(parent); boss.transform.position = pos; boss.transform.localScale = new Vector3(1.75f, 1.75f, 1.75f); // Массивный титан // Удаляем обычный BlindMutantAI, чтобы боссом управлял специализированный TitanBossAI var standardAI = boss.GetComponent(); if (standardAI != null) Object.DestroyImmediate(standardAI); // Настраиваем здоровье босса на 200 HP var health = boss.GetComponent(); if (health == null) health = boss.AddComponent(); health.maxHealth = 200f; // Добавляем специализированный интеллект босса var titanAI = boss.GetComponent(); if (titanAI == null) titanAI = boss.AddComponent(); titanAI.walkSpeed = 2.8f; titanAI.runSpeed = 4.6f; titanAI.meleeDamage = 18f; titanAI.meleeCooldown = 2.2f; titanAI.spitDamage = 14f; titanAI.spitCooldown = 8.5f; // Настраиваем NavMeshAgent под габариты босса var agent = boss.GetComponent(); if (agent != null) { agent.speed = 2.8f; agent.radius = 0.85f; agent.height = 3.0f; agent.stoppingDistance = 2.4f; agent.acceleration = 10f; } // Подсветка биолюминесценции босса (багровое свечение) GameObject bossGlow = new GameObject("Titan_Bioluminescence"); bossGlow.transform.SetParent(boss.transform); bossGlow.transform.localPosition = new Vector3(0f, 1.8f, 0f); Light glowLight = bossGlow.AddComponent(); glowLight.type = LightType.Point; glowLight.color = new Color(0.95f, 0.15f, 0.2f); glowLight.range = 7.5f; glowLight.intensity = 2.4f; return boss; } private static void BuildBossArenaLockdown(Transform parent, Vector3 entrancePos, Material echoMat, GameObject bossObj) { GameObject arenaRoot = new GameObject("BossArena_LockdownManager"); arenaRoot.transform.SetParent(parent); arenaRoot.transform.position = entrancePos; // 1. Гермоворота (Blast Door) на входе в реакторную комнату (pos = 0, 0, 13) // Вход шириной 3.6м, высотой 4.2м GameObject doorObj = GameObject.CreatePrimitive(PrimitiveType.Cube); doorObj.name = "BlastDoor_Quarantine"; doorObj.transform.SetParent(arenaRoot.transform); doorObj.transform.position = entrancePos + new Vector3(0f, 2.1f, 0f); doorObj.transform.localScale = new Vector3(3.8f, 4.2f, 0.45f); if (echoMat != null) doorObj.GetComponent().sharedMaterial = echoMat; // Добавляем NavMeshObstacle для предотвращения прохода через закрытую дверь var obstacle = doorObj.AddComponent(); obstacle.carving = true; obstacle.size = new Vector3(3.8f, 4.2f, 0.45f); // 2. Сигнальная лампа карантина над дверью GameObject lampObj = new GameObject("Quarantine_EmergencyLight"); lampObj.transform.SetParent(arenaRoot.transform); lampObj.transform.position = entrancePos + new Vector3(0f, 3.8f, 0.8f); Light alertLight = lampObj.AddComponent(); alertLight.type = LightType.Point; alertLight.color = new Color(0.2f, 0.85f, 0.35f); // До боя дежурный зеленоватый свет alertLight.range = 10f; alertLight.intensity = 1.8f; // 3. Зона триггера блокировки (сразу за дверью внутри комнаты) GameObject triggerObj = new GameObject("Trigger_LockdownArea"); triggerObj.transform.SetParent(arenaRoot.transform); triggerObj.transform.position = entrancePos + new Vector3(0f, 1.5f, 2.8f); BoxCollider col = triggerObj.AddComponent(); col.isTrigger = true; col.size = new Vector3(5.5f, 3.5f, 3.5f); var rb = triggerObj.AddComponent(); rb.isKinematic = true; // Навешиваем BossArenaController прямо на триггер var arenaCtrl = triggerObj.AddComponent(); arenaCtrl.blastDoorRoot = doorObj; arenaCtrl.blastDoorCollider = doorObj.GetComponent(); arenaCtrl.emergencyLight = alertLight; if (bossObj != null) { var titanAI = bossObj.GetComponent(); arenaCtrl.bossAI = titanAI; if (titanAI != null) { titanAI.arenaController = arenaCtrl; } } } private static void SetupFinalVictoryUI() { GameObject hudCanvas = GameObject.Find("HUD_Canvas"); if (hudCanvas == null) return; // Создаем полосу здоровья босса (скрыта по умолчанию) BossHealthBarUI.Create(hudCanvas.transform); // Создаем оверлей акустического ослепления босса (скрыт по умолчанию) AcousticJammerOverlay.Create(hudCanvas.transform); // Проверяем, существует ли уже панель победы var old = hudCanvas.transform.Find("FinalVictoryPanel"); if (old != null) Undo.DestroyObjectImmediate(old.gameObject); // Корневая панель GameObject root = new GameObject("FinalVictoryPanel", typeof(RectTransform), typeof(CanvasRenderer), typeof(Image)); root.transform.SetParent(hudCanvas.transform, false); RectTransform rt = root.GetComponent(); rt.anchorMin = Vector2.zero; rt.anchorMax = Vector2.one; rt.sizeDelta = Vector2.zero; Image bg = root.GetComponent(); bg.color = new Color(0.02f, 0.02f, 0.03f, 0.95f); // Карточка GameObject card = new GameObject("VictoryCard", typeof(RectTransform), typeof(CanvasRenderer), typeof(Image), typeof(Outline)); card.transform.SetParent(root.transform, false); RectTransform cardRt = card.GetComponent(); cardRt.anchorMin = new Vector2(0.5f, 0.5f); cardRt.anchorMax = new Vector2(0.5f, 0.5f); cardRt.pivot = new Vector2(0.5f, 0.5f); cardRt.sizeDelta = new Vector2(680f, 440f); Image cardImg = card.GetComponent(); cardImg.color = new Color(0.06f, 0.06f, 0.07f, 1f); Outline cardOutline = card.GetComponent(); cardOutline.effectColor = new Color(0.2f, 0.9f, 0.5f, 0.8f); cardOutline.effectDistance = new Vector2(2f, -2f); // Заголовок GameObject titleObj = new GameObject("Title", typeof(RectTransform), typeof(CanvasRenderer), typeof(Text)); titleObj.transform.SetParent(card.transform, false); RectTransform titleRt = titleObj.GetComponent(); titleRt.anchorMin = new Vector2(0f, 1f); titleRt.anchorMax = new Vector2(1f, 1f); titleRt.pivot = new Vector2(0.5f, 1f); titleRt.anchoredPosition = new Vector2(0f, -25f); titleRt.sizeDelta = new Vector2(620f, 45f); Text titleTxt = titleObj.GetComponent(); titleTxt.text = "МИССИЯ ВЫПОЛНЕНА // ЭВАКУАЦИЯ УСПЕШНА!"; titleTxt.font = Resources.GetBuiltinResource("LegacyRuntime.ttf"); titleTxt.fontSize = 22; titleTxt.fontStyle = FontStyle.Bold; titleTxt.alignment = TextAnchor.MiddleCenter; titleTxt.color = new Color(0.2f, 1.0f, 0.5f, 1.0f); // Описание GameObject descObj = new GameObject("Description", typeof(RectTransform), typeof(CanvasRenderer), typeof(Text)); descObj.transform.SetParent(card.transform, false); RectTransform descRt = descObj.GetComponent(); descRt.anchorMin = new Vector2(0.5f, 0.5f); descRt.anchorMax = new Vector2(0.5f, 0.5f); descRt.pivot = new Vector2(0.5f, 0.5f); descRt.anchoredPosition = new Vector2(0f, 15f); descRt.sizeDelta = new Vector2(580f, 140f); Text descTxt = descObj.GetComponent(); descTxt.text = "Вы успешно преодолели Сектор глубоких исследований, обошли слепых мутантов и активировали аварийный гермошлюз.\n\nКомплекс 'Synthesia' запечатан. Вы выбрались на поверхность живым!"; descTxt.font = Resources.GetBuiltinResource("LegacyRuntime.ttf"); descTxt.fontSize = 16; descTxt.lineSpacing = 1.3f; descTxt.alignment = TextAnchor.MiddleCenter; descTxt.color = new Color(0.9f, 0.9f, 0.9f, 0.95f); // Кнопка В главное меню GameObject btnMenuObj = new GameObject("MainMenuButton", typeof(RectTransform), typeof(CanvasRenderer), typeof(Image), typeof(Button)); btnMenuObj.transform.SetParent(card.transform, false); RectTransform btnMenuRt = btnMenuObj.GetComponent(); btnMenuRt.anchorMin = new Vector2(0.5f, 0f); btnMenuRt.anchorMax = new Vector2(0.5f, 0f); btnMenuRt.pivot = new Vector2(0.5f, 0f); btnMenuRt.anchoredPosition = new Vector2(-150f, 30f); btnMenuRt.sizeDelta = new Vector2(260f, 48f); Image btnMenuImg = btnMenuObj.GetComponent(); btnMenuImg.color = new Color(0.18f, 0.18f, 0.20f, 1f); Button btnMenu = btnMenuObj.GetComponent