using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using TMPro; // ГЛОБАЛЬНАЯ КАРТА (панель "Мир"). // Слева/сверху -- карта: ваш город, два тестовых поселения, маршруты, армии в пути с таймерами. // Справа/снизу -- информация: армия в городе, выбранное поселение, походы, отчёты о боях, // и окно отправки войск (сколько каких воинов, время в пути, шанс победы). public class WorldMapPanel : BasePanel { string selectedId = "bandits"; bool sendMode; readonly int[] sendUnits = new int[4]; // то, что обновляется каждый кадр без перерисовки class MarchView { public WorldMarch m; public RectTransform marker; public TextMeshProUGUI label; public TextMeshProUGUI timer; } readonly List marchViews = new List(); readonly List> listTimers = new List>(); readonly Dictionary ruinTimers = new Dictionary(); readonly TextMeshProUGUI[] sendCounts = new TextMeshProUGUI[4]; TextMeshProUGUI sendSummary; Button sendButton; protected override void OnEnable() { base.OnEnable(); sendMode = false; } protected override void Build(RectTransform root) { marchViews.Clear(); listTimers.Clear(); ruinTimers.Clear(); sendSummary = null; sendButton = null; for (int i = 0; i < 4; i++) sendCounts[i] = null; bool wide = root.rect.width > root.rect.height * 1.2f; RectTransform layout; if (wide) { layout = UIKit.Stretch(UIKit.Row(root, -1, 16)); } else { layout = UIKit.Stretch(UIKit.Card(root, new Color(0, 0, 0, 0), 0, 12)); } // --- карта --- var mapHolder = UIKit.Box(layout, new Color(0.16f, 0.27f, 0.17f)); var mapLe = UIKit.Size(mapHolder, -1, -1, 1); mapLe.flexibleHeight = wide ? 1 : 1.3f; BuildMap((RectTransform)mapHolder.transform); // --- боковая колонка --- var side = UIKit.Make("Side", layout); var sideLe = UIKit.Size(side, wide ? 640 : -1, -1); sideLe.flexibleHeight = 1; if (!wide) sideLe.flexibleWidth = 1; var list = ScrollList(side, 12); if (sendMode) BuildSend(list); else BuildInfo(list); Tick(); } // ===================== КАРТА ===================== void BuildMap(RectTransform map) { map.gameObject.AddComponent(); // декорации: "леса", "горы", "озеро" -- просто пятна, чтобы карта не была пустой var rnd = new System.Random(7); for (int i = 0; i < 26; i++) { float x = (float)rnd.NextDouble(), y = (float)rnd.NextDouble(); int kind = rnd.Next(3); Color c = kind == 0 ? new Color(0.11f, 0.21f, 0.12f) : (kind == 1 ? new Color(0.35f, 0.35f, 0.33f) : new Color(0.2f, 0.32f, 0.45f)); float s = 30 + (float)rnd.NextDouble() * 60; var blob = UIKit.Box(map, c); blob.raycastTarget = false; var brt = blob.rectTransform; brt.anchorMin = brt.anchorMax = new Vector2(x, y); brt.sizeDelta = new Vector2(s, s * 0.7f); brt.localRotation = Quaternion.Euler(0, 0, rnd.Next(0, 90)); } // сетка for (int i = 1; i < 5; i++) { Line(map, new Vector2(i / 5f, 0), new Vector2(i / 5f, 1), new Color(1, 1, 1, 0.05f), 2); Line(map, new Vector2(0, i / 5f), new Vector2(1, i / 5f), new Color(1, 1, 1, 0.05f), 2); } var home = WorldData.Home; // постоянные дороги от города к поселениям foreach (var s in WorldData.Settlements) if (!s.isHome) Line(map, home.pos, s.pos, new Color(0.85f, 0.75f, 0.5f, 0.25f), 5); // активные маршруты -- ярче foreach (var m in GP.Data.marches) { var target = WorldData.Get(m.targetId); if (target == null) continue; Line(map, home.pos, target.pos, m.returning ? new Color(0.4f, 0.9f, 0.5f, 0.8f) : new Color(1f, 0.55f, 0.2f, 0.85f), 8); } // поселения foreach (var s in WorldData.Settlements) SettlementIcon(map, s); // армии в пути foreach (var m in GP.Data.marches) { var v = new MarchView { m = m }; var marker = UIKit.Box(map, m.returning ? new Color(0.2f, 0.7f, 0.3f) : new Color(0.95f, 0.5f, 0.15f)); marker.raycastTarget = false; v.marker = marker.rectTransform; v.marker.sizeDelta = new Vector2(64, 64); v.label = UIKit.Text(v.marker, WorldSystem.Count(m.returning ? m.survivors : m.units).ToString(), 26, Color.white, TextAlignmentOptions.Center); UIKit.Stretch(v.label.rectTransform); v.label.fontStyle = FontStyles.Bold; v.timer = UIKit.Text(v.marker, "", 24, Color.white, TextAlignmentOptions.Center); var trt = v.timer.rectTransform; trt.anchorMin = new Vector2(0.5f, 1); trt.anchorMax = new Vector2(0.5f, 1); trt.pivot = new Vector2(0.5f, 0); trt.sizeDelta = new Vector2(220, 34); trt.anchoredPosition = new Vector2(0, 4); v.timer.outlineWidth = 0.25f; v.timer.outlineColor = Color.black; marchViews.Add(v); } Frame(); } void SettlementIcon(RectTransform map, SettlementDef s) { var st = s.isHome ? null : WorldSystem.State(s.id); bool ruined = !s.isHome && WorldSystem.IsRuined(s.id, System.DateTime.UtcNow.Ticks); bool selected = s.id == selectedId; float size = s.isHome ? 130 : 110; if (selected) { // золотая рамка выбранного поселения (под иконкой) var ring = UIKit.Box(map, UIKit.Theme.Gold); ring.raycastTarget = false; ring.rectTransform.anchorMin = ring.rectTransform.anchorMax = s.pos; ring.rectTransform.sizeDelta = new Vector2(size + 16, size + 16); } var holder = UIKit.Make("Settlement_" + s.id, map); holder.anchorMin = holder.anchorMax = s.pos; holder.sizeDelta = new Vector2(size, size); var img = holder.gameObject.AddComponent(); img.color = ruined ? new Color(0.3f, 0.3f, 0.3f) : s.color; var btn = holder.gameObject.AddComponent