Kursach_StealthAction/Assets/Scripts/Editor/PauseMenuBuilder.cs

460 lines
21 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem.UI;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine.SceneManagement;
public static class PauseMenuBuilder
{
private static DefaultControls.Resources uiResources;
private static Font standardFont;
[MenuItem("Tools/Add Pause Menu to SampleScene")]
public static string Build()
{
standardFont = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
if (standardFont == null)
standardFont = Resources.GetBuiltinResource<Font>("Arial.ttf");
uiResources = new DefaultControls.Resources
{
standard = AssetDatabase.GetBuiltinExtraResource<Sprite>("UI/Skin/UISprite.psd"),
background = AssetDatabase.GetBuiltinExtraResource<Sprite>("UI/Skin/Background.psd"),
knob = AssetDatabase.GetBuiltinExtraResource<Sprite>("UI/Skin/Knob.psd"),
checkmark = AssetDatabase.GetBuiltinExtraResource<Sprite>("UI/Skin/Checkmark.psd"),
dropdown = AssetDatabase.GetBuiltinExtraResource<Sprite>("UI/Skin/DropdownArrow.psd"),
mask = AssetDatabase.GetBuiltinExtraResource<Sprite>("UI/Skin/UIMask.psd")
};
// Открываем сцену геймплея
Scene gameplayScene = EditorSceneManager.OpenScene("Assets/Scenes/SampleScene.unity", OpenSceneMode.Single);
// Проверяем EventSystem
if (Object.FindAnyObjectByType<EventSystem>() == null)
{
GameObject esGo = new GameObject("EventSystem");
esGo.AddComponent<EventSystem>();
esGo.AddComponent<InputSystemUIInputModule>();
}
// Пересоздаем PauseCanvas
var old = GameObject.Find("PauseCanvas");
if (old != null) Object.DestroyImmediate(old);
// Создаем Canvas паузы
GameObject canvasGo = new GameObject("PauseCanvas");
Canvas canvas = canvasGo.AddComponent<Canvas>();
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
canvas.sortingOrder = 100; // Поверх игрового мира
CanvasScaler scaler = canvasGo.AddComponent<CanvasScaler>();
scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
scaler.referenceResolution = new Vector2(1920, 1080);
scaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight;
scaler.matchWidthOrHeight = 0.5f;
canvasGo.AddComponent<GraphicRaycaster>();
PauseMenu pauseMenu = canvasGo.AddComponent<PauseMenu>();
// Цвета стилистики Главного Меню (Synthesia Minimalist Black & Yellow)
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. КАРТОЧКА МЕНЮ ПАУЗЫ (PauseMenuPanel)
// ==========================================
GameObject pausePanel = CreateImage("PauseMenuPanel", canvasGo.transform,
new Color(0.0f, 0.0f, 0.0f, 0.88f),
Vector2.zero, Vector2.one, Vector2.zero, Vector2.zero);
GameObject pauseCard = CreateImage("Pause_Card", pausePanel.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(480f, 560f), Vector2.zero);
Outline cardOutline = pauseCard.AddComponent<Outline>();
cardOutline.effectColor = new Color(1.00f, 0.85f, 0.10f, 0.55f);
cardOutline.effectDistance = new Vector2(2f, -2f);
CreateText("Pause_Title", pauseCard.transform,
"ПАУЗА",
34, FontStyle.Bold, TextAnchor.MiddleCenter,
new Color(1.00f, 0.85f, 0.10f, 1.0f),
new Vector2(0.05f, 0.86f), new Vector2(0.95f, 0.97f), Vector2.zero, Vector2.zero);
CreateImage("Pause_Divider", pauseCard.transform,
new Color(1.00f, 0.85f, 0.10f, 0.40f),
new Vector2(0.08f, 0.84f), new Vector2(0.92f, 0.845f), Vector2.zero, Vector2.zero);
GameObject btnContainer = CreateEmptyRect("Buttons_Container", pauseCard.transform,
new Vector2(0.08f, 0.05f), new Vector2(0.92f, 0.81f), Vector2.zero, Vector2.zero);
VerticalLayoutGroup vLayout = btnContainer.AddComponent<VerticalLayoutGroup>();
vLayout.spacing = 16f;
vLayout.childAlignment = TextAnchor.MiddleCenter;
vLayout.childControlWidth = true;
vLayout.childControlHeight = false;
vLayout.childForceExpandWidth = true;
vLayout.childForceExpandHeight = false;
// Кнопки меню паузы
Button resumeBtn = CreateStyledButton("Btn_Resume", btnContainer.transform,
"► ПРОДОЛЖИТЬ",
yellowBtnNormal, yellowBtnHover, yellowBtnPress, blackBtnText, 62f, 20);
Button settingsBtn = CreateStyledButton("Btn_Settings", btnContainer.transform,
"⚙ НАСТРОЙКИ",
yellowBtnNormal, yellowBtnHover, yellowBtnPress, blackBtnText, 62f, 20);
Button restartBtn = CreateStyledButton("Btn_Restart", btnContainer.transform,
"↺ ЗАНОВО",
yellowBtnNormal, yellowBtnHover, yellowBtnPress, blackBtnText, 62f, 20);
Button menuBtn = CreateStyledButton("Btn_MainMenu", btnContainer.transform,
"⌂ ГЛАВНОЕ МЕНЮ",
yellowBtnNormal, yellowBtnHover, yellowBtnPress, blackBtnText, 62f, 20);
Button quitBtn = CreateStyledButton("Btn_Quit", btnContainer.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, 62f, 20);
// ==========================================
// 2. ПАНЕЛЬ НАСТРОЕК (SettingsPanel) - ТОЧНО КАК В ГЛАВНОМ МЕНЮ
// ==========================================
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<Outline>();
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<VerticalLayoutGroup>();
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<HorizontalLayoutGroup>();
bottomLayout.spacing = 30f;
bottomLayout.childAlignment = TextAnchor.MiddleCenter;
bottomLayout.childControlWidth = true;
bottomLayout.childControlHeight = true;
bottomLayout.childForceExpandWidth = true;
bottomLayout.childForceExpandHeight = true;
Button resetBtn = CreateStyledButton("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 = CreateStyledButton("Button_Back", bottomButtonsRow.transform,
"Применить и выйти",
yellowBtnNormal, yellowBtnHover, yellowBtnPress, blackBtnText,
50f, 18);
// ==========================================
// 3. ПРИВЯЗКА К СИСТЕМЕ PAUSEMENU
// ==========================================
pauseMenu.pauseMenuPanel = pausePanel;
pauseMenu.settingsPanel = settingsPanel;
pauseMenu.resumeButton = resumeBtn;
pauseMenu.settingsButton = settingsBtn;
pauseMenu.restartButton = restartBtn;
pauseMenu.mainMenuButton = menuBtn;
pauseMenu.quitButton = quitBtn;
pauseMenu.backFromSettingsButton = backBtn;
pauseMenu.resetDefaultsButton = resetBtn;
// Привязываем обработчики через UnityEvent для отображения в Инспекторе
UnityEditor.Events.UnityEventTools.AddPersistentListener(resumeBtn.onClick, pauseMenu.ResumeGame);
UnityEditor.Events.UnityEventTools.AddPersistentListener(settingsBtn.onClick, pauseMenu.OpenSettings);
UnityEditor.Events.UnityEventTools.AddPersistentListener(restartBtn.onClick, pauseMenu.RestartGame);
UnityEditor.Events.UnityEventTools.AddPersistentListener(menuBtn.onClick, pauseMenu.ReturnToMainMenu);
UnityEditor.Events.UnityEventTools.AddPersistentListener(quitBtn.onClick, pauseMenu.QuitGame);
UnityEditor.Events.UnityEventTools.AddPersistentListener(backBtn.onClick, pauseMenu.CloseSettings);
UnityEditor.Events.UnityEventTools.AddPersistentListener(resetBtn.onClick, pauseMenu.ResetToDefaults);
pauseMenu.volumeSlider = volSlider;
pauseMenu.volumeValueText = volText;
pauseMenu.muteToggle = muteToggle;
pauseMenu.qualityDropdown = qualityDropdown;
pauseMenu.fullscreenToggle = fullscreenToggle;
pauseMenu.resolutionDropdown = resolutionDropdown;
pauseMenu.sensitivitySlider = sensSlider;
pauseMenu.sensitivityValueText = sensText;
pausePanel.SetActive(false);
settingsPanel.SetActive(false);
// Также гарантируем экран смерти
DeathScreenBuilder.Build();
EditorSceneManager.MarkSceneDirty(gameplayScene);
EditorSceneManager.SaveScene(gameplayScene);
Debug.Log("[PauseMenuBuilder] PauseCanvas в стиле MainMenu успешно создан и сохранен в SampleScene.unity");
return "SUCCESS: PauseMenu rebuilt with separate Settings panel matching MainMenu style!";
}
#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<RectTransform>();
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<Image>();
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)
{
GameObject go = CreateEmptyRect(name, parent, anchorMin, anchorMax, sizeDelta, anchoredPosition);
Text t = go.AddComponent<Text>();
t.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 CreateStyledButton(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<RectTransform>();
if (rt != null)
{
rt.sizeDelta = new Vector2(rt.sizeDelta.x, height);
}
LayoutElement layout = btnObj.AddComponent<LayoutElement>();
layout.minHeight = height;
layout.preferredHeight = height;
Image img = btnObj.GetComponent<Image>();
img.color = normalColor;
img.type = Image.Type.Sliced;
Outline btnOutline = btnObj.AddComponent<Outline>();
btnOutline.effectColor = new Color(1.00f, 0.95f, 0.60f, 0.65f);
btnOutline.effectDistance = new Vector2(2f, -2f);
Shadow btnShadow = btnObj.AddComponent<Shadow>();
btnShadow.effectColor = new Color(0.00f, 0.00f, 0.00f, 0.50f);
btnShadow.effectDistance = new Vector2(2f, -2f);
Button btn = btnObj.GetComponent<Button>();
ColorBlock colors = btn.colors;
colors.normalColor = normalColor;
colors.highlightedColor = highlightedColor;
colors.pressedColor = pressedColor;
colors.selectedColor = highlightedColor;
colors.colorMultiplier = 1f;
colors.fadeDuration = 0.12f;
btn.colors = colors;
Text text = btnObj.GetComponentInChildren<Text>();
if (text != null)
{
text.font = standardFont;
text.text = label;
text.fontSize = fontSize;
text.fontStyle = FontStyle.Bold;
text.color = textColor;
text.alignment = TextAnchor.MiddleCenter;
text.horizontalOverflow = HorizontalWrapMode.Overflow;
text.verticalOverflow = VerticalWrapMode.Overflow;
}
return btn;
}
private static void CreateCategoryHeader(string name, Transform parent, string text)
{
GameObject go = CreateEmptyRect(name, parent, Vector2.zero, Vector2.one, new Vector2(0f, 32f), Vector2.zero);
LayoutElement layout = go.AddComponent<LayoutElement>();
layout.minHeight = 32f;
layout.preferredHeight = 32f;
Text t = go.AddComponent<Text>();
t.font = standardFont;
t.text = text;
t.fontSize = 16;
t.fontStyle = FontStyle.Bold;
t.alignment = TextAnchor.MiddleLeft;
t.color = new Color(1.00f, 0.85f, 0.10f, 0.95f);
}
private static (Slider slider, Text valueText) CreateSliderRow(string name, Transform parent, string label, float min, float max, float def, string unitSuffix)
{
GameObject row = CreateEmptyRect(name, parent, Vector2.zero, Vector2.one, new Vector2(0f, 44f), Vector2.zero);
LayoutElement layout = row.AddComponent<LayoutElement>();
layout.minHeight = 44f;
layout.preferredHeight = 44f;
CreateText("Label", row.transform, label, 16, FontStyle.Normal, TextAnchor.MiddleLeft,
new Color(0.92f, 0.92f, 0.92f, 1f), new Vector2(0f, 0f), new Vector2(0.40f, 1f), Vector2.zero, Vector2.zero);
GameObject sliderObj = DefaultControls.CreateSlider(uiResources);
sliderObj.name = "Slider";
sliderObj.transform.SetParent(row.transform, false);
RectTransform sliderRt = sliderObj.GetComponent<RectTransform>();
sliderRt.anchorMin = new Vector2(0.42f, 0.20f);
sliderRt.anchorMax = new Vector2(0.82f, 0.80f);
sliderRt.offsetMin = Vector2.zero;
sliderRt.offsetMax = Vector2.zero;
Slider slider = sliderObj.GetComponent<Slider>();
slider.minValue = min;
slider.maxValue = max;
slider.value = def;
Transform fill = sliderObj.transform.Find("Fill Area/Fill");
if (fill != null)
{
var img = fill.GetComponent<Image>();
if (img != null) img.color = new Color(1.00f, 0.85f, 0.10f, 1f);
}
GameObject valueTextObj = CreateText("ValueText", row.transform,
unitSuffix == "%" ? $"{Mathf.RoundToInt(def * 100)}%" : $"{def:F1}{unitSuffix}",
15, FontStyle.Bold, TextAnchor.MiddleRight,
new Color(1.00f, 0.85f, 0.10f, 1f), new Vector2(0.84f, 0f), new Vector2(1f, 1f), Vector2.zero, Vector2.zero);
return (slider, valueTextObj.GetComponent<Text>());
}
private static Toggle CreateToggleRow(string name, Transform parent, string label)
{
GameObject row = CreateEmptyRect(name, parent, Vector2.zero, Vector2.one, new Vector2(0f, 40f), Vector2.zero);
LayoutElement layout = row.AddComponent<LayoutElement>();
layout.minHeight = 40f;
layout.preferredHeight = 40f;
CreateText("Label", row.transform, label, 16, FontStyle.Normal, TextAnchor.MiddleLeft,
new Color(0.92f, 0.92f, 0.92f, 1f), new Vector2(0f, 0f), new Vector2(0.70f, 1f), Vector2.zero, Vector2.zero);
GameObject toggleObj = DefaultControls.CreateToggle(uiResources);
toggleObj.name = "Toggle";
toggleObj.transform.SetParent(row.transform, false);
RectTransform rt = toggleObj.GetComponent<RectTransform>();
rt.anchorMin = new Vector2(0.85f, 0.15f);
rt.anchorMax = new Vector2(1f, 0.85f);
rt.offsetMin = Vector2.zero;
rt.offsetMax = Vector2.zero;
Text defaultLabel = toggleObj.GetComponentInChildren<Text>();
if (defaultLabel != null) Object.DestroyImmediate(defaultLabel.gameObject);
return toggleObj.GetComponent<Toggle>();
}
private static Dropdown CreateDropdownRow(string name, Transform parent, string label)
{
GameObject row = CreateEmptyRect(name, parent, Vector2.zero, Vector2.one, new Vector2(0f, 44f), Vector2.zero);
LayoutElement layout = row.AddComponent<LayoutElement>();
layout.minHeight = 44f;
layout.preferredHeight = 44f;
CreateText("Label", row.transform, label, 16, FontStyle.Normal, TextAnchor.MiddleLeft,
new Color(0.92f, 0.92f, 0.92f, 1f), new Vector2(0f, 0f), new Vector2(0.40f, 1f), Vector2.zero, Vector2.zero);
GameObject ddObj = DefaultControls.CreateDropdown(uiResources);
ddObj.name = "Dropdown";
ddObj.transform.SetParent(row.transform, false);
RectTransform rt = ddObj.GetComponent<RectTransform>();
rt.anchorMin = new Vector2(0.42f, 0.10f);
rt.anchorMax = new Vector2(1f, 0.90f);
rt.offsetMin = Vector2.zero;
rt.offsetMax = Vector2.zero;
Image img = ddObj.GetComponent<Image>();
if (img != null) img.color = new Color(0.12f, 0.12f, 0.12f, 1f);
return ddObj.GetComponent<Dropdown>();
}
#endregion
}