Files
MVP1/Assets/Scripts/Construction of buildings/BuildManager.cs
T

160 lines
5.8 KiB
C#

using UnityEngine;
using System.Collections.Generic;
// Управляет режимом строительства. Теперь здание можно поставить ТОЛЬКО
// на заранее подготовленный участок (BuildSlot) -- свободное размещение убрано.
// Наведение на пустой слот -> подсветка (можно строить).
// Наведение на занятый слот / мимо слотов -> подсветки нет, клик ничего не делает.
public class BuildManager : MonoBehaviour
{
public static BuildManager Instance { get; private set; }
[Header("Все типы зданий в игре")]
public List<BuildingData> allBuildings;
[Header("Поиск участков под застройку")]
[Tooltip("Слой, на котором находятся объекты BuildSlot")]
public LayerMask buildSlotsLayerMask;
[Header("Подсветка участка при наведении")]
public Color highlightValidColor = new Color(1f, 1f, 1f, 0.9f); // белая -- можно строить
public Color highlightInvalidColor = new Color(1f, 0.2f, 0.2f, 0.9f); // красная -- нельзя (не хватает ресурсов)
private BuildingData currentlyPlacing;
private BuildSlot lastHighlightedSlot;
private Camera mainCam;
void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
mainCam = Camera.main;
}
void Update()
{
if (currentlyPlacing == null) return; // не в режиме строительства -- ничего не делаем
Vector3 worldPos = GetPointerWorldPosition();
worldPos.z = 0;
BuildSlot slotUnderPointer = GetSlotAtPosition(worldPos);
// Убираем подсветку с предыдущего слота, если курсор ушёл с него
if (lastHighlightedSlot != null && lastHighlightedSlot != slotUnderPointer)
{
lastHighlightedSlot.ClearHighlight();
}
if (slotUnderPointer != null && !slotUnderPointer.isOccupied)
{
bool canAfford = currentlyPlacing.CanAfford();
slotUnderPointer.SetHighlight(canAfford ? highlightValidColor : highlightInvalidColor);
lastHighlightedSlot = slotUnderPointer;
if (Input.GetMouseButtonDown(0))
{
TryConfirmPlacement(slotUnderPointer, canAfford);
}
}
else
{
lastHighlightedSlot = null;
}
// Отмена по правой кнопке / Escape
if (Input.GetMouseButtonDown(1) || Input.GetKeyDown(KeyCode.Escape))
{
CancelPlacement();
}
}
BuildSlot GetSlotAtPosition(Vector3 position)
{
Collider2D hit = Physics2D.OverlapPoint(position, buildSlotsLayerMask);
if (hit == null) return null;
return hit.GetComponent<BuildSlot>();
}
// Список зданий, доступных для стройки ПРЯМО СЕЙЧАС (по уровню Ратуши)
public List<BuildingData> GetAvailableBuildings()
{
List<BuildingData> available = new List<BuildingData>();
int townHallLevel = TownHall.Instance != null ? TownHall.Instance.currentLevel : 1;
foreach (var b in allBuildings)
{
if (b.requiredTownHallLevel <= townHallLevel)
available.Add(b);
}
return available;
}
// Вызывается из UI-кнопки конкретного здания в меню стройки
public void StartPlacing(BuildingData data)
{
currentlyPlacing = data;
Debug.Log($"[СТРОЙКА] Выбрано здание: {data.buildingName}. Кликни на пустой участок.");
}
void TryConfirmPlacement(BuildSlot slot, bool canAfford)
{
if (!canAfford)
{
Debug.Log("[СТРОЙКА] Не хватает ресурсов!");
return;
}
currentlyPlacing.PayCost();
GameObject built = Instantiate(currentlyPlacing.prefab, slot.transform.position, Quaternion.identity);
PlacedBuildingId idMarker = built.AddComponent<PlacedBuildingId>();
idMarker.buildingName = currentlyPlacing.buildingName;
slot.Occupy(built);
BuildingSlotLink link = built.AddComponent<BuildingSlotLink>();
link.linkedSlot = slot;
Debug.Log($"[СТРОЙКА] Построено: {currentlyPlacing.buildingName} на участке {slot.name}");
currentlyPlacing = null;
lastHighlightedSlot = null;
}
void CancelPlacement()
{
if (lastHighlightedSlot != null)
{
lastHighlightedSlot.ClearHighlight();
lastHighlightedSlot = null;
}
currentlyPlacing = null;
Debug.Log("[СТРОЙКА] Размещение отменено.");
}
// Найти пустой (свободный) BuildSlot по названию -- используется при восстановлении сохранения
public BuildSlot FindSlotAtPosition(Vector3 position, float tolerance = 0.05f)
{
BuildSlot[] allSlots = FindObjectsByType<BuildSlot>(FindObjectsSortMode.None);
foreach (var slot in allSlots)
{
if (Vector3.Distance(slot.transform.position, position) < tolerance)
return slot;
}
return null;
}
Vector3 GetPointerWorldPosition()
{
Vector3 screenPos = Input.mousePosition;
return mainCam.ScreenToWorldPoint(screenPos);
}
}