using System; using System.IO; using System.Reflection; using UnityEditor; using UnityEditor.SceneManagement; using UnityEngine; using UnityEngine.AI; using UnityEngine.SceneManagement; using UnityEngine.UI; public static class Lab5SceneBuilder { private const string SceneDirectory = "Assets/Scenes"; private const string ScenePath = SceneDirectory + "/Lab5_StealthMechanics.unity"; private const string MaterialDirectory = "Assets/Materials/Lab5"; private sealed class BuildContext { public Font font; public Material floorMaterial; public Material wallMaterial; public Material coverMaterial; public Material enemyMaterial; public Material playerMaterial; public Material zoneMaterial; public Material visionMaterial; public int playerLayer; public int coverLayer; public int obstacleLayer; public int visionLayer; public LayerMask obstacleMask; public LayerMask targetMask; } [MenuItem("Tools/Lab5/Create Full Test Scene")] public static void CreateFullTestScene() { // Builder пересобирает лабораторную с нуля, чтобы не требовать ручной настройки в инспекторе. EnsureFolders(); EnsureTag("Player"); BuildContext context = new BuildContext { playerLayer = EnsureLayer("Player", 8), coverLayer = EnsureLayer("Cover", 9), obstacleLayer = EnsureLayer("Obstacle", 10), visionLayer = EnsureLayer("Vision", 11) }; context.obstacleMask = (1 << context.coverLayer) | (1 << context.obstacleLayer); context.targetMask = 1 << context.playerLayer; context.font = LoadBuiltinFont(); context.floorMaterial = GetOrCreateOpaqueMaterial(MaterialDirectory + "/Lab5_Floor.mat", new Color(0.21f, 0.24f, 0.28f)); context.wallMaterial = GetOrCreateOpaqueMaterial(MaterialDirectory + "/Lab5_Wall.mat", new Color(0.63f, 0.65f, 0.69f)); context.coverMaterial = GetOrCreateOpaqueMaterial(MaterialDirectory + "/Lab5_Cover.mat", new Color(0.48f, 0.31f, 0.2f)); context.enemyMaterial = GetOrCreateOpaqueMaterial(MaterialDirectory + "/Lab5_Enemy.mat", new Color(0.78f, 0.2f, 0.18f)); context.playerMaterial = GetOrCreateOpaqueMaterial(MaterialDirectory + "/Lab5_Player.mat", new Color(0.15f, 0.46f, 0.9f)); context.zoneMaterial = GetOrCreateTransparentMaterial(MaterialDirectory + "/Lab5_Zone.mat", new Color(0.15f, 0.95f, 0.95f, 0.3f)); context.visionMaterial = GetOrCreateTransparentMaterial(MaterialDirectory + "/Lab5_Vision.mat", new Color(0.2f, 0.95f, 0.35f, 0.22f)); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); Scene scene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single); GameObject sceneRoot = new GameObject("Lab5_Root"); GameObject environmentRoot = new GameObject("Environment"); environmentRoot.transform.SetParent(sceneRoot.transform); GameObject systemsRoot = new GameObject("Systems"); systemsRoot.transform.SetParent(sceneRoot.transform); GameObject patrolRoot = new GameObject("PatrolRoutes"); patrolRoot.transform.SetParent(sceneRoot.transform); GameObject enemiesRoot = new GameObject("Enemies"); enemiesRoot.transform.SetParent(sceneRoot.transform); CreateLighting(); CreateEnvironment(context, environmentRoot.transform); GameObject noiseManager = new GameObject("NoiseManager"); noiseManager.transform.SetParent(systemsRoot.transform); noiseManager.AddComponent(); GameObject player = CreatePlayer(context, sceneRoot.transform); CreateUI(context, sceneRoot.transform, player); CreateEnemies(context, enemiesRoot.transform, patrolRoot.transform, player); bool navMeshBaked = TryBakeNavMesh(); EditorSceneManager.MarkSceneDirty(scene); EditorSceneManager.SaveScene(scene, ScenePath); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); Selection.activeObject = AssetDatabase.LoadAssetAtPath(ScenePath); EditorUtility.DisplayDialog( "Lab 5", navMeshBaked ? "Сцена создана и сохранена. NavMesh был перестроен автоматически." : "Сцена создана и сохранена. Если враги не встают на NavMesh, откройте Window -> AI -> Navigation и нажмите Bake.", "OK"); } private static void CreateLighting() { GameObject lightObject = new GameObject("Directional Light"); Light directionalLight = lightObject.AddComponent(); directionalLight.type = LightType.Directional; directionalLight.intensity = 1.15f; lightObject.transform.rotation = Quaternion.Euler(50f, -30f, 0f); RenderSettings.ambientMode = UnityEngine.Rendering.AmbientMode.Flat; RenderSettings.ambientLight = new Color(0.45f, 0.47f, 0.5f); } private static void CreateEnvironment(BuildContext context, Transform parent) { GameObject floor = GameObject.CreatePrimitive(PrimitiveType.Plane); floor.name = "Floor"; floor.transform.SetParent(parent); floor.transform.position = Vector3.zero; floor.transform.localScale = new Vector3(4f, 1f, 4f); floor.GetComponent().sharedMaterial = context.floorMaterial; floor.layer = LayerMask.NameToLayer("Default"); SetNavigationStatic(floor); CreateWall(context, parent, "NorthWall", new Vector3(0f, 1.5f, 20f), new Vector3(40f, 3f, 1f)); CreateWall(context, parent, "SouthWall", new Vector3(0f, 1.5f, -20f), new Vector3(40f, 3f, 1f)); CreateWall(context, parent, "EastWall", new Vector3(20f, 1.5f, 0f), new Vector3(1f, 3f, 40f)); CreateWall(context, parent, "WestWall", new Vector3(-20f, 1.5f, 0f), new Vector3(1f, 3f, 40f)); CreateWall(context, parent, "LeftDividerA", new Vector3(-5f, 1.5f, -12f), new Vector3(1f, 3f, 12f)); CreateWall(context, parent, "LeftDividerB", new Vector3(-5f, 1.5f, 3f), new Vector3(1f, 3f, 6f)); CreateWall(context, parent, "LeftDividerC", new Vector3(-5f, 1.5f, 14f), new Vector3(1f, 3f, 8f)); CreateWall(context, parent, "RightDividerA", new Vector3(5f, 1.5f, -14f), new Vector3(1f, 3f, 8f)); CreateWall(context, parent, "RightDividerB", new Vector3(5f, 1.5f, -3f), new Vector3(1f, 3f, 6f)); CreateWall(context, parent, "RightDividerC1", new Vector3(5f, 1.5f, 6f), new Vector3(1f, 3f, 8f)); CreateWall(context, parent, "RightDividerC2", new Vector3(5f, 1.5f, 16f), new Vector3(1f, 3f, 8f)); CreateWall(context, parent, "LeftRoomTopA", new Vector3(-15f, 1.5f, 7f), new Vector3(8f, 3f, 1f)); CreateWall(context, parent, "LeftRoomTopB", new Vector3(-7f, 1.5f, 7f), new Vector3(2f, 3f, 1f)); CreateWall(context, parent, "LeftRoomBottomA", new Vector3(-15f, 1.5f, -7f), new Vector3(8f, 3f, 1f)); CreateWall(context, parent, "LeftRoomBottomB", new Vector3(-7f, 1.5f, -7f), new Vector3(2f, 3f, 1f)); CreateWall(context, parent, "RightRoomTopA", new Vector3(8f, 1.5f, 7f), new Vector3(4f, 3f, 1f)); CreateWall(context, parent, "RightRoomTopB", new Vector3(16f, 1.5f, 7f), new Vector3(6f, 3f, 1f)); CreateWall(context, parent, "RightRoomBottomA", new Vector3(8f, 1.5f, -7f), new Vector3(4f, 3f, 1f)); CreateWall(context, parent, "RightRoomBottomB", new Vector3(16f, 1.5f, -7f), new Vector3(6f, 3f, 1f)); CreateCover(context, parent, "CenterBarrier", new Vector3(0f, 1f, 0f), new Vector3(2.5f, 2f, 2f)); CreateCover(context, parent, "CoverBox_A", new Vector3(-10f, 1f, -3f), new Vector3(2f, 2f, 2f)); CreateCover(context, parent, "CoverBox_B", new Vector3(-1.5f, 1f, -10f), new Vector3(2f, 2f, 2f)); CreateCover(context, parent, "CoverBox_C", new Vector3(2f, 1f, 5f), new Vector3(2.5f, 2f, 2f)); CreateCover(context, parent, "CoverWall_A", new Vector3(10f, 1.25f, 2f), new Vector3(3.5f, 2.5f, 1f)); CreateCover(context, parent, "CoverWall_B", new Vector3(13f, 1f, 13f), new Vector3(2f, 2f, 2f)); CreateCover(context, parent, "CoverBox_D", new Vector3(-15f, 1f, 14f), new Vector3(2f, 2f, 2f)); GameObject exitZone = GameObject.CreatePrimitive(PrimitiveType.Cylinder); exitZone.name = "ExitZone"; exitZone.transform.SetParent(parent); exitZone.transform.position = new Vector3(15f, 0.2f, 15f); exitZone.transform.localScale = new Vector3(2f, 0.2f, 2f); exitZone.GetComponent().sharedMaterial = context.zoneMaterial; exitZone.layer = context.visionLayer; exitZone.GetComponent().isTrigger = true; exitZone.AddComponent(); } private static GameObject CreatePlayer(BuildContext context, Transform parent) { GameObject player = new GameObject("Player"); player.transform.SetParent(parent); player.transform.position = new Vector3(-15f, 0f, 14f); player.tag = "Player"; player.layer = context.playerLayer; CharacterController controller = player.AddComponent(); controller.height = 2f; controller.radius = 0.35f; controller.center = new Vector3(0f, 1f, 0f); controller.stepOffset = 0.35f; controller.slopeLimit = 45f; GameObject body = GameObject.CreatePrimitive(PrimitiveType.Capsule); body.name = "PlayerBody"; body.transform.SetParent(player.transform); body.transform.localPosition = new Vector3(0f, 1f, 0f); body.transform.localRotation = Quaternion.identity; body.GetComponent().sharedMaterial = context.playerMaterial; body.layer = context.playerLayer; UnityEngine.Object.DestroyImmediate(body.GetComponent()); GameObject cameraObject = new GameObject("PlayerCamera"); cameraObject.transform.SetParent(player.transform); cameraObject.transform.localPosition = new Vector3(0f, 0.8f, 0f); cameraObject.transform.localRotation = Quaternion.identity; Camera cameraComponent = cameraObject.AddComponent(); cameraComponent.nearClipPlane = 0.03f; cameraObject.AddComponent(); SimpleFPSController fpsController = player.AddComponent(); fpsController.characterController = controller; fpsController.playerCamera = cameraComponent; fpsController.walkSpeed = 4.1f; fpsController.runSpeed = 7.1f; fpsController.mouseSensitivity = 2.2f; PlayerStealth stealth = player.AddComponent(); stealth.characterController = controller; stealth.fpsController = fpsController; stealth.playerCamera = cameraComponent; player.AddComponent(); return player; } private static StealthIndicator CreateUI(BuildContext context, Transform parent, GameObject player) { GameObject canvasObject = new GameObject("Canvas"); canvasObject.transform.SetParent(parent); Canvas canvas = canvasObject.AddComponent(); canvas.renderMode = RenderMode.ScreenSpaceOverlay; CanvasScaler scaler = canvasObject.AddComponent(); scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize; scaler.referenceResolution = new Vector2(1920f, 1080f); scaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight; scaler.matchWidthOrHeight = 0.7f; canvasObject.AddComponent(); GameObject eventSystem = new GameObject("EventSystem"); eventSystem.transform.SetParent(parent); eventSystem.AddComponent(); eventSystem.AddComponent(); GameObject panel = CreateUIObject("StealthPanel", canvasObject.transform, new Vector2(20f, -20f), new Vector2(390f, 240f), new Vector2(0f, 1f), new Vector2(0f, 1f)); Image panelImage = panel.AddComponent(); panelImage.color = new Color(0.06f, 0.08f, 0.1f, 0.62f); GameObject barObject = CreateUIObject("StateBar", panel.transform, new Vector2(14f, -14f), new Vector2(362f, 18f), new Vector2(0f, 1f), new Vector2(0f, 1f)); Image barImage = barObject.AddComponent(); barImage.color = new Color(0.18f, 0.85f, 0.34f, 0.95f); Text statusText = CreateText(context, panel.transform, "StatusText", "Скрытность: безопасно", 18, FontStyle.Bold, new Vector2(14f, -40f), new Vector2(362f, 28f)); Text controlsText = CreateText(context, panel.transform, "ControlsText", string.Empty, 14, FontStyle.Normal, new Vector2(14f, -74f), new Vector2(362f, 94f)); Text debugText = CreateText(context, panel.transform, "DebugText", string.Empty, 14, FontStyle.Normal, new Vector2(14f, -172f), new Vector2(362f, 56f)); GameObject healthPanel = CreateUIObject("HealthPanel", canvasObject.transform, new Vector2(-20f, -20f), new Vector2(190f, 42f), new Vector2(1f, 1f), new Vector2(1f, 1f)); Image healthPanelImage = healthPanel.AddComponent(); healthPanelImage.color = new Color(0.06f, 0.08f, 0.1f, 0.62f); Text healthText = CreateText(context, healthPanel.transform, "HealthText", "Здоровье: 100", 18, FontStyle.Bold, new Vector2(10f, -6f), new Vector2(170f, 28f)); Text gameOverText = CreateCenteredText(context, canvasObject.transform, "GameOverText", "Игрок устранен", 28, FontStyle.Bold, new Vector2(520f, 70f)); gameOverText.color = new Color(1f, 0.2f, 0.2f, 1f); gameOverText.gameObject.SetActive(false); StealthIndicator indicator = panel.AddComponent(); indicator.stateBar = barImage; indicator.statusText = statusText; indicator.controlsText = controlsText; indicator.debugText = debugText; indicator.healthText = healthText; indicator.gameOverText = gameOverText; indicator.playerStealth = player.GetComponent(); indicator.playerHealth = player.GetComponent(); return indicator; } private static void CreateEnemies(BuildContext context, Transform enemiesParent, Transform patrolParent, GameObject player) { CreateEnemy( context, enemiesParent, patrolParent, "Enemy_LeftWing", new Vector3(-12f, 0f, -10f), new[] { new Vector3(-15f, 0f, -15f), new Vector3(-10f, 0f, -15f), new Vector3(-10f, 0f, -9f), new Vector3(-15f, 0f, -9f) }, player); CreateEnemy( context, enemiesParent, patrolParent, "Enemy_CenterCorridor", new Vector3(0f, 0f, -4f), new[] { new Vector3(-1f, 0f, -14f), new Vector3(-1f, 0f, -2f), new Vector3(1f, 0f, 6f), new Vector3(1f, 0f, 14f) }, player); CreateEnemy( context, enemiesParent, patrolParent, "Enemy_RightWing", new Vector3(12f, 0f, 12f), new[] { new Vector3(10f, 0f, 10f), new Vector3(15f, 0f, 10f), new Vector3(15f, 0f, 16f), new Vector3(10f, 0f, 16f) }, player); } private static EnemyStateMachine CreateEnemy( BuildContext context, Transform enemiesParent, Transform patrolParent, string enemyName, Vector3 position, Vector3[] waypointPositions, GameObject player) { GameObject enemyRoot = new GameObject(enemyName); enemyRoot.transform.SetParent(enemiesParent); enemyRoot.transform.position = position; enemyRoot.layer = LayerMask.NameToLayer("Default"); CapsuleCollider capsuleCollider = enemyRoot.AddComponent(); capsuleCollider.center = new Vector3(0f, 1f, 0f); capsuleCollider.height = 2f; capsuleCollider.radius = 0.4f; GameObject body = GameObject.CreatePrimitive(PrimitiveType.Capsule); body.name = "Body"; body.transform.SetParent(enemyRoot.transform); body.transform.localPosition = new Vector3(0f, 1f, 0f); body.transform.localRotation = Quaternion.identity; body.GetComponent().sharedMaterial = context.enemyMaterial; UnityEngine.Object.DestroyImmediate(body.GetComponent()); NavMeshAgent agent = enemyRoot.AddComponent(); agent.radius = 0.35f; agent.height = 2f; agent.baseOffset = 0f; agent.speed = 2.2f; agent.angularSpeed = 360f; agent.acceleration = 12f; agent.stoppingDistance = 0.1f; agent.autoBraking = true; EnemyStateMachine stateMachine = enemyRoot.AddComponent(); stateMachine.agent = agent; stateMachine.patrolSpeed = 2.2f; stateMachine.suspicionSpeed = 2.9f; stateMachine.alertSpeed = 4.1f; stateMachine.hearingRange = 14f; stateMachine.suspicionWaitDuration = 2.5f; stateMachine.captureDistance = 1.7f; EnemyVision vision = enemyRoot.AddComponent(); vision.stateMachine = stateMachine; vision.player = player.transform; vision.viewRadius = 13.5f; vision.viewAngle = 70f; vision.eyeHeight = 1.4f; vision.obstacleMask = context.obstacleMask; vision.targetMask = context.targetMask; EnemyVisionVisualizer visualizer = enemyRoot.AddComponent(); visualizer.vision = vision; visualizer.stateMachine = stateMachine; visualizer.visionMaterialTemplate = context.visionMaterial; stateMachine.vision = vision; stateMachine.patrolPoints = CreateWaypoints(enemyName + "_Route", patrolParent, waypointPositions); return stateMachine; } private static Transform[] CreateWaypoints(string routeName, Transform patrolParent, Vector3[] positions) { GameObject routeRoot = new GameObject(routeName); routeRoot.transform.SetParent(patrolParent); Transform[] waypoints = new Transform[positions.Length]; for (int i = 0; i < positions.Length; i++) { GameObject waypoint = new GameObject("Waypoint_" + i); waypoint.transform.SetParent(routeRoot.transform); waypoint.transform.position = positions[i]; waypoints[i] = waypoint.transform; } return waypoints; } private static GameObject CreateWall(BuildContext context, Transform parent, string name, Vector3 position, Vector3 scale) { GameObject wall = GameObject.CreatePrimitive(PrimitiveType.Cube); wall.name = name; wall.transform.SetParent(parent); wall.transform.position = position; wall.transform.localScale = scale; wall.GetComponent().sharedMaterial = context.wallMaterial; wall.layer = context.obstacleLayer; SetNavigationStatic(wall); return wall; } private static GameObject CreateCover(BuildContext context, Transform parent, string name, Vector3 position, Vector3 scale) { GameObject cover = GameObject.CreatePrimitive(PrimitiveType.Cube); cover.name = name; cover.transform.SetParent(parent); cover.transform.position = position; cover.transform.localScale = scale; cover.GetComponent().sharedMaterial = context.coverMaterial; cover.layer = context.coverLayer; cover.AddComponent(); SetNavigationStatic(cover); return cover; } private static GameObject CreateUIObject(string name, Transform parent, Vector2 anchoredPosition, Vector2 sizeDelta, Vector2 anchorMin, Vector2 anchorMax) { GameObject gameObject = new GameObject(name, typeof(RectTransform)); gameObject.transform.SetParent(parent, false); RectTransform rectTransform = gameObject.GetComponent(); rectTransform.anchorMin = anchorMin; rectTransform.anchorMax = anchorMax; rectTransform.pivot = new Vector2(anchorMin.x, anchorMax.y); rectTransform.anchoredPosition = anchoredPosition; rectTransform.sizeDelta = sizeDelta; return gameObject; } private static Text CreateText( BuildContext context, Transform parent, string name, string text, int fontSize, FontStyle fontStyle, Vector2 anchoredPosition, Vector2 sizeDelta) { GameObject textObject = CreateUIObject(name, parent, anchoredPosition, sizeDelta, new Vector2(0f, 1f), new Vector2(0f, 1f)); Text uiText = textObject.AddComponent(); uiText.font = context.font; uiText.text = text; uiText.fontSize = fontSize; uiText.fontStyle = fontStyle; uiText.alignment = TextAnchor.UpperLeft; uiText.horizontalOverflow = HorizontalWrapMode.Wrap; uiText.verticalOverflow = VerticalWrapMode.Overflow; uiText.color = Color.white; return uiText; } private static Text CreateCenteredText( BuildContext context, Transform parent, string name, string text, int fontSize, FontStyle fontStyle, Vector2 sizeDelta) { GameObject textObject = new GameObject(name, typeof(RectTransform)); textObject.transform.SetParent(parent, false); RectTransform rectTransform = textObject.GetComponent(); rectTransform.anchorMin = new Vector2(0.5f, 0.5f); rectTransform.anchorMax = new Vector2(0.5f, 0.5f); rectTransform.pivot = new Vector2(0.5f, 0.5f); rectTransform.anchoredPosition = Vector2.zero; rectTransform.sizeDelta = sizeDelta; Text uiText = textObject.AddComponent(); uiText.font = context.font; uiText.text = text; uiText.fontSize = fontSize; uiText.fontStyle = fontStyle; uiText.alignment = TextAnchor.MiddleCenter; uiText.horizontalOverflow = HorizontalWrapMode.Wrap; uiText.verticalOverflow = VerticalWrapMode.Overflow; uiText.color = Color.white; return uiText; } private static Material GetOrCreateOpaqueMaterial(string path, Color color) { Material material = AssetDatabase.LoadAssetAtPath(path); if (material == null) { material = new Material(Shader.Find("Standard")); AssetDatabase.CreateAsset(material, path); } material.shader = Shader.Find("Standard"); material.color = color; EditorUtility.SetDirty(material); return material; } private static Font LoadBuiltinFont() { Font font = Resources.GetBuiltinResource("LegacyRuntime.ttf"); if (font != null) { return font; } font = Resources.GetBuiltinResource("Arial.ttf"); if (font != null) { return font; } throw new InvalidOperationException("Не удалось загрузить встроенный шрифт Unity."); } private static Material GetOrCreateTransparentMaterial(string path, Color color) { Material material = AssetDatabase.LoadAssetAtPath(path); if (material == null) { material = new Material(Shader.Find("Standard")); AssetDatabase.CreateAsset(material, path); } material.shader = Shader.Find("Standard"); material.SetFloat("_Mode", 3f); material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha); material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); material.SetInt("_ZWrite", 0); material.DisableKeyword("_ALPHATEST_ON"); material.EnableKeyword("_ALPHABLEND_ON"); material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent; material.color = color; EditorUtility.SetDirty(material); return material; } private static void EnsureFolders() { Directory.CreateDirectory(SceneDirectory); Directory.CreateDirectory("Assets/Scripts"); Directory.CreateDirectory("Assets/Editor"); Directory.CreateDirectory("Assets/Materials"); Directory.CreateDirectory(MaterialDirectory); } private static void EnsureTag(string tagName) { SerializedObject tagManager = new SerializedObject(AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/TagManager.asset")[0]); SerializedProperty tagsProperty = tagManager.FindProperty("tags"); for (int i = 0; i < tagsProperty.arraySize; i++) { SerializedProperty existingTag = tagsProperty.GetArrayElementAtIndex(i); if (existingTag.stringValue == tagName) { return; } } tagsProperty.InsertArrayElementAtIndex(tagsProperty.arraySize); tagsProperty.GetArrayElementAtIndex(tagsProperty.arraySize - 1).stringValue = tagName; tagManager.ApplyModifiedProperties(); } private static int EnsureLayer(string layerName, int preferredIndex) { int existingLayer = LayerMask.NameToLayer(layerName); if (existingLayer >= 0) { return existingLayer; } SerializedObject tagManager = new SerializedObject(AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/TagManager.asset")[0]); SerializedProperty layersProperty = tagManager.FindProperty("layers"); if (preferredIndex >= 8 && preferredIndex < layersProperty.arraySize) { SerializedProperty preferredLayer = layersProperty.GetArrayElementAtIndex(preferredIndex); if (string.IsNullOrEmpty(preferredLayer.stringValue) || preferredLayer.stringValue == layerName) { preferredLayer.stringValue = layerName; tagManager.ApplyModifiedProperties(); return preferredIndex; } } for (int i = 8; i < layersProperty.arraySize; i++) { SerializedProperty layerProperty = layersProperty.GetArrayElementAtIndex(i); if (string.IsNullOrEmpty(layerProperty.stringValue)) { layerProperty.stringValue = layerName; tagManager.ApplyModifiedProperties(); return i; } } Debug.LogWarning("Не удалось добавить слой " + layerName + ". Будет использован Default."); return 0; } private static void SetNavigationStatic(GameObject gameObject) { GameObjectUtility.SetStaticEditorFlags( gameObject, StaticEditorFlags.BatchingStatic | StaticEditorFlags.ContributeGI | StaticEditorFlags.NavigationStatic | StaticEditorFlags.OccludeeStatic | StaticEditorFlags.OccluderStatic); } private static bool TryBakeNavMesh() { try { Type navMeshBuilderType = FindType("UnityEditor.AI.NavMeshBuilder"); if (navMeshBuilderType == null) { Debug.LogWarning("UnityEditor.AI.NavMeshBuilder не найден. Враги смогут использовать fallback-движение без NavMesh."); return false; } MethodInfo clearMethod = navMeshBuilderType.GetMethod("ClearAllNavMeshes", BindingFlags.Public | BindingFlags.Static); MethodInfo buildMethod = navMeshBuilderType.GetMethod("BuildNavMesh", BindingFlags.Public | BindingFlags.Static); if (buildMethod == null) { Debug.LogWarning("Метод BuildNavMesh не найден. Используйте Window -> AI -> Navigation -> Bake."); return false; } clearMethod?.Invoke(null, null); buildMethod.Invoke(null, null); return true; } catch (Exception exception) { Debug.LogWarning("Автоматическая запечка NavMesh не удалась: " + exception.Message); return false; } } private static Type FindType(string fullName) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { Type type = assemblies[i].GetType(fullName); if (type != null) { return type; } } return null; } }