first commit
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
[RequireComponent(typeof(RectTransform))]
|
||||
public class LineConnectorUI : MonoBehaviour
|
||||
{
|
||||
public RectTransform start;
|
||||
public RectTransform end;
|
||||
public Image lineImage;
|
||||
public float thickness = 4f;
|
||||
public bool dynamicUpdate = true;
|
||||
|
||||
private RectTransform rectTransform;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
rectTransform = GetComponent<RectTransform>();
|
||||
if (lineImage == null)
|
||||
{
|
||||
lineImage = GetComponent<Image>();
|
||||
}
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
if (dynamicUpdate)
|
||||
{
|
||||
UpdateLine();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetEndpoints(RectTransform startPoint, RectTransform endPoint)
|
||||
{
|
||||
start = startPoint;
|
||||
end = endPoint;
|
||||
UpdateLine();
|
||||
}
|
||||
|
||||
public void UpdateLine()
|
||||
{
|
||||
if (start == null || end == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (rectTransform == null)
|
||||
{
|
||||
rectTransform = GetComponent<RectTransform>();
|
||||
}
|
||||
|
||||
RectTransform parent = rectTransform.parent as RectTransform;
|
||||
if (parent == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2 startPosition = GetCenterInParentSpace(parent, start);
|
||||
Vector2 endPosition = GetCenterInParentSpace(parent, end);
|
||||
Vector2 delta = endPosition - startPosition;
|
||||
|
||||
rectTransform.anchorMin = new Vector2(0.5f, 0.5f);
|
||||
rectTransform.anchorMax = new Vector2(0.5f, 0.5f);
|
||||
rectTransform.pivot = new Vector2(0.5f, 0.5f);
|
||||
rectTransform.anchoredPosition = startPosition + delta * 0.5f;
|
||||
rectTransform.sizeDelta = new Vector2(delta.magnitude, Mathf.Max(1f, thickness));
|
||||
rectTransform.localRotation = Quaternion.Euler(0f, 0f, Mathf.Atan2(delta.y, delta.x) * Mathf.Rad2Deg);
|
||||
}
|
||||
|
||||
private Vector2 GetCenterInParentSpace(RectTransform parent, RectTransform target)
|
||||
{
|
||||
Vector3 worldCenter = target.TransformPoint(target.rect.center);
|
||||
Vector3 localCenter = parent.InverseTransformPoint(worldCenter);
|
||||
return new Vector2(localCenter.x, localCenter.y);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 91664eb39be68649fa272e155e08b460
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,67 @@
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class NotificationUI : MonoBehaviour
|
||||
{
|
||||
public Text messageText;
|
||||
public CanvasGroup canvasGroup;
|
||||
public float visibleDuration = 2.2f;
|
||||
public float fadeDuration = 0.25f;
|
||||
|
||||
private Coroutine routine;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (canvasGroup == null)
|
||||
{
|
||||
canvasGroup = GetComponent<CanvasGroup>();
|
||||
}
|
||||
|
||||
if (canvasGroup != null)
|
||||
{
|
||||
canvasGroup.alpha = 0f;
|
||||
canvasGroup.blocksRaycasts = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void Show(string message)
|
||||
{
|
||||
if (messageText == null || string.IsNullOrWhiteSpace(message))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
messageText.text = message;
|
||||
|
||||
if (routine != null)
|
||||
{
|
||||
StopCoroutine(routine);
|
||||
}
|
||||
|
||||
routine = StartCoroutine(ShowRoutine());
|
||||
}
|
||||
|
||||
private IEnumerator ShowRoutine()
|
||||
{
|
||||
if (canvasGroup == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
canvasGroup.alpha = 1f;
|
||||
yield return new WaitForSeconds(Mathf.Max(0.1f, visibleDuration));
|
||||
|
||||
float elapsed = 0f;
|
||||
float duration = Mathf.Max(0.05f, fadeDuration);
|
||||
while (elapsed < duration)
|
||||
{
|
||||
elapsed += Time.deltaTime;
|
||||
canvasGroup.alpha = Mathf.Lerp(1f, 0f, elapsed / duration);
|
||||
yield return null;
|
||||
}
|
||||
|
||||
canvasGroup.alpha = 0f;
|
||||
routine = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b9af78e14524d49c8942a7b8ab1dc61d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,75 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class StatsPanelUI : MonoBehaviour
|
||||
{
|
||||
public PlayerStats playerStats;
|
||||
public Text titleText;
|
||||
public Text maxHealthText;
|
||||
public Text maxManaText;
|
||||
public Text damageText;
|
||||
public Text moveSpeedText;
|
||||
public Text cooldownReductionText;
|
||||
public Text criticalChanceText;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (playerStats == null)
|
||||
{
|
||||
playerStats = FindObjectOfType<PlayerStats>();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
if (playerStats != null)
|
||||
{
|
||||
playerStats.OnStatsChanged += Refresh;
|
||||
}
|
||||
|
||||
Refresh();
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
if (playerStats != null)
|
||||
{
|
||||
playerStats.OnStatsChanged -= Refresh;
|
||||
}
|
||||
}
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
if (playerStats == null)
|
||||
{
|
||||
playerStats = FindObjectOfType<PlayerStats>();
|
||||
}
|
||||
|
||||
if (playerStats == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (titleText != null)
|
||||
{
|
||||
titleText.text = "Характеристики";
|
||||
}
|
||||
|
||||
SetText(maxHealthText, "Max Health", playerStats.MaxHealth, false);
|
||||
SetText(maxManaText, "Max Mana", playerStats.MaxMana, false);
|
||||
SetText(damageText, "Damage", playerStats.Damage, false);
|
||||
SetText(moveSpeedText, "Move Speed", playerStats.MoveSpeed, false);
|
||||
SetText(cooldownReductionText, "Cooldown Reduction", playerStats.AbilityCooldownReduction, true);
|
||||
SetText(criticalChanceText, "Critical Chance", playerStats.CriticalChance, true);
|
||||
}
|
||||
|
||||
private void SetText(Text text, string label, float value, bool percent)
|
||||
{
|
||||
if (text == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
text.text = percent ? $"{label}: {value:0.#}%" : $"{label}: {value:0.#}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e2abe10fb9912e35b99a6e90c1840beb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,167 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class TalentNodeUI : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
|
||||
{
|
||||
public TalentData talent;
|
||||
public TalentManager manager;
|
||||
public TalentTooltipUI tooltip;
|
||||
|
||||
public Image backgroundImage;
|
||||
public Image iconImage;
|
||||
public Text nameText;
|
||||
public Text costText;
|
||||
public Text stateText;
|
||||
public Button learnButton;
|
||||
public Outline borderOutline;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (learnButton == null)
|
||||
{
|
||||
learnButton = GetComponent<Button>();
|
||||
}
|
||||
|
||||
if (backgroundImage == null)
|
||||
{
|
||||
backgroundImage = GetComponent<Image>();
|
||||
}
|
||||
|
||||
if (borderOutline == null)
|
||||
{
|
||||
borderOutline = GetComponent<Outline>();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
if (learnButton != null)
|
||||
{
|
||||
learnButton.onClick.RemoveListener(OnClickLearn);
|
||||
learnButton.onClick.AddListener(OnClickLearn);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
if (learnButton != null)
|
||||
{
|
||||
learnButton.onClick.RemoveListener(OnClickLearn);
|
||||
}
|
||||
}
|
||||
|
||||
public void Setup(TalentData talent, TalentManager manager)
|
||||
{
|
||||
this.talent = talent;
|
||||
this.manager = manager;
|
||||
Refresh();
|
||||
}
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
if (talent == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (nameText != null)
|
||||
{
|
||||
nameText.text = talent.displayName;
|
||||
}
|
||||
|
||||
if (costText != null)
|
||||
{
|
||||
costText.text = $"{talent.cost} очк.";
|
||||
}
|
||||
|
||||
if (iconImage != null)
|
||||
{
|
||||
iconImage.sprite = talent.icon;
|
||||
iconImage.color = talent.icon != null ? Color.white : talent.branchColor;
|
||||
}
|
||||
|
||||
bool learned = manager != null && manager.IsLearned(talent);
|
||||
bool prerequisitesLearned = manager != null && manager.ArePrerequisitesLearned(talent);
|
||||
bool enoughPoints = manager != null && manager.GetAvailableTalentPoints() >= talent.cost;
|
||||
bool available = manager != null && manager.CanLearn(talent);
|
||||
|
||||
Color nodeColor = UITheme.LockedNode;
|
||||
string state = "Заблокировано";
|
||||
|
||||
if (learned)
|
||||
{
|
||||
nodeColor = UITheme.LearnedNode;
|
||||
state = "Изучено";
|
||||
}
|
||||
else if (available)
|
||||
{
|
||||
nodeColor = talent.branchColor;
|
||||
state = "Доступно";
|
||||
}
|
||||
else if (prerequisitesLearned && !enoughPoints)
|
||||
{
|
||||
nodeColor = UITheme.NotEnoughNode;
|
||||
state = "Не хватает очков";
|
||||
}
|
||||
|
||||
if (backgroundImage != null)
|
||||
{
|
||||
backgroundImage.color = new Color(nodeColor.r, nodeColor.g, nodeColor.b, learned || available ? 0.92f : 0.72f);
|
||||
}
|
||||
|
||||
if (borderOutline != null)
|
||||
{
|
||||
borderOutline.effectColor = learned ? UITheme.Gold : (available ? Color.white : UITheme.LockedNode);
|
||||
}
|
||||
|
||||
if (stateText != null)
|
||||
{
|
||||
stateText.text = state;
|
||||
}
|
||||
|
||||
if (learnButton != null)
|
||||
{
|
||||
learnButton.interactable = available;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnClickLearn()
|
||||
{
|
||||
if (manager != null && talent != null)
|
||||
{
|
||||
manager.LearnTalent(talent);
|
||||
}
|
||||
}
|
||||
|
||||
public void ShowTooltip()
|
||||
{
|
||||
if (tooltip == null)
|
||||
{
|
||||
tooltip = FindObjectOfType<TalentTooltipUI>(true);
|
||||
}
|
||||
|
||||
if (tooltip != null)
|
||||
{
|
||||
tooltip.Show(talent, manager);
|
||||
}
|
||||
}
|
||||
|
||||
public void HideTooltip()
|
||||
{
|
||||
if (tooltip != null)
|
||||
{
|
||||
tooltip.Hide();
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPointerEnter(PointerEventData eventData)
|
||||
{
|
||||
ShowTooltip();
|
||||
}
|
||||
|
||||
public void OnPointerExit(PointerEventData eventData)
|
||||
{
|
||||
HideTooltip();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e2a5a7bbb12a718f3b66184c7d62d48f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,227 @@
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class TalentTooltipUI : MonoBehaviour
|
||||
{
|
||||
public RectTransform panelRoot;
|
||||
public CanvasGroup canvasGroup;
|
||||
public Text titleText;
|
||||
public Text descriptionText;
|
||||
public Text costText;
|
||||
public Text modifiersText;
|
||||
public Text requirementsText;
|
||||
public Text statusText;
|
||||
public Text reasonText;
|
||||
public Vector2 screenOffset = new Vector2(22f, -18f);
|
||||
|
||||
private bool visible;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (panelRoot == null)
|
||||
{
|
||||
panelRoot = transform as RectTransform;
|
||||
}
|
||||
|
||||
if (canvasGroup == null)
|
||||
{
|
||||
canvasGroup = GetComponent<CanvasGroup>();
|
||||
}
|
||||
|
||||
Hide();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (!visible || panelRoot == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
panelRoot.position = Input.mousePosition + new Vector3(screenOffset.x, screenOffset.y, 0f);
|
||||
}
|
||||
|
||||
public void Show(TalentData talent, TalentManager manager)
|
||||
{
|
||||
if (talent == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (titleText != null)
|
||||
{
|
||||
titleText.text = talent.displayName;
|
||||
}
|
||||
|
||||
if (descriptionText != null)
|
||||
{
|
||||
descriptionText.text = talent.description;
|
||||
}
|
||||
|
||||
if (costText != null)
|
||||
{
|
||||
costText.text = $"Стоимость: {talent.cost}";
|
||||
}
|
||||
|
||||
if (modifiersText != null)
|
||||
{
|
||||
modifiersText.text = BuildModifiersText(talent);
|
||||
}
|
||||
|
||||
if (requirementsText != null)
|
||||
{
|
||||
requirementsText.text = BuildRequirementsText(talent);
|
||||
}
|
||||
|
||||
if (statusText != null)
|
||||
{
|
||||
statusText.text = $"Статус: {BuildStatusText(talent, manager)}";
|
||||
}
|
||||
|
||||
if (reasonText != null)
|
||||
{
|
||||
reasonText.text = manager != null ? manager.GetBlockingReason(talent) : string.Empty;
|
||||
}
|
||||
|
||||
visible = true;
|
||||
if (canvasGroup != null)
|
||||
{
|
||||
canvasGroup.alpha = 1f;
|
||||
canvasGroup.blocksRaycasts = false;
|
||||
}
|
||||
|
||||
if (panelRoot != null)
|
||||
{
|
||||
panelRoot.gameObject.SetActive(true);
|
||||
panelRoot.SetAsLastSibling();
|
||||
}
|
||||
}
|
||||
|
||||
public void Hide()
|
||||
{
|
||||
visible = false;
|
||||
if (canvasGroup != null)
|
||||
{
|
||||
canvasGroup.alpha = 0f;
|
||||
canvasGroup.blocksRaycasts = false;
|
||||
}
|
||||
|
||||
if (panelRoot != null)
|
||||
{
|
||||
panelRoot.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
private string BuildModifiersText(TalentData talent)
|
||||
{
|
||||
if (talent.modifiers == null || talent.modifiers.Length == 0)
|
||||
{
|
||||
return "Модификаторы: нет";
|
||||
}
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.AppendLine("Модификаторы:");
|
||||
for (int i = 0; i < talent.modifiers.Length; i++)
|
||||
{
|
||||
builder.AppendLine(FormatModifier(talent.modifiers[i]));
|
||||
}
|
||||
|
||||
return builder.ToString().TrimEnd();
|
||||
}
|
||||
|
||||
private string BuildRequirementsText(TalentData talent)
|
||||
{
|
||||
if (talent.prerequisites == null || talent.prerequisites.Length == 0)
|
||||
{
|
||||
return "Требования: нет";
|
||||
}
|
||||
|
||||
StringBuilder builder = new StringBuilder("Требования: ");
|
||||
for (int i = 0; i < talent.prerequisites.Length; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
builder.Append(", ");
|
||||
}
|
||||
|
||||
TalentData prerequisite = talent.prerequisites[i];
|
||||
builder.Append(prerequisite != null ? prerequisite.displayName : "Missing");
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
private string BuildStatusText(TalentData talent, TalentManager manager)
|
||||
{
|
||||
if (manager == null)
|
||||
{
|
||||
return "неизвестно";
|
||||
}
|
||||
|
||||
if (manager.IsLearned(talent))
|
||||
{
|
||||
return "изучено";
|
||||
}
|
||||
|
||||
if (manager.CanLearn(talent))
|
||||
{
|
||||
return "доступно";
|
||||
}
|
||||
|
||||
if (!manager.ArePrerequisitesLearned(talent))
|
||||
{
|
||||
return "заблокировано";
|
||||
}
|
||||
|
||||
return "не хватает очков";
|
||||
}
|
||||
|
||||
private string FormatModifier(StatModifier modifier)
|
||||
{
|
||||
string statName = FormatStatName(modifier.statType);
|
||||
string valueText;
|
||||
|
||||
if (modifier.modifierType == ModifierType.PercentAdd || modifier.modifierType == ModifierType.PercentMultiply)
|
||||
{
|
||||
valueText = FormatSignedNumber(modifier.value * 100f) + "%";
|
||||
}
|
||||
else if (modifier.statType == StatType.AbilityCooldownReduction || modifier.statType == StatType.CriticalChance)
|
||||
{
|
||||
valueText = FormatSignedNumber(modifier.value) + "%";
|
||||
}
|
||||
else
|
||||
{
|
||||
valueText = FormatSignedNumber(modifier.value);
|
||||
}
|
||||
|
||||
return $"{statName} {valueText}";
|
||||
}
|
||||
|
||||
private string FormatStatName(StatType statType)
|
||||
{
|
||||
switch (statType)
|
||||
{
|
||||
case StatType.MaxHealth:
|
||||
return "Max Health";
|
||||
case StatType.MaxMana:
|
||||
return "Max Mana";
|
||||
case StatType.Damage:
|
||||
return "Damage";
|
||||
case StatType.MoveSpeed:
|
||||
return "Move Speed";
|
||||
case StatType.AbilityCooldownReduction:
|
||||
return "Cooldown Reduction";
|
||||
case StatType.CriticalChance:
|
||||
return "Critical Chance";
|
||||
default:
|
||||
return statType.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
private string FormatSignedNumber(float value)
|
||||
{
|
||||
string sign = value >= 0f ? "+" : string.Empty;
|
||||
return sign + value.ToString("0.##");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ad8bf819a87ddc4de9584bb11236e5a8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,279 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class TalentTreeUI : MonoBehaviour
|
||||
{
|
||||
public TalentManager manager;
|
||||
public PlayerStats playerStats;
|
||||
|
||||
[Header("Tree")]
|
||||
public GameObject panelRoot;
|
||||
public RectTransform lineRoot;
|
||||
public RectTransform nodesRoot;
|
||||
public TalentNodeUI nodePrefab;
|
||||
public TalentTooltipUI tooltip;
|
||||
|
||||
[Header("Panels")]
|
||||
public Text titleText;
|
||||
public Text pointsText;
|
||||
public Text controlsText;
|
||||
public StatsPanelUI statsPanel;
|
||||
|
||||
[Header("Buttons")]
|
||||
public Button saveButton;
|
||||
public Button loadButton;
|
||||
public Button resetButton;
|
||||
|
||||
public bool openOnStart;
|
||||
|
||||
private readonly List<TalentNodeUI> nodes = new List<TalentNodeUI>();
|
||||
private readonly List<LineConnectorUI> lines = new List<LineConnectorUI>();
|
||||
private bool isOpen;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (manager == null)
|
||||
{
|
||||
manager = FindObjectOfType<TalentManager>();
|
||||
}
|
||||
|
||||
if (playerStats == null)
|
||||
{
|
||||
playerStats = FindObjectOfType<PlayerStats>();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
if (manager != null)
|
||||
{
|
||||
manager.OnTalentStateChanged += Refresh;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
if (manager != null)
|
||||
{
|
||||
manager.OnTalentStateChanged -= Refresh;
|
||||
}
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
BindButtons();
|
||||
BuildTree();
|
||||
Refresh();
|
||||
SetOpen(openOnStart);
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (Input.GetKeyDown(KeyCode.K))
|
||||
{
|
||||
Toggle();
|
||||
}
|
||||
}
|
||||
|
||||
public void Toggle()
|
||||
{
|
||||
SetOpen(!isOpen);
|
||||
}
|
||||
|
||||
public void SetOpen(bool open)
|
||||
{
|
||||
isOpen = open;
|
||||
if (panelRoot != null)
|
||||
{
|
||||
panelRoot.SetActive(open);
|
||||
}
|
||||
|
||||
if (open)
|
||||
{
|
||||
Refresh();
|
||||
UpdateLines();
|
||||
}
|
||||
}
|
||||
|
||||
public void BuildTree()
|
||||
{
|
||||
ClearChildren(nodesRoot);
|
||||
ClearChildren(lineRoot);
|
||||
nodes.Clear();
|
||||
lines.Clear();
|
||||
|
||||
if (manager == null || nodePrefab == null || nodesRoot == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Dictionary<TalentData, TalentNodeUI> nodeByTalent = new Dictionary<TalentData, TalentNodeUI>();
|
||||
for (int i = 0; i < manager.allTalents.Count; i++)
|
||||
{
|
||||
TalentData talent = manager.allTalents[i];
|
||||
if (talent == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
TalentNodeUI node = Instantiate(nodePrefab, nodesRoot);
|
||||
node.gameObject.SetActive(true);
|
||||
node.tooltip = tooltip;
|
||||
node.Setup(talent, manager);
|
||||
|
||||
RectTransform rectTransform = node.transform as RectTransform;
|
||||
if (rectTransform != null)
|
||||
{
|
||||
rectTransform.anchoredPosition = talent.treePosition;
|
||||
}
|
||||
|
||||
nodes.Add(node);
|
||||
nodeByTalent[talent] = node;
|
||||
}
|
||||
|
||||
if (lineRoot == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < manager.allTalents.Count; i++)
|
||||
{
|
||||
TalentData talent = manager.allTalents[i];
|
||||
if (talent == null || talent.prerequisites == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int prerequisiteIndex = 0; prerequisiteIndex < talent.prerequisites.Length; prerequisiteIndex++)
|
||||
{
|
||||
TalentData prerequisite = talent.prerequisites[prerequisiteIndex];
|
||||
if (prerequisite == null || !nodeByTalent.ContainsKey(prerequisite) || !nodeByTalent.ContainsKey(talent))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
LineConnectorUI line = CreateLine(lineRoot, prerequisite, nodeByTalent[prerequisite], nodeByTalent[talent]);
|
||||
lines.Add(line);
|
||||
}
|
||||
}
|
||||
|
||||
UpdateLines();
|
||||
}
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
if (titleText != null)
|
||||
{
|
||||
titleText.text = "Дерево талантов";
|
||||
}
|
||||
|
||||
if (pointsText != null)
|
||||
{
|
||||
int points = manager != null ? manager.GetAvailableTalentPoints() : 0;
|
||||
pointsText.text = $"Очки талантов: {points}";
|
||||
}
|
||||
|
||||
if (controlsText != null)
|
||||
{
|
||||
controlsText.text = "K - дерево X - +50 XP T - +1 очко E - кристалл F5 - сохранить F9 - загрузить Backspace - сброс";
|
||||
}
|
||||
|
||||
for (int i = 0; i < nodes.Count; i++)
|
||||
{
|
||||
if (nodes[i] != null)
|
||||
{
|
||||
nodes[i].Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
if (statsPanel != null)
|
||||
{
|
||||
statsPanel.Refresh();
|
||||
}
|
||||
|
||||
UpdateLines();
|
||||
}
|
||||
|
||||
private void BindButtons()
|
||||
{
|
||||
if (saveButton != null)
|
||||
{
|
||||
saveButton.onClick.RemoveAllListeners();
|
||||
saveButton.onClick.AddListener(() =>
|
||||
{
|
||||
if (manager != null)
|
||||
{
|
||||
manager.SaveProgress();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (loadButton != null)
|
||||
{
|
||||
loadButton.onClick.RemoveAllListeners();
|
||||
loadButton.onClick.AddListener(() =>
|
||||
{
|
||||
if (manager != null)
|
||||
{
|
||||
manager.LoadProgress();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (resetButton != null)
|
||||
{
|
||||
resetButton.onClick.RemoveAllListeners();
|
||||
resetButton.onClick.AddListener(() =>
|
||||
{
|
||||
if (manager != null)
|
||||
{
|
||||
manager.ResetProgress();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private LineConnectorUI CreateLine(RectTransform parent, TalentData childTalent, TalentNodeUI startNode, TalentNodeUI endNode)
|
||||
{
|
||||
GameObject lineObject = new GameObject($"Line_{startNode.talent.talentId}_to_{childTalent.talentId}", typeof(RectTransform), typeof(Image), typeof(LineConnectorUI));
|
||||
lineObject.transform.SetParent(parent, false);
|
||||
|
||||
Image image = lineObject.GetComponent<Image>();
|
||||
Color color = childTalent.branchColor;
|
||||
image.color = new Color(color.r, color.g, color.b, 0.72f);
|
||||
image.raycastTarget = false;
|
||||
|
||||
LineConnectorUI connector = lineObject.GetComponent<LineConnectorUI>();
|
||||
connector.lineImage = image;
|
||||
connector.thickness = 5f;
|
||||
connector.dynamicUpdate = true;
|
||||
connector.SetEndpoints(startNode.transform as RectTransform, endNode.transform as RectTransform);
|
||||
return connector;
|
||||
}
|
||||
|
||||
private void UpdateLines()
|
||||
{
|
||||
Canvas.ForceUpdateCanvases();
|
||||
for (int i = 0; i < lines.Count; i++)
|
||||
{
|
||||
if (lines[i] != null)
|
||||
{
|
||||
lines[i].UpdateLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearChildren(RectTransform root)
|
||||
{
|
||||
if (root == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = root.childCount - 1; i >= 0; i--)
|
||||
{
|
||||
Destroy(root.GetChild(i).gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8d35bf66a09a03cd7ab53136fcb7d2a1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,15 @@
|
||||
using UnityEngine;
|
||||
|
||||
public static class UITheme
|
||||
{
|
||||
public static readonly Color Panel = new Color(0.06f, 0.07f, 0.09f, 0.92f);
|
||||
public static readonly Color PanelSoft = new Color(0.09f, 0.10f, 0.13f, 0.86f);
|
||||
public static readonly Color Gold = new Color(1.00f, 0.72f, 0.24f, 1f);
|
||||
public static readonly Color Text = new Color(0.94f, 0.92f, 0.86f, 1f);
|
||||
public static readonly Color MutedText = new Color(0.70f, 0.72f, 0.76f, 1f);
|
||||
public static readonly Color LearnedNode = new Color(0.19f, 0.66f, 0.34f, 1f);
|
||||
public static readonly Color AvailableNode = new Color(0.86f, 0.58f, 0.18f, 1f);
|
||||
public static readonly Color LockedNode = new Color(0.28f, 0.29f, 0.32f, 1f);
|
||||
public static readonly Color NotEnoughNode = new Color(0.14f, 0.15f, 0.18f, 1f);
|
||||
public static readonly Color Danger = new Color(0.90f, 0.28f, 0.23f, 1f);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1ce84f6aceb15dff29ba0e6028b52677
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user