mirror of
http://47.107.252.169:3000/Roguelite-Game-Developing-Team/Gen_Hack-and-Slash-Roguelite.git
synced 2025-11-20 04:07:13 +08:00
Co-authored-by: m0_75251201 <m0_75251201@noreply.gitcode.com> Reviewed-on: http://47.107.252.169:3000/Roguelite-Game-Developing-Team/Gen_Hack-and-Slash-Roguelite/pulls/56
175 lines
9.0 KiB
C#
175 lines
9.0 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
|
||
namespace UI
|
||
{
|
||
public class SkillTreeUI : FullScreenUI
|
||
{
|
||
public SkillTreePageUI skillTreePageUIPrefab;
|
||
public Transform skillTreePageUIParent; // 用于承载 SkillTreePageUI 实例的 Transform
|
||
|
||
private List<SkillTreePageUI> _skillTreePageUIs = new List<SkillTreePageUI>();
|
||
private int _currentPageIndex = 0; // 当前显示的页面索引
|
||
// 动画相关
|
||
private bool _isAnimating = false;
|
||
private float _animationProgress = 0f; // 0到1的进度
|
||
[SerializeField] private float _animationDuration = 0.3f; // 动画持续时间
|
||
private int _animationDirection = 0; // -1:左翻页, 1:右翻页 (或0表示无动画)
|
||
private SkillTreePageUI _currentMovingPage; // 当前正在移动的页面
|
||
private SkillTreePageUI _targetMovingPage; // 正在移入的页面
|
||
private float _pageWidth; // 页面的标准宽度,用于计算滑动位置
|
||
private void Start()
|
||
{
|
||
// 获取所有技能树标签
|
||
var allTags = Managers.SkillTreeManager.Instance.GetAllTag();
|
||
if (allTags == null || allTags.Length == 0)
|
||
{
|
||
Debug.LogWarning("No skill tree tags found. SkillTreeUI will be empty.");
|
||
// 可以在这里禁用翻页按钮或显示提示
|
||
return;
|
||
}
|
||
// [改进] 动态获取页面的宽度
|
||
// 为了准确获取 prefab 的尺寸,最好在编辑器中设置好 prefab 的 RectTransform,
|
||
// 或者在这里实例化一个临时对象来获取其 RectTransform 信息。
|
||
var prefabRect = skillTreePageUIPrefab.GetComponent<RectTransform>();
|
||
if (prefabRect != null)
|
||
{
|
||
_pageWidth = prefabRect.rect.width;
|
||
// 如果父级有LayoutGroup或者Canvas Scaler可能影响实际尺寸,需注意
|
||
// 如果 prefab 是撑满 FullScreenUI 的,那 _pageWidth 应该等于 FullScreenUI 的宽度
|
||
// 这里假设 SkillTreePageUI 会充满其父级,或者具有固定宽度。
|
||
// 简单起见,我们也可以假设它充满父级,那么 _pageWidth = parent.GetComponent<RectTransform>().rect.width;
|
||
if (skillTreePageUIParent != null)
|
||
{
|
||
_pageWidth = skillTreePageUIParent.GetComponent<RectTransform>().rect.width;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Debug.LogError("SkillTreePageUI Prefab does not have a RectTransform!");
|
||
_pageWidth = 1920; // fallback default
|
||
}
|
||
// 为每个标签实例化并初始化 SkillTreePageUI
|
||
foreach (var tag in allTags)
|
||
{
|
||
var newPage = Instantiate(skillTreePageUIPrefab, skillTreePageUIParent);
|
||
newPage.name = $"SkillTreePage_{tag}"; // 方便在 Hierarchy 中识别
|
||
|
||
// 设置 RectTransform 属性,确保页面正确布局
|
||
var pageRectTransform = newPage.GetComponent<RectTransform>();
|
||
pageRectTransform.anchorMin = Vector2.zero;
|
||
pageRectTransform.anchorMax = Vector2.one;
|
||
pageRectTransform.pivot = new Vector2(0.5f, 0.5f); // 中心
|
||
pageRectTransform.anchoredPosition = Vector2.zero;
|
||
pageRectTransform.sizeDelta = Vector2.zero; // 撑满父级
|
||
newPage.GenerateAndLayoutAllSkillTrees(tag);
|
||
_skillTreePageUIs.Add(newPage);
|
||
// 初始状态下所有页面都先设为激活,通过位置控制显示
|
||
newPage.gameObject.SetActive(true);
|
||
}
|
||
// 根据 _currentPageIndex 设置所有页面的初始位置
|
||
// 只有当前页面在中央 (0,0),其他页面在屏幕外
|
||
for (var i = 0; i < _skillTreePageUIs.Count; i++)
|
||
{
|
||
_skillTreePageUIs[i].GetComponent<RectTransform>().anchoredPosition =
|
||
new Vector2(_pageWidth * (i - _currentPageIndex), 0);
|
||
}
|
||
// 确保当前页面在层级的最上方,防止被其他未隐藏的页面遮挡
|
||
if (_skillTreePageUIs.Count > 0)
|
||
{
|
||
_skillTreePageUIs[_currentPageIndex].transform.SetAsLastSibling();
|
||
}
|
||
}
|
||
// 实现翻页动画
|
||
public override void TickUI()
|
||
{
|
||
base.TickUI();
|
||
if (_isAnimating)
|
||
{
|
||
_animationProgress += Time.deltaTime / _animationDuration;
|
||
_animationProgress = Mathf.Clamp01(_animationProgress);
|
||
// 计算当前页面的目标位置:从 0 移动到 -_pageWidth * _animationDirection
|
||
var currentX = Mathf.Lerp(0, -_pageWidth * _animationDirection, _animationProgress);
|
||
_currentMovingPage.GetComponent<RectTransform>().anchoredPosition = new Vector2(currentX, 0);
|
||
// 计算目标页面的目标位置:从 _pageWidth * _animationDirection 移动到 0
|
||
var targetX = Mathf.Lerp(_pageWidth * _animationDirection, 0, _animationProgress);
|
||
_targetMovingPage.GetComponent<RectTransform>().anchoredPosition = new Vector2(targetX, 0);
|
||
if (_animationProgress >= 1f)
|
||
{
|
||
// 动画结束
|
||
_isAnimating = false;
|
||
_animationDirection = 0; // 重置动画方向
|
||
// 更新当前页面索引 (使用 _targetMovingPage 的索引)
|
||
_currentPageIndex = _skillTreePageUIs.IndexOf(_targetMovingPage);
|
||
// 确保新的当前页面在正确位置 (0,0)
|
||
_targetMovingPage.GetComponent<RectTransform>().anchoredPosition = Vector2.zero;
|
||
// 隐藏所有非当前页面,将其放置到屏幕外,减少渲染负担
|
||
for (var i = 0; i < _skillTreePageUIs.Count; i++)
|
||
{
|
||
if (i != _currentPageIndex)
|
||
{
|
||
// 将非当前页面放置到正确的位置,以便下次翻页时能从正确位置移入
|
||
_skillTreePageUIs[i].GetComponent<RectTransform>().anchoredPosition =
|
||
new Vector2(_pageWidth * (i - _currentPageIndex), 0);
|
||
}
|
||
}
|
||
// 确保新的当前页面在层级最上方
|
||
_skillTreePageUIs[_currentPageIndex].transform.SetAsLastSibling();
|
||
}
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 控制切换到上一页。
|
||
/// </summary>
|
||
public void TurnPageLeft()
|
||
{
|
||
if (_isAnimating) return; // 动画进行中,忽略新的翻页请求
|
||
// 检查是否已经到达第一页
|
||
if (_currentPageIndex <= 0)
|
||
{
|
||
Debug.Log("SkillTreeUI: Already at the first page.");
|
||
return;
|
||
}
|
||
_animationDirection = -1; // 左翻页方向
|
||
StartPageTurnAnimation(_currentPageIndex - 1);
|
||
}
|
||
/// <summary>
|
||
/// 控制切换到下一页。
|
||
/// </summary>
|
||
public void TurnPageRight()
|
||
{
|
||
if (_isAnimating) return; // 动画进行中,忽略新的翻页请求
|
||
// 检查是否已经到达最后一页
|
||
if (_currentPageIndex >= _skillTreePageUIs.Count - 1)
|
||
{
|
||
Debug.Log("SkillTreeUI: Already at the last page.");
|
||
return;
|
||
}
|
||
_animationDirection = 1; // 右翻页方向
|
||
StartPageTurnAnimation(_currentPageIndex + 1);
|
||
}
|
||
/// <summary>
|
||
/// 启动翻页动画的内部方法。
|
||
/// </summary>
|
||
/// <param name="targetPageIndex">目标页面的索引。</param>
|
||
private void StartPageTurnAnimation(int targetPageIndex)
|
||
{
|
||
_isAnimating = true;
|
||
_animationProgress = 0f; // 重置动画进度
|
||
_currentMovingPage = _skillTreePageUIs[_currentPageIndex];
|
||
_targetMovingPage = _skillTreePageUIs[targetPageIndex];
|
||
// 确保参与动画的两个页面都是激活状态
|
||
_currentMovingPage.gameObject.SetActive(true);
|
||
_targetMovingPage.gameObject.SetActive(true);
|
||
// 将目标页面初始位置设置在当前页的左侧或右侧
|
||
// 例如,如果向右翻页 (_animationDirection = 1),目标页从右边 (_pageWidth) 滑入
|
||
_targetMovingPage.GetComponent<RectTransform>().anchoredPosition =
|
||
new Vector2(_pageWidth * _animationDirection, 0);
|
||
// 确保目标页面在当前页面之上,以便在滑动时覆盖旧页面
|
||
_targetMovingPage.transform.SetAsLastSibling();
|
||
}
|
||
// 可以添加一个 GoToPage(int pageIndex) 方法来直接跳转到某一页
|
||
// 这里为了简化,只实现了左右翻页
|
||
}
|
||
} |