MVP1 #3
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d2475bd20689b914cb6e99c4a5f1fcd5
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -3,18 +3,6 @@ using UnityEngine.UI;
|
||||
using UnityEditor;
|
||||
using TMPro;
|
||||
|
||||
// СКЕЛЕТ HUD БЕЗ СПРАЙТОВ.
|
||||
//
|
||||
// Как использовать:
|
||||
// 1. Положи этот файл в папку Assets/Editor/ (обязательно "Editor" в пути, иначе не соберётся билд)
|
||||
// 2. В Unity сверху появится пункт меню: Tools -> Build HUD Skeleton
|
||||
// 3. Жми -- создастся полный Canvas с иерархией, якорями под мобильный экран,
|
||||
// цветными заглушками вместо спрайтов и подписанными текстами.
|
||||
// 4. Дизайнеры позже просто меняют Image -> Source Image на каждом объекте,
|
||||
// ничего не пересобирая -- имена и структура объектов остаются те же.
|
||||
//
|
||||
// Референс: HUD в духе Rise of Kingdoms / Vikings (портретная мобильная стратегия)
|
||||
|
||||
public class HUDSkeletonBuilder : EditorWindow
|
||||
{
|
||||
[MenuItem("Tools/Build HUD Skeleton")]
|
||||
@@ -105,8 +93,8 @@ public class HUDSkeletonBuilder : EditorWindow
|
||||
RectTransform bottomBar = CreatePanel(canvasRect, "BottomNavBar", new Color(0.08f, 0.08f, 0.1f, 0.92f));
|
||||
AnchorBottomStretch(bottomBar, height: 190);
|
||||
|
||||
string[] navNames = { "Home", "Hero", "Battle", "Troops", "Shop" };
|
||||
string[] navLabels = { "ГЛАВНАЯ", "ГЕРОЙ", "БОЙ", "ВОЙСКА", "МАГАЗИН" };
|
||||
string[] navNames = { "Home", "Hero", "Battle", "Troops", "Shop", "ARENA" };
|
||||
string[] navLabels = { "ГЛАВНАЯ", "ГЕРОЙ", "БОЙ", "ВОЙСКА", "МАГАЗИН", "АРЕНА" };
|
||||
float navWidth = 1080f / 5f;
|
||||
for (int i = 0; i < navNames.Length; i++)
|
||||
{
|
||||
|
||||
@@ -3,15 +3,6 @@ using UnityEngine.UI;
|
||||
using UnityEditor;
|
||||
using TMPro;
|
||||
|
||||
// СКЕЛЕТ ЗАГЛАВНОГО ЭКРАНА (Main Menu) БЕЗ СПРАЙТОВ.
|
||||
//
|
||||
// Как использовать:
|
||||
// 1. Файл должен лежать в Assets/Editor/
|
||||
// 2. Tools -> Build Main Menu Skeleton
|
||||
// 3. Создастся Canvas с фоном-заглушкой, заголовком и тремя кнопками:
|
||||
// Играть / Настройки / Выход.
|
||||
// 4. Дизайнеры позже меняют Image -> Source Image на объектах,
|
||||
// структуру и имена не трогают.
|
||||
|
||||
public class MainMenuSkeletonBuilder : EditorWindow
|
||||
{
|
||||
|
||||
+1169
-29
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0930acd12dcae2c4a87c45419e24391c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
// Центральное хранилище всех ресурсов игрока.
|
||||
// Один объект на сцену (Singleton) -- любой скрипт обращается через ResourceManager.Instance
|
||||
|
||||
public enum ResourceType
|
||||
{
|
||||
Power, // "сила" -- как в референсе HUD
|
||||
Food,
|
||||
Wood,
|
||||
Stone,
|
||||
Iron,
|
||||
Gold,
|
||||
Gems
|
||||
}
|
||||
|
||||
public class ResourceManager : MonoBehaviour
|
||||
{
|
||||
public static ResourceManager Instance { get; private set; }
|
||||
|
||||
// Событие: вызывается каждый раз, когда любой ресурс меняется.
|
||||
// UI подписывается на него, чтобы обновлять текст автоматически, без Update() каждый кадр.
|
||||
public event Action<ResourceType, float> OnResourceChanged;
|
||||
|
||||
[Header("Стартовые значения (для теста/баланса)")]
|
||||
public float startWood = 0f;
|
||||
public float startStone = 0f;
|
||||
public float startIron = 0f;
|
||||
public float startFood = 0f;
|
||||
public float startGold = 0f;
|
||||
public float startGems = 0f;
|
||||
public float startPower = 0f;
|
||||
|
||||
private Dictionary<ResourceType, float> resources = new Dictionary<ResourceType, float>();
|
||||
|
||||
void Awake()
|
||||
{
|
||||
// Классический паттерн Singleton: если уже есть экземпляр -- уничтожаем дубликат
|
||||
if (Instance != null && Instance != this)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
Instance = this;
|
||||
DontDestroyOnLoad(gameObject); // менеджер ресурсов должен жить между сценами (меню -> игра)
|
||||
|
||||
resources[ResourceType.Wood] = startWood;
|
||||
resources[ResourceType.Stone] = startStone;
|
||||
resources[ResourceType.Iron] = startIron;
|
||||
resources[ResourceType.Food] = startFood;
|
||||
resources[ResourceType.Gold] = startGold;
|
||||
resources[ResourceType.Gems] = startGems;
|
||||
resources[ResourceType.Power] = startPower;
|
||||
}
|
||||
|
||||
// Добавить ресурс (можно и отрицательное число -- для трат)
|
||||
public void AddResource(ResourceType type, float amount)
|
||||
{
|
||||
if (!resources.ContainsKey(type))
|
||||
resources[type] = 0f;
|
||||
|
||||
resources[type] += amount;
|
||||
if (resources[type] < 0f) resources[type] = 0f; // ресурс не уходит в минус
|
||||
|
||||
OnResourceChanged?.Invoke(type, resources[type]);
|
||||
}
|
||||
|
||||
// Проверить, хватает ли ресурса (для трат/построек в будущем)
|
||||
public bool HasEnough(ResourceType type, float amount)
|
||||
{
|
||||
return GetResource(type) >= amount;
|
||||
}
|
||||
|
||||
// Попробовать потратить -- вернёт false, если не хватило (и ничего не спишет)
|
||||
public bool TrySpend(ResourceType type, float amount)
|
||||
{
|
||||
if (!HasEnough(type, amount)) return false;
|
||||
AddResource(type, -amount);
|
||||
return true;
|
||||
}
|
||||
|
||||
public float GetResource(ResourceType type)
|
||||
{
|
||||
return resources.TryGetValue(type, out float value) ? value : 0f;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5505825aa4d83af49a3a641e48af3ff7
|
||||
@@ -0,0 +1,56 @@
|
||||
using Unity.Microsoft.GDK;
|
||||
using UnityEngine;
|
||||
|
||||
// Вешается на ЛЮБОЕ здание (лесопилка, каменоломня, шахта) -- настраиваешь
|
||||
// в Inspector, какой ресурс и сколько оно производит. Один скрипт на все типы построек.
|
||||
//
|
||||
// ПРИМЕР НАСТРОЙКИ:
|
||||
// Лесопилка: resourceType = Wood, amountPerTick = 5, tickInterval = 3
|
||||
// Каменоломня: resourceType = Stone, amountPerTick = 4, tickInterval = 3
|
||||
// Шахта: resourceType = Iron, amountPerTick = 2, tickInterval = 4 (руда добывается медленнее)
|
||||
|
||||
public class ResourceProducer : MonoBehaviour
|
||||
{
|
||||
[Header("Что производит это здание")]
|
||||
public ResourceType resourceType;
|
||||
public float amountPerTick = 1f;
|
||||
public float tickInterval = 3f; // секунд между "тиками" производства
|
||||
|
||||
[Header("Уровень здания (для будущего апгрейда)")]
|
||||
public int level = 1;
|
||||
[Tooltip("Множитель производства за каждый уровень выше первого")]
|
||||
public float perLevelMultiplier = 1.2f;
|
||||
|
||||
private float timer;
|
||||
|
||||
void Update()
|
||||
{
|
||||
timer += Time.deltaTime;
|
||||
|
||||
if (timer >= tickInterval)
|
||||
{
|
||||
timer -= tickInterval;
|
||||
Produce();
|
||||
}
|
||||
}
|
||||
|
||||
void Produce()
|
||||
{
|
||||
if (ResourceManager.Instance == null)
|
||||
{
|
||||
Debug.LogWarning($"{gameObject.name}: ResourceManager.Instance не найден. " +
|
||||
"Убедись, что на сцене есть объект с компонентом ResourceManager.");
|
||||
return;
|
||||
}
|
||||
|
||||
float finalAmount = amountPerTick * Mathf.Pow(perLevelMultiplier, level - 1);
|
||||
ResourceManager.Instance.AddResource(resourceType, finalAmount);
|
||||
Debug.Log($"{gameObject.name} произвел {finalAmount} {resourceType}. Итого: {ResourceManager.Instance.GetResource(resourceType)}");
|
||||
}
|
||||
|
||||
// Вызывай при апгрейде здания (кнопка "улучшить" повесишь позже)
|
||||
public void Upgrade()
|
||||
{
|
||||
level++;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eb8009d4824ec6f4392a50d60eead242
|
||||
@@ -0,0 +1,71 @@
|
||||
using UnityEngine;
|
||||
using TMPro;
|
||||
|
||||
|
||||
[RequireComponent(typeof(TMP_Text))]
|
||||
public class ResourceUIText : MonoBehaviour
|
||||
{
|
||||
public ResourceType resourceType;
|
||||
|
||||
[Tooltip("Сокращать большие числа (1200 -> 1.2K, 1500000 -> 1.5M), как на референсе HUD")]
|
||||
public bool useShortFormat = true;
|
||||
|
||||
private TMP_Text label;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
label = GetComponent<TMP_Text>();
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
// Ждём, пока ResourceManager точно проинициализируется (Awake порядок не гарантирован)
|
||||
if (ResourceManager.Instance != null)
|
||||
{
|
||||
Subscribe();
|
||||
}
|
||||
else
|
||||
{
|
||||
Invoke(nameof(TrySubscribeDelayed), 0.1f);
|
||||
}
|
||||
}
|
||||
|
||||
void TrySubscribeDelayed()
|
||||
{
|
||||
if (ResourceManager.Instance != null)
|
||||
Subscribe();
|
||||
}
|
||||
|
||||
void Subscribe()
|
||||
{
|
||||
ResourceManager.Instance.OnResourceChanged += HandleResourceChanged;
|
||||
// сразу показать текущее значение при старте, не дожидаясь первого изменения
|
||||
UpdateText(ResourceManager.Instance.GetResource(resourceType));
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
if (ResourceManager.Instance != null)
|
||||
ResourceManager.Instance.OnResourceChanged -= HandleResourceChanged;
|
||||
}
|
||||
|
||||
void HandleResourceChanged(ResourceType type, float newValue)
|
||||
{
|
||||
if (type != resourceType) return; // реагируем только на "свой" ресурс
|
||||
UpdateText(newValue);
|
||||
}
|
||||
|
||||
void UpdateText(float value)
|
||||
{
|
||||
label.text = useShortFormat ? FormatShort(value) : Mathf.FloorToInt(value).ToString();
|
||||
}
|
||||
|
||||
string FormatShort(float value)
|
||||
{
|
||||
if (value >= 1_000_000f)
|
||||
return (value / 1_000_000f).ToString("0.#") + "M";
|
||||
if (value >= 1_000f)
|
||||
return (value / 1_000f).ToString("0.#") + "K";
|
||||
return Mathf.FloorToInt(value).ToString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8fb37401fb35fdc4496913e6c8d442eb
|
||||
+2498
-1963
File diff suppressed because one or more lines are too long
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0fa6a80c1f57f044c8deaf91dc062bdf
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,3 +1,4 @@
|
||||
<Solution>
|
||||
<Project Path="Assembly-CSharp-Editor.csproj" />
|
||||
<Project Path="Assembly-CSharp.csproj" />
|
||||
</Solution>
|
||||
|
||||
@@ -512,7 +512,10 @@ PlayerSettings:
|
||||
m_BuildTargetGroupLightmapSettings: []
|
||||
m_BuildTargetGroupLoadStoreDebugModeSettings: []
|
||||
m_BuildTargetNormalMapEncoding: []
|
||||
m_BuildTargetDefaultTextureCompressionFormat: []
|
||||
m_BuildTargetDefaultTextureCompressionFormat:
|
||||
- serializedVersion: 3
|
||||
m_BuildTarget: Android
|
||||
m_Formats: 01000000
|
||||
playModeTestRunnerEnabled: 0
|
||||
runPlayModeTestAsEditModeTest: 0
|
||||
actionOnDotNetUnhandledException: 1
|
||||
@@ -857,7 +860,8 @@ PlayerSettings:
|
||||
XboxOneXTitleMemory: 8
|
||||
XboxOneOverrideIdentityName:
|
||||
XboxOneOverrideIdentityPublisher:
|
||||
cloudServicesEnabled: {}
|
||||
cloudServicesEnabled:
|
||||
Purchasing: 0
|
||||
luminIcon:
|
||||
m_Name:
|
||||
m_ModelFolderPath:
|
||||
@@ -877,7 +881,7 @@ PlayerSettings:
|
||||
qnxGraphicConfPath:
|
||||
apiCompatibilityLevel: 6
|
||||
captureStartupLogs: {}
|
||||
activeInputHandler: 1
|
||||
activeInputHandler: 2
|
||||
windowsGamepadBackendHint: 0
|
||||
enableDirectStorage: 0
|
||||
cloudProjectId: 31566238-597b-4365-ab7f-7669af6314b9
|
||||
|
||||
Reference in New Issue
Block a user