357 lines
14 KiB
C#
357 lines
14 KiB
C#
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<GameObject>(MutantPrefabPath);
|
||
if (mutantPrefab == null)
|
||
{
|
||
Debug.LogError($"[MutantPopulationSetup] Prefab not found at {MutantPrefabPath}");
|
||
return "ERROR: Mutant.prefab not found!";
|
||
}
|
||
|
||
// 1. Очищаем старых мутантов в сцене
|
||
var existingEnemies = Object.FindObjectsByType<BlindMutantAI>();
|
||
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($"<color=green>{summary}</color>");
|
||
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<NavMeshAgent>();
|
||
if (agent != null)
|
||
{
|
||
agent.Warp(pos);
|
||
agent.avoidancePriority = Random.Range(30, 70);
|
||
}
|
||
|
||
var ai = mutantGo.GetComponent<BlindMutantAI>();
|
||
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;
|
||
}
|
||
}
|