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
(client) feat:实现技能树界面,实现地图生成器,实现维度指定,实现规则瓦片定义,实现逃跑逻辑,实现消息定义,实现武器动画,实现受击动画 fix: 修复单攻击子弹击中多个目标,修复人物属性计算错误 (#56)
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
This commit is contained in:
175
Client/Assets/Scripts/UI/SkillTreeUI.cs
Normal file
175
Client/Assets/Scripts/UI/SkillTreeUI.cs
Normal file
@@ -0,0 +1,175 @@
|
||||
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) 方法来直接跳转到某一页
|
||||
// 这里为了简化,只实现了左右翻页
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user