Добавлены префабы построек, BuildManager, BuildMenuUI и скрипт камеры
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
// Управляет режимом строительства: показывает "призрак" здания под курсором,
|
||||
// проверяет ресурсы, спавнит здание в подтверждённой позиции.
|
||||
|
||||
public class BuildManager : MonoBehaviour
|
||||
{
|
||||
public static BuildManager Instance { get; private set; }
|
||||
|
||||
[Header("Все типы зданий в игре")]
|
||||
public List<BuildingData> allBuildings;
|
||||
|
||||
[Header("Визуал 'призрака' здания при размещении")]
|
||||
public Color validPlacementColor = new Color(1, 1, 1, 0.6f);
|
||||
public Color invalidPlacementColor = new Color(1, 0.3f, 0.3f, 0.6f);
|
||||
|
||||
private BuildingData currentlyPlacing;
|
||||
private GameObject ghostObject;
|
||||
private Camera mainCam;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (Instance != null && Instance != this)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
Instance = this;
|
||||
mainCam = Camera.main;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (currentlyPlacing == null || ghostObject == null)
|
||||
return;
|
||||
|
||||
Vector3 worldPos = GetPointerWorldPosition();
|
||||
worldPos.z = 0;
|
||||
ghostObject.transform.position = worldPos;
|
||||
|
||||
bool canAfford = currentlyPlacing.CanAfford();
|
||||
SpriteRenderer sr = ghostObject.GetComponent<SpriteRenderer>();
|
||||
if (sr != null)
|
||||
sr.color = canAfford ? validPlacementColor : invalidPlacementColor;
|
||||
|
||||
if (Input.GetMouseButtonDown(0))
|
||||
{
|
||||
TryConfirmPlacement(worldPos);
|
||||
}
|
||||
|
||||
if (Input.GetMouseButtonDown(1) || Input.GetKeyDown(KeyCode.Escape))
|
||||
{
|
||||
CancelPlacement();
|
||||
}
|
||||
}
|
||||
|
||||
// Список зданий, доступных для стройки ПРЯМО СЕЙЧАС (по уровню Ратуши)
|
||||
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)
|
||||
{
|
||||
if (currentlyPlacing != null)
|
||||
{
|
||||
CancelPlacement();
|
||||
}
|
||||
|
||||
currentlyPlacing = data;
|
||||
|
||||
ghostObject = Instantiate(data.prefab);
|
||||
// Отключаем на "призраке" всё, что мешает (коллайдер, скрипты сбора ресурсов и т.д.)
|
||||
Collider2D col = ghostObject.GetComponent<Collider2D>();
|
||||
if (col != null) col.enabled = false;
|
||||
|
||||
MonoBehaviour[] scripts = ghostObject.GetComponents<MonoBehaviour>();
|
||||
foreach (var s in scripts)
|
||||
{
|
||||
s.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
void TryConfirmPlacement(Vector3 position)
|
||||
{
|
||||
if (!currentlyPlacing.CanAfford())
|
||||
{
|
||||
Debug.Log("[СТРОЙКА] Не хватает ресурсов!");
|
||||
return;
|
||||
}
|
||||
|
||||
currentlyPlacing.PayCost();
|
||||
|
||||
GameObject built = Instantiate(currentlyPlacing.prefab, position, Quaternion.identity);
|
||||
Debug.Log($"[СТРОЙКА] Построено: {currentlyPlacing.buildingName} в {position}");
|
||||
|
||||
Destroy(ghostObject);
|
||||
currentlyPlacing = null;
|
||||
}
|
||||
|
||||
void CancelPlacement()
|
||||
{
|
||||
if (ghostObject != null) Destroy(ghostObject);
|
||||
currentlyPlacing = null;
|
||||
Debug.Log("[СТРОЙКА] Размещение отменено.");
|
||||
}
|
||||
|
||||
Vector3 GetPointerWorldPosition()
|
||||
{
|
||||
Vector3 screenPos = Input.mousePosition;
|
||||
return mainCam.ScreenToWorldPoint(screenPos);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9de6545e2f73cd04f9d95334879c4fc4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 100
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,54 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
using System.Collections.Generic;
|
||||
|
||||
// Заполняет меню стройки кнопками для каждого доступного здания.
|
||||
// Вешается на пустой объект-контейнер меню (например BuildMenuPanel).
|
||||
|
||||
|
||||
public class BuildMenuUi : MonoBehaviour
|
||||
{
|
||||
[Header("Ссылки")]
|
||||
public Transform buttonContainer; //Куда савить снопки
|
||||
public GameObject buildingButtonPrefab; //Преваб одной кнопки здания
|
||||
|
||||
void Start()
|
||||
{
|
||||
RefreshMenu();
|
||||
}
|
||||
void OnEnable()
|
||||
{
|
||||
if (BuildManager.Instance == null) return;
|
||||
RefreshMenu();
|
||||
}
|
||||
|
||||
public void RefreshMenu()
|
||||
{
|
||||
//Чистка старых кнопок перед сборкой списка
|
||||
foreach (Transform child in buttonContainer)
|
||||
{
|
||||
Destroy(child.gameObject);
|
||||
}
|
||||
List<BuildingData> available = BuildManager.Instance.GetAvailableBuildings();
|
||||
foreach (var building in available)
|
||||
{
|
||||
GameObject btnGO = Instantiate(buildingButtonPrefab, buttonContainer);
|
||||
|
||||
Transform iconT = btnGO.transform.Find("Icon");
|
||||
Transform nameT = btnGO.transform.Find("NameText");
|
||||
Transform costT = btnGO.transform.Find("CostText");
|
||||
|
||||
if (iconT != null) iconT.GetComponent<Image>().sprite = building.icon;
|
||||
if (nameT != null) nameT.GetComponent<TMP_Text>().text = building.buildingName;
|
||||
if (costT != null) costT.GetComponent<TMP_Text>().text = building.GetCostText();
|
||||
Button btn = btnGO.GetComponent<Button>();
|
||||
BuildingData capturedBuilding = building; // важно для замыкания в цикле
|
||||
btn.onClick.AddListener(() =>
|
||||
{
|
||||
BuildManager.Instance.StartPlacing(capturedBuilding);
|
||||
gameObject.SetActive(false); // закрываем меню после выбора, идём размещать здание
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e52ef64e91883de4c94450d91e119b48
|
||||
@@ -15,7 +15,7 @@ public class BuildingData : ScriptableObject
|
||||
|
||||
[Header("Требования")]
|
||||
[Tooltip("Необходимый уровень ратуши")]
|
||||
public int requiredTowmHallLevel = 1;
|
||||
public int requiredTownHallLevel = 1;
|
||||
|
||||
[Header("Стоимость")]
|
||||
public ResourceCost[] cost;
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
using UnityEngine;
|
||||
|
||||
// Вешается на объект Ратуши, который уже стоит на карте.
|
||||
// Хранит текущий уровень -- от него зависит, какие здания разблокированы в BuildManager.
|
||||
|
||||
public class TownHall : MonoBehaviour
|
||||
{
|
||||
public static TownHall Instance { get; private set; }
|
||||
|
||||
[Header("Уровень")]
|
||||
public int currentLevel = 1;
|
||||
public int maxLevel = 10;
|
||||
|
||||
[Header("Стоимость апгрейда (растёт с каждым уровнем)")]
|
||||
public ResourceCost[] baseUpgradeCost;
|
||||
[Tooltip("Во сколько раз дорожает апгрейд за каждый следующий уровень")]
|
||||
public float costMultiplierPerLevel = 1.5f;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (Instance != null && Instance != this)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
// Стоимость апгрейда на текущем уровне (растёт по экспоненте)
|
||||
public ResourceCost[] GetUpgradeCost()
|
||||
{
|
||||
ResourceCost[] scaled = new ResourceCost[baseUpgradeCost.Length];
|
||||
float multiplier = Mathf.Pow(costMultiplierPerLevel, currentLevel - 1);
|
||||
|
||||
for (int i = 0; i < baseUpgradeCost.Length; i++)
|
||||
{
|
||||
scaled[i] = new ResourceCost
|
||||
{
|
||||
type = baseUpgradeCost[i].type,
|
||||
amount = baseUpgradeCost[i].amount * multiplier
|
||||
};
|
||||
}
|
||||
return scaled;
|
||||
}
|
||||
|
||||
public bool CanUpgrade()
|
||||
{
|
||||
if (currentLevel >= maxLevel) return false;
|
||||
if (ResourceManager.Instance == null) return false;
|
||||
|
||||
foreach (var c in GetUpgradeCost())
|
||||
{
|
||||
if (!ResourceManager.Instance.HasEnough(c.type, c.amount))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Upgrade()
|
||||
{
|
||||
if (!CanUpgrade())
|
||||
{
|
||||
Debug.Log("[РАТУША] Не хватает ресурсов на апгрейд или максимальный уровень.");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var c in GetUpgradeCost())
|
||||
{
|
||||
ResourceManager.Instance.TrySpend(c.type, c.amount);
|
||||
}
|
||||
|
||||
currentLevel++;
|
||||
Debug.Log($"[РАТУША] Улучшена до уровня {currentLevel}!");
|
||||
}
|
||||
void OnMouseDown()
|
||||
{
|
||||
Debug.Log($"[Ратуша] Клик! текущий уровень: {currentLevel}. Улучшение...");
|
||||
Upgrade();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aafc612f8913ade44b6b60cf76d8932d
|
||||
Reference in New Issue
Block a user