Files

235 lines
10 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 int currentCharacter;
// 存储角色动画和角色定义的列表
public List<(TemporaryAnimatorImageUI, CharacterDef)> characterAnimation = new();
// 获取当前选中的角色定义
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.SelectCharacterPlayGame(SelectedCharacter);
}
}
}