/
GeekNerd
/
ServerModelingProject
Обзор
Документация
Войти
/
GeekNerd
/
ServerModelingProject
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
Assets/Scripts/RoomBuilding/UIDotGridView.cs
243 строки
9 KB
Gorney-Alex
Init
30 май 2026, 19:05
30 май 2026, 19:05
3cdcc49
Код
Авторство
О чём код?
using DataClasses; using Cysharp.Threading.Tasks; using System.Collections.Generic; using System.Threading; using Interfaces; using UnityEngine; using UnityEngine.Events; using UnityEngine.EventSystems; using UnityEngine.UI; using Zenject; namespace RoomBuilding { public class UIDotGridView : MonoBehaviour, IInitializable { [Header("Dot colors")] [SerializeField] private Color colorDefault = new Color(0.0f, 0.0f, 0.0f); [SerializeField] private Color colorFirst = new Color(0.2f, 0.8f, 0.2f); [SerializeField] private Color colorClose = new Color(1.0f, 0.9f, 0.1f); [SerializeField] private Color colorHover = new Color(1.0f, 1.0f, 1.0f); [Header("Grid")] [SerializeField] private RectTransform dotsContainer; [SerializeField] private float pixelsPerGridStep = 20f; [SerializeField] private float spawnDelaySeconds = 0.001f; [SerializeField] private int maxDotsToSpawn = 2500; private ICustomFactory _factory; private RoomBuildingSettings _settings; private PolygonDrawingService _drawingService; private readonly List<IDotButtonView> _dots = new(); private readonly List<Vector2> _dotWorlds = new(); private bool _isSpawned; private CancellationTokenSource _spawnCts; private float _pixelsPerMeter; [Inject] public void Construct(ICustomFactory factory, RoomBuildingSettings settings, PolygonDrawingService drawingService) { _factory = factory; _settings = settings; _drawingService = drawingService; } public void Initialize() { if (!Validate()) return; if (_isSpawned) return; _pixelsPerMeter = pixelsPerGridStep / _settings.DotSpacing; _drawingService.OnVerticesChanged += RefreshDotColors; _drawingService.OnStateChanged += _ => RefreshDotColors(); _spawnCts = new CancellationTokenSource(); SpawnDotsAsync(_spawnCts.Token).Forget(); _isSpawned = true; } private void OnDestroy() { if (_drawingService != null) { _drawingService.OnVerticesChanged -= RefreshDotColors; _drawingService.OnStateChanged -= _ => RefreshDotColors(); } _spawnCts?.Cancel(); _spawnCts?.Dispose(); } private async UniTaskVoid SpawnDotsAsync(CancellationToken ct) { var root = dotsContainer != null ? dotsContainer : transform as RectTransform; if (root == null) { Debug.LogError("[UIDotGridView] dotsContainer missing"); return; } int dotsX = _settings.FieldWidth + 1; int dotsY = _settings.FieldHeight + 1; int totalDots = dotsX * dotsY; if (totalDots > maxDotsToSpawn) { Debug.LogError($"[UIDotGridView] Too many dots: {totalDots}. Increase maxDotsToSpawn."); return; } for (int i = root.childCount - 1; i >= 0; i--) { Destroy(root.GetChild(i).gameObject); } _dots.Clear(); _dotWorlds.Clear(); float totalW = _settings.FieldWidth * _settings.DotSpacing * _pixelsPerMeter; float totalH = _settings.FieldHeight * _settings.DotSpacing * _pixelsPerMeter; float startX = -totalW * 0.5f; float startY = -totalH * 0.5f; float stepPx = _settings.DotSpacing * _pixelsPerMeter; for (int x = 0; x <= _settings.FieldWidth; x++) { for (int y = 0; y <= _settings.FieldHeight; y++) { if (ct.IsCancellationRequested) return; float px = startX + x * stepPx; float py = startY + y * stepPx; float worldX = x * _settings.DotSpacing - (_settings.FieldWidth * _settings.DotSpacing) * 0.5f; float worldY = y * _settings.DotSpacing - (_settings.FieldHeight * _settings.DotSpacing) * 0.5f; var world = new Vector2(worldX, worldY); var dot = _factory.CreateDotButton(dotsContainer); dot.UpdateName($"Dot_{x}_{y}"); dot.UpdatePosition(new Vector2(px, py)); _dots.Add(dot); _dotWorlds.Add(world); SetupDotEvents(dot, world, _dots.Count - 1); if (spawnDelaySeconds > 0f) { await UniTask.Delay((int)(spawnDelaySeconds * 1000f), DelayType.Realtime, PlayerLoopTiming.Update, ct); } } } } private void SetupDotEvents(IDotButtonView dot, Vector2 world, int dotIndex) { var btn = dot.GetButton(); if (btn == null) return; btn.onClick.AddListener(() => OnDotClicked(world, dotIndex)); var trigger = dot.OwnerGameObject.GetComponent<EventTrigger>() ?? dot.OwnerGameObject.AddComponent<EventTrigger>(); AddTriggerEntry(trigger, EventTriggerType.PointerEnter, _ => OnDotHoverEnter(dotIndex)); AddTriggerEntry(trigger, EventTriggerType.PointerExit, _ => OnDotHoverExit(dotIndex)); } private void OnDotClicked(Vector2 world, int dotIndex) { if (Input.GetKey(KeyCode.D) && _drawingService.State == DrawingState.Closed) { int edge = _drawingService.FindNearestEdgeIndex(world); if (edge >= 0) { _drawingService.AddDoor(edge); } return; } if (Input.GetKey(KeyCode.C) && _drawingService.State == DrawingState.Closed) { _drawingService.AddCrac(world); return; } if (Input.GetKey(KeyCode.B)) { _drawingService.AddColumn(world); return; } _drawingService.HandleDotClick(world); } private void OnDotHoverEnter(int dotIndex) { var img = GetDotImage(dotIndex); if (img == null) return; if (dotIndex == 0 && _drawingService.State == DrawingState.Drawing && _drawingService.Vertices.Count >= 3) { img.color = colorClose; } else { img.color = colorHover; } if ((_drawingService.State == DrawingState.Drawing || _drawingService.IsColumnMode) && dotIndex < _dotWorlds.Count) { _drawingService.HandleCursorMove(_dotWorlds[dotIndex]); } } private void OnDotHoverExit(int dotIndex) { RefreshSingleDot(dotIndex); } private void RefreshDotColors() { for (int i = 0; i < _dots.Count; i++) { RefreshSingleDot(i); } } private void RefreshSingleDot(int i) { var img = GetDotImage(i); if (img == null) return; var verts = _drawingService.Vertices; if (verts.Count > 0 && i < _dotWorlds.Count && Vector2.Distance(_dotWorlds[i], verts[0]) < 0.01f) { img.color = colorFirst; return; } img.color = colorDefault; } private Image GetDotImage(int index) { if (index < 0 || index >= _dots.Count) return null; return _dots[index].OwnerGameObject.GetComponent<Image>(); } private static void AddTriggerEntry(EventTrigger trigger, EventTriggerType type, UnityAction<BaseEventData> action) { var entry = new EventTrigger.Entry { eventID = type }; entry.callback.AddListener(action); trigger.triggers.Add(entry); } private bool Validate() { if (_settings == null) { Debug.LogError("[UIDotGridView] Settings missing"); return false; } if (_factory == null) { Debug.LogError("[UIDotGridView] Factory missing"); return false; } if (_settings.DotSpacing <= 0f) { Debug.LogError("[UIDotGridView] DotSpacing <= 0"); return false; } if (_settings.FieldWidth < 1 || _settings.FieldHeight < 1) { Debug.LogError("[UIDotGridView] Invalid field size"); return false; } return true; } } }