mirror of
http://47.107.252.169:3000/Roguelite-Game-Developing-Team/Gen_Hack-and-Slash-Roguelite.git
synced 2025-11-20 02:17:12 +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/57
244 lines
10 KiB
C#
244 lines
10 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using Data;
|
||
using Managers;
|
||
using Map;
|
||
using Prefab;
|
||
using TMPro;
|
||
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
|
||
namespace UI
|
||
{
|
||
public class SelectCharacterUI : MonoBehaviour
|
||
{
|
||
// 角色显示位置
|
||
public Transform characterDisplay;
|
||
|
||
// 角色信息文本
|
||
public TMP_Text characterInformation;
|
||
|
||
public Button enterButton;
|
||
public TMP_Text buttonText;
|
||
|
||
[SerializeField]
|
||
// 目标角色动画显示尺寸
|
||
private float targetCharacterAnimationDisplaySize = 600f;
|
||
|
||
// 存储角色动画和角色定义的列表
|
||
public List<(TemporaryAnimatorImageUI, CharacterDef)> characterAnimation = new();
|
||
|
||
// 当前选中的角色索引
|
||
public int currentCharacter = 0;
|
||
|
||
// 获取当前选中的角色定义
|
||
public CharacterDef SelectedCharacter => characterAnimation[currentCharacter].Item2;
|
||
|
||
/// <summary>
|
||
/// 当脚本实例被启用时调用。
|
||
/// 初始化角色UI,加载角色数据,并生成动画。
|
||
/// </summary>
|
||
private void Start()
|
||
{
|
||
Program.Instance.FocusedDimension.OnDimensionLoaded += MapLoaded;
|
||
enterButton.interactable = false;
|
||
buttonText.text = "地图加载中";
|
||
|
||
var characterDefs = DefineManager.Instance.QueryDefinesByType<CharacterDef>();
|
||
|
||
if (characterDefs == null || characterDefs.Length == 0)
|
||
{
|
||
Debug.LogWarning("未找到任何角色定义,禁用SelectCharacterUI。");
|
||
gameObject.SetActive(false);
|
||
return;
|
||
}
|
||
|
||
foreach (var def in characterDefs)
|
||
{
|
||
if (def.drawingOrder == null)
|
||
{
|
||
Debug.LogWarning($"角色 '{def.label}' 的 drawingOrder 为 null,跳过动画生成。");
|
||
continue;
|
||
}
|
||
|
||
var drawingOrder = def.drawingOrder.GetDrawNodeDef(EntityState.Idle, Orientation.Down, out _);
|
||
if (drawingOrder == null)
|
||
{
|
||
Debug.LogWarning($"角色 '{def.label}' 在 Idle/Down 状态下没有有效的绘制节点,跳过动画生成。");
|
||
continue;
|
||
}
|
||
|
||
// GenerateTemporaryAnimationUI 返回一个组件(例如 RectTransform 或 CanvasGroup),
|
||
// 其gameObject是实际的UI对象。
|
||
var animationComponent = TemporaryAnimationManager.Instance.GenerateTemporaryAnimationUI(
|
||
drawingOrder, characterDisplay.position, characterDisplay, -1);
|
||
|
||
// 确保animationComponent及其gameObject存在
|
||
if (animationComponent != null && animationComponent.gameObject != null)
|
||
{
|
||
var rectTransform = animationComponent.gameObject.GetComponent<RectTransform>();
|
||
if (rectTransform != null)
|
||
{
|
||
var initialSize = rectTransform.sizeDelta;
|
||
// 检查原始尺寸是否有效,避免除以零和处理极小值
|
||
if (initialSize.x > 0.001f && initialSize.y > 0.001f)
|
||
{
|
||
var scaleX = targetCharacterAnimationDisplaySize / initialSize.x;
|
||
var scaleY = targetCharacterAnimationDisplaySize / initialSize.y;
|
||
var scaleFactor = Mathf.Min(scaleX, scaleY);
|
||
rectTransform.localScale = new Vector3(scaleFactor, scaleFactor, 1f);
|
||
}
|
||
else
|
||
{
|
||
Debug.LogWarning(
|
||
$"动画 '{animationComponent.name}' 原始尺寸无效 ({initialSize.x}x{initialSize.y}), 无法进行缩放。");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Debug.LogWarning($"生成动画 '{animationComponent.name}' 的GameObject没有RectTransform组件,无法进行缩放。");
|
||
}
|
||
|
||
characterAnimation.Add((animationComponent, def));
|
||
animationComponent.gameObject.SetActive(false); // 初始时全部禁用
|
||
animationComponent.gameObject.name = def.label;
|
||
}
|
||
else
|
||
{
|
||
Debug.LogWarning(
|
||
$"GenerateTemporaryAnimationUI 返回了null或者GameObject为null for character '{def.label}',跳过添加和缩放。");
|
||
}
|
||
}
|
||
|
||
// 在调用 UpdateUI 之前验证 characterAnimation 列表是否为空。
|
||
// 如果列表为空,说明没有可显示的角色,UI应该被禁用。
|
||
if (characterAnimation.Count == 0)
|
||
{
|
||
Debug.LogWarning("尽管找到了角色定义,但未能成功生成任何角色动画UI。禁用SelectCharacterUI。");
|
||
gameObject.SetActive(false);
|
||
return; // Early exit if no animatable characters
|
||
}
|
||
|
||
UpdateUI(currentCharacter); // 初始显示第一个角色
|
||
|
||
}
|
||
|
||
private void MapLoaded(Dimension dimension)
|
||
{
|
||
dimension.OnDimensionLoaded -= MapLoaded;
|
||
buttonText.text = "选择此角色";
|
||
enterButton.interactable = true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新UI显示当前选中角色的动画和信息。
|
||
/// </summary>
|
||
/// <param name="newCharacterIndex">新角色的索引。</param>
|
||
public void UpdateUI(int newCharacterIndex)
|
||
{
|
||
// 在更新之前,检查 characterAnimation 列表是否非空。
|
||
if (characterAnimation.Count == 0)
|
||
{
|
||
Debug.LogWarning("UpdateUI 被调用,但 characterAnimation 列表为空。无法更新UI。");
|
||
// 此时,如果UI仍激活,可能需要禁用它,取决于具体需求
|
||
gameObject.SetActive(false);
|
||
return;
|
||
}
|
||
|
||
// 在更新之前,确保新索引是有效的,防止越界
|
||
if (newCharacterIndex < 0 || newCharacterIndex >= characterAnimation.Count)
|
||
{
|
||
// 如果 newCharacterIndex 计算有误,应进行修正或报错
|
||
// 这里假设传入的 newCharacterIndex 是经过 OnLeft/OnRight 处理的环绕索引
|
||
// 但为了健壮性,仍进行检查
|
||
Debug.LogError($"UpdateUI 接收到无效的角色索引: {newCharacterIndex} (角色总数: {characterAnimation.Count})。");
|
||
// 可选择将索引强制规范化,例如 newCharacterIndex = 0; 或 return;
|
||
newCharacterIndex = 0; // 强制设置为第一个,以防万一
|
||
if (characterAnimation.Count == 0) return; // 再次检查以防强制为0后依然越界
|
||
}
|
||
|
||
// 优化前一个角色的禁用逻辑
|
||
// 只有当前角色索引有效且其对应的GameObject存在时才禁用
|
||
if (currentCharacter >= 0 && currentCharacter < characterAnimation.Count)
|
||
{
|
||
var previousAnimator = characterAnimation[currentCharacter].Item1;
|
||
if (previousAnimator != null && previousAnimator.gameObject.activeSelf)
|
||
{
|
||
previousAnimator.gameObject.SetActive(false);
|
||
}
|
||
}
|
||
|
||
currentCharacter = newCharacterIndex; // 更新当前角色索引
|
||
|
||
// 激活新的角色动画
|
||
var currentAnimator = characterAnimation[currentCharacter].Item1;
|
||
if (currentAnimator != null)
|
||
{
|
||
currentAnimator.gameObject.SetActive(true);
|
||
}
|
||
else
|
||
{
|
||
// 如果当前选中的角色动画组件丢失,记录警告并尝试继续显示信息
|
||
Debug.LogWarning($"当前选中角色的动画组件为null (索引: {currentCharacter})。");
|
||
// 考虑更强大的错误处理:跳到下一个有效角色,或者禁用此UI。
|
||
}
|
||
|
||
// 更新角色信息
|
||
var def = characterAnimation[currentCharacter].Item2;
|
||
characterInformation.text = $"<color=#FFBF00>{def.label}</color>\n{def.description}";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理用户点击左箭头按钮的逻辑,切换到上一个角色。
|
||
/// </summary>
|
||
public void OnLeft()
|
||
{
|
||
// 增加对 characterAnimation.Count 的检查
|
||
if (characterAnimation.Count == 0)
|
||
{
|
||
Debug.LogWarning("无法左移,因为没有可用的角色动画。");
|
||
return;
|
||
}
|
||
|
||
var newPos = currentCharacter - 1;
|
||
if (newPos < 0)
|
||
newPos += characterAnimation.Count; // 环绕到列表末尾
|
||
UpdateUI(newPos);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理用户点击右箭头按钮的逻辑,切换到下一个角色。
|
||
/// </summary>
|
||
public void OnRight()
|
||
{
|
||
// 增加对 characterAnimation.Count 的检查
|
||
if (characterAnimation.Count == 0)
|
||
{
|
||
Debug.LogWarning("无法右移,因为没有可用的角色动画。");
|
||
return;
|
||
}
|
||
|
||
var newPos = currentCharacter + 1;
|
||
if (newPos >= characterAnimation.Count)
|
||
newPos %= characterAnimation.Count; // 环绕到列表开头
|
||
UpdateUI(newPos);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理用户点击“确认”按钮的逻辑,选择当前角色并关闭UI。
|
||
/// </summary>
|
||
public void OnEnter()
|
||
{
|
||
// 确保在尝试选择角色之前,characterAnimation 列表非空,并且 currentCharacter 有效
|
||
if (characterAnimation.Count == 0 || currentCharacter < 0 || currentCharacter >= characterAnimation.Count)
|
||
{
|
||
Debug.LogWarning("无法选择角色,因为没有可用的角色或当前选择无效。");
|
||
gameObject.SetActive(false); // 强制关闭UI,避免空选
|
||
return;
|
||
}
|
||
|
||
gameObject.SetActive(false);
|
||
Program.Instance.PlayGame(SelectedCharacter);
|
||
}
|
||
}
|
||
} |