From 57fc7e00068b2a24940699b8d4c682e4c38e5f43 Mon Sep 17 00:00:00 2001 From: Alexander Date: Mon, 19 Oct 2026 18:41:43 +0200 Subject: [PATCH] =?UTF-8?q?HUD=20=D1=83=D1=87=D0=B8=D1=82=D1=8B=D0=B2?= =?UTF-8?q?=D0=B0=D0=B5=D1=82=20Safe=20Area=20(=D0=B2=D1=8B=D1=80=D0=B5?= =?UTF-8?q?=D0=B7,=20=D1=81=D0=BA=D1=80=D1=83=D0=B3=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F,=20=D0=BF=D0=BE=D0=BB=D0=BE=D1=81=D0=BA=D0=B0=20?= =?UTF-8?q?=C2=AB=D0=B4=D0=BE=D0=BC=D0=BE=D0=B9=C2=BB)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - UI/SafeArea: подгоняет контейнер под Screen.safeArea, следит за поворотом - UI/SafeAreaInstaller: при загрузке сцены переносит элементы HUD_Canvas и WorldMap_Canvas в контейнер SafeArea; окна на весь экран остаются на весь экран Co-Authored-By: Claude Opus 5.5 --- Assets/Scripts/UI/SafeArea.cs | 38 ++++++++++++ Assets/Scripts/UI/SafeArea.cs.meta | 2 + Assets/Scripts/UI/SafeAreaInstaller.cs | 64 +++++++++++++++++++++ Assets/Scripts/UI/SafeAreaInstaller.cs.meta | 2 + Docs/Modules/README.md | 1 + 5 files changed, 107 insertions(+) create mode 100644 Assets/Scripts/UI/SafeArea.cs create mode 100644 Assets/Scripts/UI/SafeArea.cs.meta create mode 100644 Assets/Scripts/UI/SafeAreaInstaller.cs create mode 100644 Assets/Scripts/UI/SafeAreaInstaller.cs.meta diff --git a/Assets/Scripts/UI/SafeArea.cs b/Assets/Scripts/UI/SafeArea.cs new file mode 100644 index 0000000..b3c712f --- /dev/null +++ b/Assets/Scripts/UI/SafeArea.cs @@ -0,0 +1,38 @@ +using UnityEngine; + +// Подгоняет RectTransform под безопасную зону экрана (Screen.safeArea): вырез камеры, скруглённые углы, +// полоска "домой" на iPhone. Следит за поворотом и сменой разрешения (и в Device Simulator). +// Вешать на растянутый на весь Canvas объект; всё, что внутри, не залезет под вырез. +[RequireComponent(typeof(RectTransform))] +public class SafeArea : MonoBehaviour +{ + private RectTransform rect; + private Rect appliedArea; + private Vector2Int appliedScreen; + + void Awake() + { + rect = GetComponent(); + Apply(); + } + + void Update() + { + if (Screen.safeArea != appliedArea || Screen.width != appliedScreen.x || Screen.height != appliedScreen.y) + Apply(); + } + + void Apply() + { + Rect area = Screen.safeArea; + appliedArea = area; + appliedScreen = new Vector2Int(Screen.width, Screen.height); + if (Screen.width <= 0 || Screen.height <= 0) return; + + // Якоря в долях экрана: Canvas в режиме Screen Space Overlay покрывает экран целиком + rect.anchorMin = new Vector2(area.xMin / Screen.width, area.yMin / Screen.height); + rect.anchorMax = new Vector2(area.xMax / Screen.width, area.yMax / Screen.height); + rect.offsetMin = Vector2.zero; + rect.offsetMax = Vector2.zero; + } +} diff --git a/Assets/Scripts/UI/SafeArea.cs.meta b/Assets/Scripts/UI/SafeArea.cs.meta new file mode 100644 index 0000000..9fa0816 --- /dev/null +++ b/Assets/Scripts/UI/SafeArea.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 282b2b2a77a0def428cbc2209b881107 \ No newline at end of file diff --git a/Assets/Scripts/UI/SafeAreaInstaller.cs b/Assets/Scripts/UI/SafeAreaInstaller.cs new file mode 100644 index 0000000..5a43e9a --- /dev/null +++ b/Assets/Scripts/UI/SafeAreaInstaller.cs @@ -0,0 +1,64 @@ +using UnityEngine; +using UnityEngine.SceneManagement; + +// Сам ставит Safe Area на экранные Canvas при загрузке каждой сцены (город, карта мира). +// Руками в сцене ничего делать не нужно, и пересборка HUD через Tools не сломает настройку. +// +// Правило: всё, что растянуто на весь экран (фоны и окна поверх игры: BuildMenuPanel, Panels), +// остаётся на весь экран. Остальные элементы (верхняя и нижняя панели, кнопки по краям, чат, окна +// по центру) переезжают в контейнер "SafeArea" и не залезают под вырез и скругления экрана. +public static class SafeAreaInstaller +{ + const string ContainerName = "SafeArea"; + + // Canvas, которые подгоняются под безопасную зону + static readonly string[] CanvasNames = { "HUD_Canvas", "WorldMap_Canvas" }; + + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)] + static void Init() + { + InstallAll(); + SceneManager.sceneLoaded += (scene, mode) => InstallAll(); + } + + static void InstallAll() + { + foreach (var name in CanvasNames) + { + var go = GameObject.Find(name); + if (go != null) Install(go.GetComponent()); + } + } + + public static void Install(RectTransform canvasRect) + { + if (canvasRect == null || canvasRect.Find(ContainerName) != null) return; + + var container = new GameObject(ContainerName, typeof(RectTransform)).GetComponent(); + container.SetParent(canvasRect, false); + container.anchorMin = Vector2.zero; + container.anchorMax = Vector2.one; + container.offsetMin = Vector2.zero; + container.offsetMax = Vector2.zero; + + // Контейнер -- первым: окна на весь экран остаются поверх HUD + container.SetSiblingIndex(0); + + // Пока контейнер совпадает с Canvas, перенос сохраняет раскладку один в один + for (int i = canvasRect.childCount - 1; i >= 0; i--) + { + var child = canvasRect.GetChild(i) as RectTransform; + if (child == null || child == container || IsFullScreen(child)) continue; + child.SetParent(container, false); + child.SetSiblingIndex(0); // обход с конца -- порядок отрисовки сохраняется + } + + container.gameObject.AddComponent(); // а теперь сжимаем под безопасную зону + } + + // Растянут на весь экран без отступов -- это фон или окно поверх игры + static bool IsFullScreen(RectTransform rt) + { + return rt.anchorMin == Vector2.zero && rt.anchorMax == Vector2.one; + } +} diff --git a/Assets/Scripts/UI/SafeAreaInstaller.cs.meta b/Assets/Scripts/UI/SafeAreaInstaller.cs.meta new file mode 100644 index 0000000..90c9232 --- /dev/null +++ b/Assets/Scripts/UI/SafeAreaInstaller.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 4ea5be4ca2881df479ea683302268991 \ No newline at end of file diff --git a/Docs/Modules/README.md b/Docs/Modules/README.md index 8201119..09e5545 100644 --- a/Docs/Modules/README.md +++ b/Docs/Modules/README.md @@ -58,5 +58,6 @@ EditMode-тесты: `Assets/Scripts/Modules/Tests/ModuleTests.cs`. Запуск | Дата | Кто | Что | | --- | --- | --- | +| 19.10.2026 | Claude | Слой приложения: HUD города и карты мира учитывает Safe Area (`UI/SafeArea.cs`, `UI/SafeAreaInstaller.cs`). Элементы, растянутые на весь экран, остаются на весь экран. | | 19.10.2026 | Claude | Добавлен сброс сохранений (Настройки, меню Tools, `ISaveSystem.ResetAll`). Обновлены Core, Economy, Settlement, World, Save. | | 19.10.2026 | Claude | Создана модульная система: ядро, шесть модулей, точка сборки `App/GameModules`, тесты, документы модулей. Ветка `feature/modules`. |