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; /// /// 当脚本实例被启用时调用。 /// 初始化角色UI,加载角色数据,并生成动画。 /// private void Start() { Program.Instance.FocusedDimension.OnDimensionLoaded += MapLoaded; enterButton.interactable = false; buttonText.text = "地图加载中"; var characterDefs = DefineManager.Instance.QueryDefinesByType(); 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(); 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; } /// /// 更新UI显示当前选中角色的动画和信息。 /// /// 新角色的索引。 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 = $"{def.label}\n{def.description}"; } /// /// 处理用户点击左箭头按钮的逻辑,切换到上一个角色。 /// public void OnLeft() { // 增加对 characterAnimation.Count 的检查 if (characterAnimation.Count == 0) { Debug.LogWarning("无法左移,因为没有可用的角色动画。"); return; } var newPos = currentCharacter - 1; if (newPos < 0) newPos += characterAnimation.Count; // 环绕到列表末尾 UpdateUI(newPos); } /// /// 处理用户点击右箭头按钮的逻辑,切换到下一个角色。 /// 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); } /// /// 处理用户点击“确认”按钮的逻辑,选择当前角色并关闭UI。 /// 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); } } }