using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using UnityEngine.EventSystems; using UnityEngine.InputSystem.UI; using UnityEngine.Rendering.Universal; using UnityEditor; using UnityEditor.SceneManagement; using UnityEngine.SceneManagement; public static class MainMenuSceneBuilder { private static DefaultControls.Resources uiResources; private static Font standardFont; private static Font handwrittenFont; [MenuItem("Tools/Build Main Menu Scene")] public static string BuildScene() { standardFont = Resources.GetBuiltinResource("LegacyRuntime.ttf"); if (standardFont == null) standardFont = Resources.GetBuiltinResource("Arial.ttf"); // Загрузка рукописного шрифта для названия Synthesia handwrittenFont = AssetDatabase.LoadAssetAtPath("Assets/Fonts/SegoeScriptBold.ttf"); if (handwrittenFont == null) handwrittenFont = AssetDatabase.LoadAssetAtPath("Assets/Fonts/Inkfree.ttf"); if (handwrittenFont == null) handwrittenFont = AssetDatabase.LoadAssetAtPath("Assets/Fonts/MonotypeCorsiva.ttf"); if (handwrittenFont == null) handwrittenFont = standardFont; uiResources = new DefaultControls.Resources { standard = AssetDatabase.GetBuiltinExtraResource("UI/Skin/UISprite.psd"), background = AssetDatabase.GetBuiltinExtraResource("UI/Skin/Background.psd"), knob = AssetDatabase.GetBuiltinExtraResource("UI/Skin/Knob.psd"), checkmark = AssetDatabase.GetBuiltinExtraResource("UI/Skin/Checkmark.psd"), dropdown = AssetDatabase.GetBuiltinExtraResource("UI/Skin/DropdownArrow.psd"), mask = AssetDatabase.GetBuiltinExtraResource("UI/Skin/UIMask.psd") }; // Создаем новую пустую сцену Scene newScene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single); // 1. Камера (Абсолютно черный фон) GameObject camGo = new GameObject("Main Camera"); Camera cam = camGo.AddComponent(); cam.clearFlags = CameraClearFlags.SolidColor; cam.backgroundColor = Color.black; camGo.AddComponent(); camGo.AddComponent(); camGo.tag = "MainCamera"; camGo.transform.position = new Vector3(0, 0, -10); // 2. EventSystem GameObject eventSysGo = new GameObject("EventSystem"); eventSysGo.AddComponent(); eventSysGo.AddComponent(); // 3. Canvas (1920x1080) GameObject canvasGo = new GameObject("Canvas"); Canvas canvas = canvasGo.AddComponent(); canvas.renderMode = RenderMode.ScreenSpaceOverlay; canvas.pixelPerfect = true; CanvasScaler scaler = canvasGo.AddComponent(); scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize; scaler.referenceResolution = new Vector2(1920, 1080); scaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight; scaler.matchWidthOrHeight = 0.5f; canvasGo.AddComponent(); // 4. Менеджер Главного Меню GameObject managerGo = new GameObject("MainMenuManager"); MainMenuManager manager = managerGo.AddComponent(); // 5. Задний фон: Чистый глубокий черный цвет CreateImage("Background_Black", canvasGo.transform, Color.black, Vector2.zero, Vector2.one, Vector2.zero, Vector2.zero); // ========================================== // 6. АНИМИРОВАННЫЕ ЖЕЛТЫЕ ВОЛНЫ ЭХОЛОКАЦИИ В ПРАВОМ НИЖНЕМ УГЛУ // ========================================== GameObject radarRoot = CreateEmptyRect("Corner_Echolocation_Radar", canvasGo.transform, new Vector2(1f, 0f), new Vector2(1f, 0f), new Vector2(280f, 280f), new Vector2(-140f, 140f)); MenuEcholocationRadar echoRadar = radarRoot.AddComponent(); echoRadar.maxSimultaneousWaves = 3; echoRadar.waveMaxRadius = 1800f; // Расходится на весь экран echoRadar.waveSpeed = 180f; echoRadar.waveSpawnInterval = 2.4f; echoRadar.initialThickness = 110f; echoRadar.maxThickness = 360f; echoRadar.waveBaseColor = new Color(1.00f, 0.82f, 0.18f, 0.40f); // Теплая янтарная дымка echoRadar.waveCoreColor = new Color(1.00f, 0.94f, 0.50f, 0.65f); // Мягкое золотистое ядро echoRadar.beaconColor = new Color(1.00f, 0.88f, 0.20f, 0.85f); // Без лишних рамок/квадратов в углу — только чистые волны эхолокации echoRadar.radarBeaconDot = null; echoRadar.radarReticle = null; // ========================================== // 7. НАЗВАНИЕ ИГРЫ: "Synthesia" В ЦЕНТРЕ (РУКОПИСНЫЙ ШРИФТ) // ========================================== GameObject headerContainer = CreateEmptyRect("Header_Container", canvasGo.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(1100f, 200f), new Vector2(0f, 210f)); GameObject titleObj = CreateTextWithFont("Title_Synthesia", headerContainer.transform, "Synthesia", handwrittenFont, 110, FontStyle.Bold, TextAnchor.MiddleCenter, new Color(1.0f, 1.0f, 1.0f, 1.0f), Vector2.zero, Vector2.one, Vector2.zero, Vector2.zero); // Теплый желтый ореол свечения Outline titleGlow = titleObj.AddComponent(); titleGlow.effectColor = new Color(1.00f, 0.85f, 0.10f, 0.50f); titleGlow.effectDistance = new Vector2(2.5f, -2.5f); Shadow titleShadow = titleObj.AddComponent(); titleShadow.effectColor = new Color(0.12f, 0.10f, 0.00f, 0.80f); titleShadow.effectDistance = new Vector2(4f, -4f); // ========================================== // 8. КНОПКИ В ЦЕНТРЕ (БОЛЬШИЕ, ЯРКИЕ ЖЕЛТЫЕ, ОЧЕВИДНО НЕ ЧЕРНЫЕ) // ========================================== GameObject mainMenuPanel = CreateEmptyRect("MainMenuPanel", canvasGo.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(620f, 380f), new Vector2(0f, -110f)); VerticalLayoutGroup menuLayout = mainMenuPanel.AddComponent(); menuLayout.childAlignment = TextAnchor.MiddleCenter; menuLayout.spacing = 24f; menuLayout.childControlWidth = true; menuLayout.childControlHeight = true; menuLayout.childForceExpandWidth = true; menuLayout.childForceExpandHeight = false; // Яркий золотисто-желтый цвет кнопок с глубоким черным текстом (очевидно не черные) Color yellowBtnNormal = new Color(0.95f, 0.78f, 0.12f, 1.00f); Color yellowBtnHover = new Color(1.00f, 0.90f, 0.35f, 1.00f); Color yellowBtnPress = new Color(0.78f, 0.62f, 0.08f, 1.00f); Color blackBtnText = new Color(0.06f, 0.06f, 0.06f, 1.00f); // Кнопка 1: "ИГРАТЬ" Button playBtn = CreateBigMenuButton("Button_Play", mainMenuPanel.transform, "ИГРАТЬ", yellowBtnNormal, yellowBtnHover, yellowBtnPress, blackBtnText, 90f, 34); // Кнопка 2: "НАСТРОЙКИ" Button settingsBtn = CreateBigMenuButton("Button_Settings", mainMenuPanel.transform, "НАСТРОЙКИ", yellowBtnNormal, yellowBtnHover, yellowBtnPress, blackBtnText, 90f, 34); // Кнопка 3: "ВЫХОД" Button quitBtn = CreateBigMenuButton("Button_Quit", mainMenuPanel.transform, "ВЫХОД", yellowBtnNormal, yellowBtnHover, yellowBtnPress, blackBtnText, 90f, 34); // ========================================== // 9. ПАНЕЛЬ НАСТРОЕК (В ЧЕРНО-ЖЕЛТОМ СТИЛЕ) // ========================================== GameObject settingsPanel = CreateEmptyRect("SettingsPanel", canvasGo.transform, Vector2.zero, Vector2.one, Vector2.zero, Vector2.zero); // Затемняющий фон CreateImage("Backdrop_Dim", settingsPanel.transform, new Color(0.0f, 0.0f, 0.0f, 0.92f), Vector2.zero, Vector2.one, Vector2.zero, Vector2.zero); // Модальное окно настроек GameObject settingsCard = CreateImage("Settings_Card", settingsPanel.transform, new Color(0.04f, 0.04f, 0.04f, 0.98f), new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(920f, 740f), Vector2.zero); Outline panelOutline = settingsCard.AddComponent(); panelOutline.effectColor = new Color(1.00f, 0.85f, 0.10f, 0.55f); panelOutline.effectDistance = new Vector2(2f, -2f); CreateText("Settings_Header", settingsCard.transform, "НАСТРОЙКИ", 28, FontStyle.Bold, TextAnchor.MiddleCenter, new Color(1.00f, 0.85f, 0.10f, 1.0f), new Vector2(0.05f, 0.90f), new Vector2(0.95f, 0.98f), Vector2.zero, Vector2.zero); CreateImage("Settings_Divider", settingsCard.transform, new Color(1.00f, 0.85f, 0.10f, 0.40f), new Vector2(0.05f, 0.89f), new Vector2(0.95f, 0.895f), Vector2.zero, Vector2.zero); // Контейнер списка настроек GameObject settingsList = CreateEmptyRect("Settings_List", settingsCard.transform, new Vector2(0.06f, 0.14f), new Vector2(0.94f, 0.87f), Vector2.zero, Vector2.zero); VerticalLayoutGroup settingsLayout = settingsList.AddComponent(); settingsLayout.spacing = 15f; settingsLayout.childAlignment = TextAnchor.UpperCenter; settingsLayout.childControlWidth = true; settingsLayout.childControlHeight = false; settingsLayout.childForceExpandWidth = true; settingsLayout.childForceExpandHeight = false; // --- Раздел: Звук --- CreateCategoryHeader("HEADER_AUDIO", settingsList.transform, "— ЗВУК И ЭХОЛОКАЦИЯ —"); var volumeRow = CreateSliderRow("Row_Volume", settingsList.transform, "Громкость звука", 0f, 1f, 1f, "%"); Slider volSlider = volumeRow.slider; Text volText = volumeRow.valueText; Toggle muteToggle = CreateToggleRow("Row_Mute", settingsList.transform, "Отключить звук (Mute)"); // --- Раздел: Графика --- CreateCategoryHeader("HEADER_GRAPHICS", settingsList.transform, "— ГРАФИКА —"); Dropdown qualityDropdown = CreateDropdownRow("Row_Quality", settingsList.transform, "Качество графики"); Toggle fullscreenToggle = CreateToggleRow("Row_Fullscreen", settingsList.transform, "Полноэкранный режим"); Dropdown resolutionDropdown = CreateDropdownRow("Row_Resolution", settingsList.transform, "Разрешение экрана"); // --- Раздел: Управление --- CreateCategoryHeader("HEADER_CONTROLS", settingsList.transform, "— УПРАВЛЕНИЕ —"); var sensRow = CreateSliderRow("Row_Sensitivity", settingsList.transform, "Чувствительность мыши", 0.2f, 3.0f, 1.0f, "x"); Slider sensSlider = sensRow.slider; Text sensText = sensRow.valueText; // Нижняя строка кнопок в панели настроек GameObject bottomButtonsRow = CreateEmptyRect("Settings_BottomButtons", settingsCard.transform, new Vector2(0.06f, 0.03f), new Vector2(0.94f, 0.12f), Vector2.zero, Vector2.zero); HorizontalLayoutGroup bottomLayout = bottomButtonsRow.AddComponent(); bottomLayout.spacing = 30f; bottomLayout.childAlignment = TextAnchor.MiddleCenter; bottomLayout.childControlWidth = true; bottomLayout.childControlHeight = true; bottomLayout.childForceExpandWidth = true; bottomLayout.childForceExpandHeight = true; Button resetBtn = CreateBigMenuButton("Button_ResetDefaults", bottomButtonsRow.transform, "Сброс", new Color(0.35f, 0.15f, 0.15f, 1.0f), new Color(0.50f, 0.20f, 0.20f, 1.0f), new Color(0.65f, 0.25f, 0.25f, 1.0f), Color.white, 50f, 18); Button backBtn = CreateBigMenuButton("Button_Back", bottomButtonsRow.transform, "Применить и выйти", new Color(0.95f, 0.78f, 0.12f, 1.0f), new Color(1.00f, 0.90f, 0.35f, 1.0f), new Color(0.78f, 0.62f, 0.08f, 1.0f), new Color(0.06f, 0.06f, 0.06f, 1.0f), 50f, 18); // ========================================== // 10. ПАНЕЛЬ ЗАГРУЗКИ (LOADING PANEL) // ========================================== GameObject loadingPanel = CreateImage("LoadingPanel", canvasGo.transform, new Color(0f, 0f, 0f, 0.98f), Vector2.zero, Vector2.one, Vector2.zero, Vector2.zero); GameObject loadingContainer = CreateEmptyRect("Loading_Container", loadingPanel.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(640f, 220f), Vector2.zero); CreateTextWithFont("Loading_Title", loadingContainer.transform, "Synthesia", handwrittenFont, 52, FontStyle.Bold, TextAnchor.MiddleCenter, new Color(1.00f, 0.85f, 0.10f, 1.0f), new Vector2(0f, 0.65f), new Vector2(1f, 1f), Vector2.zero, Vector2.zero); GameObject sliderObj = DefaultControls.CreateSlider(uiResources); sliderObj.name = "Loading_ProgressBar"; sliderObj.transform.SetParent(loadingContainer.transform, false); RectTransform sliderRt = sliderObj.GetComponent(); sliderRt.anchorMin = new Vector2(0.05f, 0.38f); sliderRt.anchorMax = new Vector2(0.95f, 0.52f); sliderRt.offsetMin = Vector2.zero; sliderRt.offsetMax = Vector2.zero; Slider loadingSlider = sliderObj.GetComponent(); loadingSlider.interactable = false; Transform fillTransform = sliderObj.transform.Find("Fill Area/Fill"); if (fillTransform != null) { Image fillImg = fillTransform.GetComponent(); if (fillImg != null) fillImg.color = new Color(1.00f, 0.85f, 0.10f, 1f); } GameObject loadingPercent = CreateText("Loading_Text", loadingContainer.transform, "Загрузка...", 18, FontStyle.Normal, TextAnchor.MiddleCenter, new Color(0.95f, 0.95f, 0.95f, 0.9f), new Vector2(0f, 0f), new Vector2(1f, 0.30f), Vector2.zero, Vector2.zero); Text loadingText = loadingPercent.GetComponent(); // ========================================== // 11. ПРИВЯЗКА К MAINMENUMANAGER // ========================================== manager.headerContainer = headerContainer; manager.mainMenuPanel = mainMenuPanel; manager.settingsPanel = settingsPanel; manager.loadingPanel = loadingPanel; manager.loadingSlider = loadingSlider; manager.loadingText = loadingText; manager.volumeSlider = volSlider; manager.volumeValueText = volText; manager.muteToggle = muteToggle; manager.qualityDropdown = qualityDropdown; manager.fullscreenToggle = fullscreenToggle; manager.resolutionDropdown = resolutionDropdown; manager.sensitivitySlider = sensSlider; manager.sensitivityValueText = sensText; manager.gameSceneName = "SampleScene"; // Привязываем кнопки через UnityEvent UnityEditor.Events.UnityEventTools.AddPersistentListener(playBtn.onClick, manager.PlayGame); UnityEditor.Events.UnityEventTools.AddPersistentListener(settingsBtn.onClick, manager.OpenSettings); UnityEditor.Events.UnityEventTools.AddPersistentListener(quitBtn.onClick, manager.QuitGame); UnityEditor.Events.UnityEventTools.AddPersistentListener(resetBtn.onClick, manager.ResetToDefaults); UnityEditor.Events.UnityEventTools.AddPersistentListener(backBtn.onClick, manager.CloseSettings); // По умолчанию активны главное меню и радар settingsPanel.SetActive(false); loadingPanel.SetActive(false); mainMenuPanel.SetActive(true); headerContainer.SetActive(true); // Сохраняем сцену MainMenu string scenePath = "Assets/Scenes/MainMenu.unity"; EditorSceneManager.SaveScene(newScene, scenePath); Debug.Log("[MainMenuSceneBuilder] Сцена Synthesia MainMenu успешно создана: " + scenePath); // Добавляем в Build Settings при необходимости EnsureSceneInBuildSettings(scenePath, 0); return "SUCCESS: Minimalist Black & Yellow MainMenu 'Synthesia' successfully built!"; } private static void EnsureSceneInBuildSettings(string scenePath, int targetIndex) { List list = new List(EditorBuildSettings.scenes); for (int i = 0; i < list.Count; i++) { if (list[i].path == scenePath) { if (i != targetIndex && targetIndex < list.Count) { var item = list[i]; list.RemoveAt(i); list.Insert(targetIndex, item); EditorBuildSettings.scenes = list.ToArray(); } return; } } if (targetIndex >= 0 && targetIndex <= list.Count) list.Insert(targetIndex, new EditorBuildSettingsScene(scenePath, true)); else list.Add(new EditorBuildSettingsScene(scenePath, true)); EditorBuildSettings.scenes = list.ToArray(); } #region Хелперы UI private static GameObject CreateEmptyRect(string name, Transform parent, Vector2 anchorMin, Vector2 anchorMax, Vector2 sizeDelta, Vector2 anchoredPosition) { GameObject go = new GameObject(name, typeof(RectTransform)); go.transform.SetParent(parent, false); RectTransform rt = go.GetComponent(); rt.anchorMin = anchorMin; rt.anchorMax = anchorMax; rt.sizeDelta = sizeDelta; rt.anchoredPosition = anchoredPosition; return go; } private static GameObject CreateImage(string name, Transform parent, Color color, Vector2 anchorMin, Vector2 anchorMax, Vector2 sizeDelta, Vector2 anchoredPosition) { GameObject go = CreateEmptyRect(name, parent, anchorMin, anchorMax, sizeDelta, anchoredPosition); Image img = go.AddComponent(); img.color = color; return go; } private static GameObject CreateText(string name, Transform parent, string text, int fontSize, FontStyle style, TextAnchor alignment, Color color, Vector2 anchorMin, Vector2 anchorMax, Vector2 sizeDelta, Vector2 anchoredPosition) { return CreateTextWithFont(name, parent, text, standardFont, fontSize, style, alignment, color, anchorMin, anchorMax, sizeDelta, anchoredPosition); } private static GameObject CreateTextWithFont(string name, Transform parent, string text, Font font, int fontSize, FontStyle style, TextAnchor alignment, Color color, Vector2 anchorMin, Vector2 anchorMax, Vector2 sizeDelta, Vector2 anchoredPosition) { GameObject go = CreateEmptyRect(name, parent, anchorMin, anchorMax, sizeDelta, anchoredPosition); Text t = go.AddComponent(); t.font = font != null ? font : standardFont; t.text = text; t.fontSize = fontSize; t.fontStyle = style; t.alignment = alignment; t.color = color; t.horizontalOverflow = HorizontalWrapMode.Overflow; t.verticalOverflow = VerticalWrapMode.Overflow; return go; } private static Button CreateBigMenuButton(string name, Transform parent, string label, Color normalColor, Color highlightedColor, Color pressedColor, Color textColor, float height, int fontSize) { GameObject btnObj = DefaultControls.CreateButton(uiResources); btnObj.name = name; btnObj.transform.SetParent(parent, false); RectTransform rt = btnObj.GetComponent(); if (rt != null) { rt.sizeDelta = new Vector2(rt.sizeDelta.x, height); } LayoutElement layout = btnObj.AddComponent(); layout.minHeight = height; layout.preferredHeight = height; Image img = btnObj.GetComponent(); img.color = normalColor; img.type = Image.Type.Sliced; // Выразительная окантовка кнопки Outline btnOutline = btnObj.AddComponent(); btnOutline.effectColor = new Color(1.00f, 0.95f, 0.60f, 0.70f); btnOutline.effectDistance = new Vector2(2f, -2f); Shadow btnShadow = btnObj.AddComponent(); btnShadow.effectColor = new Color(0.00f, 0.00f, 0.00f, 0.50f); btnShadow.effectDistance = new Vector2(3f, -3f); Button btn = btnObj.GetComponent