using System.IO; using UnityEditor; using UnityEditor.AI; using UnityEditor.SceneManagement; using UnityEngine; using UnityEngine.AI; using UnityEngine.SceneManagement; using UnityEngine.UI; public static class Lab7SceneBuilder { private const string ScenePath = "Assets/_Scenes/TerritoryScene.unity"; [MenuItem("Tools/Lab7/Create Full Territory Scene")] public static void CreateFullTerritoryScene() { Time.timeScale = 1f; CreateFolders(); EnsureTag("Player"); EnsureTag("Enemy"); Material groundMaterial = GetOrCreateMaterial("Assets/_Materials/Ground.mat", new Color(0.25f, 0.34f, 0.25f, 1f), false); Material wallMaterial = GetOrCreateMaterial("Assets/_Materials/Walls.mat", new Color(0.38f, 0.39f, 0.42f, 1f), false); Material playerMaterial = GetOrCreateMaterial("Assets/_Materials/PlayerBlue.mat", new Color(0.1f, 0.35f, 1f, 1f), false); Material enemyMaterial = GetOrCreateMaterial("Assets/_Materials/EnemyRed.mat", new Color(1f, 0.12f, 0.08f, 1f), false); Material zoneNeutralMaterial = GetOrCreateMaterial("Assets/_Materials/ZoneTransparent.mat", new Color(0.55f, 0.55f, 0.55f, 0.45f), true); Scene scene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single); scene.name = "TerritoryScene"; GameObject ground = CreateGround(groundMaterial); CreateObstacles(wallMaterial); Camera mainCamera = CreateCamera(); CreateLight(); TerritoryUI territoryUI = CreateMainUI(); ResourceManager resourceManager = CreateResourceManager(territoryUI); GameManager gameManager = CreateGameManager(territoryUI); CaptureZone[] zones = new CaptureZone[] { CreateCaptureZone("Zone A", new Vector3(-8f, 0.05f, 6f), zoneNeutralMaterial, mainCamera), CreateCaptureZone("Zone B", new Vector3(7.5f, 0.05f, 4f), zoneNeutralMaterial, mainCamera), CreateCaptureZone("Zone C", new Vector3(0f, 0.05f, -7.5f), zoneNeutralMaterial, mainCamera) }; PlayerController player = CreatePlayer(playerMaterial); EnemyAI enemyOne = CreateEnemy("Enemy 1", new Vector3(10f, 1f, -9f), enemyMaterial); EnemyAI enemyTwo = CreateEnemy("Enemy 2", new Vector3(-10f, 1f, -9f), enemyMaterial); enemyOne.zones = zones; enemyTwo.zones = zones; gameManager.zones = zones; territoryUI.UpdateZoneStatus(zones); territoryUI.SetScore(0, 0); territoryUI.HideGameOver(); resourceManager.territoryUI = territoryUI; gameManager.territoryUI = territoryUI; gameManager.winPanel = territoryUI.winPanel; gameManager.winText = territoryUI.winText; BakeNavMeshIfAvailable(ground); EditorSceneManager.SaveScene(scene, ScenePath); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); Selection.activeObject = player.gameObject; Debug.Log("Lab 7 territory scene created: " + ScenePath); } private static void CreateFolders() { CreateFolderIfMissing("Assets", "_Scripts"); CreateFolderIfMissing("Assets", "_Scenes"); CreateFolderIfMissing("Assets", "_Materials"); CreateFolderIfMissing("Assets", "_Prefabs"); CreateFolderIfMissing("Assets", "Editor"); } private static void CreateFolderIfMissing(string parent, string child) { string path = parent + "/" + child; if (!AssetDatabase.IsValidFolder(path)) { AssetDatabase.CreateFolder(parent, child); } } private static void EnsureTag(string tag) { SerializedObject tagManager = new SerializedObject(AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/TagManager.asset")[0]); SerializedProperty tagsProperty = tagManager.FindProperty("tags"); for (int i = 0; i < tagsProperty.arraySize; i++) { SerializedProperty tagProperty = tagsProperty.GetArrayElementAtIndex(i); if (tagProperty.stringValue == tag) { return; } } tagsProperty.InsertArrayElementAtIndex(tagsProperty.arraySize); tagsProperty.GetArrayElementAtIndex(tagsProperty.arraySize - 1).stringValue = tag; tagManager.ApplyModifiedProperties(); } private static Material GetOrCreateMaterial(string path, Color color, bool transparent) { Material material = AssetDatabase.LoadAssetAtPath(path); if (material == null) { material = new Material(Shader.Find("Standard")); AssetDatabase.CreateAsset(material, path); } material.color = color; if (transparent) { ConfigureTransparentMaterial(material); } else { ConfigureOpaqueMaterial(material); } EditorUtility.SetDirty(material); return material; } private static void ConfigureTransparentMaterial(Material material) { 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 = 3000; } private static void ConfigureOpaqueMaterial(Material material) { material.SetFloat("_Mode", 0f); material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One); material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero); material.SetInt("_ZWrite", 1); material.DisableKeyword("_ALPHATEST_ON"); material.DisableKeyword("_ALPHABLEND_ON"); material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); material.renderQueue = -1; } private static GameObject CreateGround(Material material) { GameObject ground = GameObject.CreatePrimitive(PrimitiveType.Plane); ground.name = "Ground"; ground.transform.position = Vector3.zero; ground.transform.localScale = new Vector3(3f, 1f, 3f); ground.GetComponent().sharedMaterial = material; GameObjectUtility.SetStaticEditorFlags(ground, StaticEditorFlags.NavigationStatic); return ground; } private static void CreateObstacles(Material material) { CreateWall("Wall North", new Vector3(0f, 1f, 14f), new Vector3(28f, 2f, 1f), material); CreateWall("Wall South", new Vector3(0f, 1f, -14f), new Vector3(28f, 2f, 1f), material); CreateWall("Wall West", new Vector3(-14f, 1f, 0f), new Vector3(1f, 2f, 28f), material); CreateWall("Wall East", new Vector3(14f, 1f, 0f), new Vector3(1f, 2f, 28f), material); CreateWall("Center Block", new Vector3(0f, 1f, 0f), new Vector3(4f, 2f, 2f), material); CreateWall("Left Cover", new Vector3(-6f, 1f, -2f), new Vector3(2f, 2f, 6f), material); CreateWall("Right Cover", new Vector3(6f, 1f, -1.5f), new Vector3(2f, 2f, 5f), material); } private static GameObject CreateWall(string name, Vector3 position, Vector3 scale, Material material) { GameObject wall = GameObject.CreatePrimitive(PrimitiveType.Cube); wall.name = name; wall.transform.position = position; wall.transform.localScale = scale; wall.GetComponent().sharedMaterial = material; GameObjectUtility.SetStaticEditorFlags(wall, StaticEditorFlags.NavigationStatic); return wall; } private static Camera CreateCamera() { GameObject cameraObject = new GameObject("Main Camera"); Camera camera = cameraObject.AddComponent(); camera.tag = "MainCamera"; camera.transform.position = new Vector3(0f, 22f, -20f); camera.transform.rotation = Quaternion.Euler(55f, 0f, 0f); camera.orthographic = true; camera.orthographicSize = 16f; camera.clearFlags = CameraClearFlags.Skybox; camera.nearClipPlane = 0.3f; camera.farClipPlane = 100f; return camera; } private static void CreateLight() { GameObject lightObject = new GameObject("Directional Light"); Light light = lightObject.AddComponent(); light.type = LightType.Directional; light.intensity = 1.1f; light.transform.rotation = Quaternion.Euler(50f, -30f, 0f); } private static TerritoryUI CreateMainUI() { Font font = GetBuiltinFont(); GameObject canvasObject = new GameObject("Main UI Canvas"); Canvas canvas = canvasObject.AddComponent(); canvas.renderMode = RenderMode.ScreenSpaceOverlay; CanvasScaler scaler = canvasObject.AddComponent(); scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize; scaler.referenceResolution = new Vector2(1920f, 1080f); canvasObject.AddComponent(); TerritoryUI territoryUI = canvasObject.AddComponent(); Text title = CreateOverlayText("Title", canvasObject.transform, font, "Лабораторная работа №7 — Контроль территории", 24, TextAnchor.UpperLeft); SetRect(title.rectTransform, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(18f, -18f), new Vector2(760f, 38f)); Text controls = CreateOverlayText("Controls", canvasObject.transform, font, "WASD — движение\nЗахватите все контрольные точки", 18, TextAnchor.UpperLeft); SetRect(controls.rectTransform, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(18f, -56f), new Vector2(430f, 62f)); Text playerPoints = CreateOverlayText("Player Points", canvasObject.transform, font, "Player Points: 0", 20, TextAnchor.UpperLeft); playerPoints.color = new Color(0.25f, 0.55f, 1f); SetRect(playerPoints.rectTransform, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(18f, -124f), new Vector2(300f, 32f)); Text enemyPoints = CreateOverlayText("Enemy Points", canvasObject.transform, font, "Enemy Points: 0", 20, TextAnchor.UpperLeft); enemyPoints.color = new Color(1f, 0.32f, 0.25f); SetRect(enemyPoints.rectTransform, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(18f, -158f), new Vector2(300f, 32f)); Text zoneStatus = CreateOverlayText("Zone Status", canvasObject.transform, font, "Zone A: Neutral, 50%\nZone B: Neutral, 50%\nZone C: Neutral, 50%", 19, TextAnchor.UpperRight); SetRect(zoneStatus.rectTransform, new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(-18f, -18f), new Vector2(360f, 110f)); GameObject winPanel = CreateWinPanel(canvasObject.transform, font, out Text winText); territoryUI.playerPointsText = playerPoints; territoryUI.enemyPointsText = enemyPoints; territoryUI.zoneStatusText = zoneStatus; territoryUI.winPanel = winPanel; territoryUI.winText = winText; return territoryUI; } private static GameObject CreateWinPanel(Transform parent, Font font, out Text winText) { GameObject panel = new GameObject("Win Panel"); panel.transform.SetParent(parent, false); Image image = panel.AddComponent(); image.color = new Color(0f, 0f, 0f, 0.72f); RectTransform rectTransform = panel.GetComponent(); SetRect(rectTransform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, new Vector2(760f, 180f)); winText = CreateOverlayText("Win Text", panel.transform, font, "", 32, TextAnchor.MiddleCenter); winText.color = Color.white; SetRect(winText.rectTransform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, new Vector2(720f, 150f)); panel.SetActive(false); return panel; } private static Text CreateOverlayText(string name, Transform parent, Font font, string text, int fontSize, TextAnchor alignment) { GameObject textObject = new GameObject(name); textObject.transform.SetParent(parent, false); Text uiText = textObject.AddComponent(); uiText.font = font; uiText.text = text; uiText.fontSize = fontSize; uiText.alignment = alignment; uiText.color = Color.white; uiText.horizontalOverflow = HorizontalWrapMode.Wrap; uiText.verticalOverflow = VerticalWrapMode.Overflow; return uiText; } private static Font GetBuiltinFont() { Font font = Resources.GetBuiltinResource("LegacyRuntime.ttf"); if (font == null) { font = Resources.GetBuiltinResource("Arial.ttf"); } return font; } private static void SetRect(RectTransform rectTransform, Vector2 anchorMin, Vector2 anchorMax, Vector2 anchoredPosition, Vector2 size) { rectTransform.anchorMin = anchorMin; rectTransform.anchorMax = anchorMax; rectTransform.pivot = anchorMin == anchorMax ? anchorMin : new Vector2(0.5f, 0.5f); rectTransform.anchoredPosition = anchoredPosition; rectTransform.sizeDelta = size; } private static ResourceManager CreateResourceManager(TerritoryUI territoryUI) { GameObject managerObject = new GameObject("ResourceManager"); ResourceManager resourceManager = managerObject.AddComponent(); resourceManager.pointsText = territoryUI.playerPointsText; resourceManager.enemyPointsText = territoryUI.enemyPointsText; resourceManager.territoryUI = territoryUI; return resourceManager; } private static GameManager CreateGameManager(TerritoryUI territoryUI) { GameObject managerObject = new GameObject("GameManager"); GameManager gameManager = managerObject.AddComponent(); gameManager.territoryUI = territoryUI; gameManager.winPanel = territoryUI.winPanel; gameManager.winText = territoryUI.winText; gameManager.scoreLimit = 100; return gameManager; } private static PlayerController CreatePlayer(Material material) { GameObject playerObject = GameObject.CreatePrimitive(PrimitiveType.Capsule); playerObject.name = "Player"; playerObject.tag = "Player"; playerObject.transform.position = new Vector3(0f, 1f, 10f); playerObject.GetComponent().sharedMaterial = material; Object.DestroyImmediate(playerObject.GetComponent()); CharacterController controller = playerObject.AddComponent(); controller.radius = 0.5f; controller.height = 2f; controller.center = Vector3.zero; PlayerController player = playerObject.AddComponent(); player.moveSpeed = 6f; return player; } private static EnemyAI CreateEnemy(string name, Vector3 position, Material material) { GameObject enemyObject = GameObject.CreatePrimitive(PrimitiveType.Capsule); enemyObject.name = name; enemyObject.tag = "Enemy"; enemyObject.transform.position = position; enemyObject.GetComponent().sharedMaterial = material; Object.DestroyImmediate(enemyObject.GetComponent()); CharacterController controller = enemyObject.AddComponent(); controller.radius = 0.5f; controller.height = 2f; controller.center = Vector3.zero; Rigidbody rigidbody = enemyObject.AddComponent(); rigidbody.isKinematic = true; rigidbody.useGravity = false; NavMeshAgent agent = enemyObject.AddComponent(); agent.speed = 3.5f; agent.angularSpeed = 360f; agent.acceleration = 12f; agent.stoppingDistance = 0.7f; EnemyAI enemyAI = enemyObject.AddComponent(); enemyAI.moveSpeed = 3.5f; enemyAI.retargetInterval = 2f; enemyAI.randomFactor = 4f; return enemyAI; } private static CaptureZone CreateCaptureZone(string name, Vector3 position, Material sharedZoneMaterial, Camera mainCamera) { GameObject zoneObject = new GameObject(name); zoneObject.transform.position = position; SphereCollider trigger = zoneObject.AddComponent(); trigger.isTrigger = true; trigger.radius = 3.1f; CaptureZone zone = zoneObject.AddComponent(); zone.zoneName = name; zone.captureTime = 5f; zone.pointsPerSecond = 5; zone.currentOwner = CaptureZone.Owner.Neutral; zone.captureProgress = 0.5f; GameObject visual = GameObject.CreatePrimitive(PrimitiveType.Cylinder); visual.name = "Visual"; visual.transform.SetParent(zoneObject.transform, false); visual.transform.localPosition = Vector3.zero; visual.transform.localScale = new Vector3(6f, 0.035f, 6f); Object.DestroyImmediate(visual.GetComponent()); Renderer renderer = visual.GetComponent(); Material runtimeMaterial = new Material(sharedZoneMaterial); runtimeMaterial.name = name + " Runtime Zone Material"; renderer.sharedMaterial = runtimeMaterial; zone.zoneRenderer = renderer; CreateWorldZoneUI(zoneObject.transform, zone, mainCamera); return zone; } private static void CreateWorldZoneUI(Transform parent, CaptureZone zone, Camera mainCamera) { Font font = GetBuiltinFont(); GameObject canvasObject = new GameObject("World UI"); canvasObject.transform.SetParent(parent, false); canvasObject.transform.localPosition = new Vector3(0f, 3f, 0f); canvasObject.transform.localRotation = Quaternion.identity; canvasObject.transform.localScale = Vector3.one * 0.025f; Canvas canvas = canvasObject.AddComponent(); canvas.renderMode = RenderMode.WorldSpace; canvas.worldCamera = mainCamera; RectTransform canvasRect = canvas.GetComponent(); canvasRect.sizeDelta = new Vector2(220f, 80f); canvasObject.AddComponent(); Text label = CreateOverlayText("Label", canvasObject.transform, font, zone.zoneName + ": Neutral", 18, TextAnchor.MiddleCenter); label.color = Color.white; SetRect(label.rectTransform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -18f), new Vector2(220f, 34f)); Slider slider = CreateWorldSlider(canvasObject.transform, out Image fillImage); slider.value = 0.5f; ZoneUI zoneUI = canvasObject.AddComponent(); zoneUI.zone = zone; zoneUI.progressSlider = slider; zoneUI.labelText = label; zoneUI.fillImage = fillImage; zoneUI.targetCamera = mainCamera; } private static Slider CreateWorldSlider(Transform parent, out Image fillImage) { GameObject sliderObject = new GameObject("Progress Slider"); sliderObject.transform.SetParent(parent, false); Slider slider = sliderObject.AddComponent(); RectTransform sliderRect = sliderObject.GetComponent(); SetRect(sliderRect, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(0f, 20f), new Vector2(190f, 18f)); slider.minValue = 0f; slider.maxValue = 1f; slider.interactable = false; slider.transition = Selectable.Transition.None; GameObject backgroundObject = new GameObject("Background"); backgroundObject.transform.SetParent(sliderObject.transform, false); Image background = backgroundObject.AddComponent(); background.color = new Color(0f, 0f, 0f, 0.75f); RectTransform backgroundRect = background.GetComponent(); backgroundRect.anchorMin = Vector2.zero; backgroundRect.anchorMax = Vector2.one; backgroundRect.offsetMin = Vector2.zero; backgroundRect.offsetMax = Vector2.zero; GameObject fillAreaObject = new GameObject("Fill Area"); fillAreaObject.transform.SetParent(sliderObject.transform, false); RectTransform fillAreaRect = fillAreaObject.AddComponent(); fillAreaRect.anchorMin = Vector2.zero; fillAreaRect.anchorMax = Vector2.one; fillAreaRect.offsetMin = new Vector2(2f, 2f); fillAreaRect.offsetMax = new Vector2(-2f, -2f); GameObject fillObject = new GameObject("Fill"); fillObject.transform.SetParent(fillAreaObject.transform, false); fillImage = fillObject.AddComponent(); fillImage.color = new Color(1f, 0.82f, 0.08f, 1f); RectTransform fillRect = fillImage.GetComponent(); fillRect.anchorMin = Vector2.zero; fillRect.anchorMax = Vector2.one; fillRect.offsetMin = Vector2.zero; fillRect.offsetMax = Vector2.zero; slider.fillRect = fillRect; slider.targetGraphic = fillImage; return slider; } private static void BakeNavMeshIfAvailable(GameObject ground) { if (ground == null) { return; } try { UnityEditor.AI.NavMeshBuilder.ClearAllNavMeshes(); UnityEditor.AI.NavMeshBuilder.BuildNavMesh(); } catch (System.Exception exception) { Debug.LogWarning("NavMesh bake was skipped. EnemyAI fallback movement will still work. " + exception.Message); } } }