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