325 lines
10 KiB
C#
325 lines
10 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using TMPro;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
using UObject = UnityEngine.Object;
|
|
|
|
namespace XGame
|
|
{
|
|
public class CharacterSwitchController : MonoBehaviour
|
|
{
|
|
private const string ConfigResourcePath = "Config/CharacterConfig";
|
|
private const string SelectedCharacterKey = "CharacterSwitch.SelectedCharacterId";
|
|
private const string PrefabPath = "Assets/Game/Art/UI/Prefab/UI_CharacterSwitch.prefab";
|
|
|
|
private CharacterConfigData config;
|
|
private CharacterConfigItem currentConfig;
|
|
private GameObject currentCharacter;
|
|
private Transform characterRoot;
|
|
private string errorText;
|
|
|
|
// UGUI 引用(替换原 IMGUI 绘制)
|
|
private GameObject uiPanel; // 实例化的 UI 根
|
|
private GameObject selectPanel; // Panel_Select
|
|
private Transform listChars; // List_Chars
|
|
private GameObject itemTemplate; // Item_Char
|
|
private TMP_Text errorLabel; // Txt_Error
|
|
private TMP_Text toggleLabel; // Txt_Toggle
|
|
private readonly List<Button> itemButtons = new List<Button>();
|
|
private readonly List<string> itemIds = new List<string>();
|
|
|
|
public string CurrentCharacterId
|
|
{
|
|
get { return currentConfig == null ? string.Empty : currentConfig.id; }
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
LoadConfig();
|
|
EnsureRoot();
|
|
LoadInitialSelection();
|
|
StartCoroutine(LoadUIAsync());
|
|
}
|
|
|
|
public void SwitchTo(string characterId)
|
|
{
|
|
if (config == null)
|
|
{
|
|
LoadConfig();
|
|
}
|
|
|
|
CharacterConfigItem next = config == null ? null : config.Find(characterId);
|
|
if (next == null)
|
|
{
|
|
errorText = "Character not found: " + characterId;
|
|
Debug.LogWarning(errorText);
|
|
return;
|
|
}
|
|
|
|
SwitchTo(next);
|
|
}
|
|
|
|
private void LoadConfig()
|
|
{
|
|
TextAsset textAsset = Resources.Load<TextAsset>(ConfigResourcePath);
|
|
if (textAsset == null)
|
|
{
|
|
errorText = "Missing character config: Resources/" + ConfigResourcePath + ".json";
|
|
Debug.LogError(errorText);
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
config = JsonUtility.FromJson<CharacterConfigData>(textAsset.text);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
errorText = "Parse character config failed: " + ex.Message;
|
|
Debug.LogError(errorText);
|
|
config = null;
|
|
}
|
|
|
|
if (config == null || config.characters == null || config.characters.Count == 0)
|
|
{
|
|
errorText = "Character config is empty.";
|
|
Debug.LogError(errorText);
|
|
config = null;
|
|
}
|
|
}
|
|
|
|
private void EnsureRoot()
|
|
{
|
|
if (characterRoot != null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
GameObject rootObject = GameObject.Find("CharacterRoot");
|
|
if (rootObject == null)
|
|
{
|
|
rootObject = new GameObject("CharacterRoot");
|
|
}
|
|
|
|
characterRoot = rootObject.transform;
|
|
if (characterRoot.parent != transform)
|
|
{
|
|
characterRoot.SetParent(transform, true);
|
|
}
|
|
}
|
|
|
|
private void LoadInitialSelection()
|
|
{
|
|
if (config == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
string selectedId = PlayerPrefs.GetString(SelectedCharacterKey, string.Empty);
|
|
CharacterConfigItem item = config.Find(selectedId) ?? config.GetDefault();
|
|
if (item != null)
|
|
{
|
|
currentConfig = item;
|
|
PlayerPrefs.SetString(SelectedCharacterKey, item.id);
|
|
PlayerPrefs.Save();
|
|
}
|
|
}
|
|
|
|
private void SwitchTo(CharacterConfigItem item)
|
|
{
|
|
if (currentCharacter != null)
|
|
{
|
|
Destroy(currentCharacter);
|
|
currentCharacter = null;
|
|
}
|
|
|
|
currentConfig = item;
|
|
errorText = string.Empty;
|
|
|
|
PlayerPrefs.SetString(SelectedCharacterKey, item.id);
|
|
PlayerPrefs.Save();
|
|
RefreshLobbyAvatar();
|
|
}
|
|
|
|
private void RefreshLobbyAvatar()
|
|
{
|
|
LobbyWorldController lobby = FindObjectOfType<LobbyWorldController>();
|
|
if (lobby != null)
|
|
{
|
|
lobby.RefreshSelectedFigure();
|
|
}
|
|
}
|
|
|
|
// ---------------- UGUI ----------------
|
|
|
|
// 异步加载 UI 预设:按需从 CDN 下载,避免同步加载读到旧 APK 底包。
|
|
private IEnumerator LoadUIAsync()
|
|
{
|
|
string prefabPath = PrefabPath;
|
|
if (prefabPath.StartsWith("Assets/"))
|
|
{
|
|
prefabPath = prefabPath.Substring(7);
|
|
}
|
|
|
|
UObject asset = null;
|
|
yield return XResLoader.coLoadRes(prefabPath, typeof(GameObject), o => asset = o);
|
|
GameObject prefab = asset as GameObject;
|
|
if (prefab == null)
|
|
{
|
|
Debug.LogError("Load UI_CharacterSwitch failed: " + PrefabPath);
|
|
yield break;
|
|
}
|
|
|
|
uiPanel = Instantiate(prefab);
|
|
// 角色切换是普通功能界面 → 挂到 UIRoot/Normal 层(见 UI 挂载规则)
|
|
UIManager.AttachTo(UILayer.Normal, uiPanel);
|
|
|
|
CacheUI();
|
|
BuildCharacterButtons();
|
|
}
|
|
|
|
private void CacheUI()
|
|
{
|
|
if (uiPanel == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Transform sel = uiPanel.transform.FindTransform("Panel_Select");
|
|
selectPanel = sel == null ? null : sel.gameObject;
|
|
listChars = uiPanel.transform.FindTransform("List_Chars");
|
|
Transform item = uiPanel.transform.FindTransform("Item_Char");
|
|
itemTemplate = item == null ? null : item.gameObject;
|
|
Transform err = uiPanel.transform.FindTransform("Txt_Error");
|
|
errorLabel = err == null ? null : err.GetComponent<TMP_Text>();
|
|
Transform tog = uiPanel.transform.FindTransform("Txt_Toggle");
|
|
toggleLabel = tog == null ? null : tog.GetComponent<TMP_Text>();
|
|
|
|
Transform toggleBtn = uiPanel.transform.FindTransform("Btn_Toggle");
|
|
if (toggleBtn != null)
|
|
{
|
|
Button b = toggleBtn.GetComponent<Button>();
|
|
if (b != null)
|
|
{
|
|
b.onClick.RemoveListener(OnToggleClicked);
|
|
b.onClick.AddListener(OnToggleClicked);
|
|
}
|
|
}
|
|
|
|
if (selectPanel != null)
|
|
{
|
|
selectPanel.SetActive(false);
|
|
}
|
|
UpdateToggleLabel();
|
|
}
|
|
|
|
private void BuildCharacterButtons()
|
|
{
|
|
itemButtons.Clear();
|
|
itemIds.Clear();
|
|
if (itemTemplate == null || listChars == null || config == null || config.characters == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < config.characters.Count; i++)
|
|
{
|
|
CharacterConfigItem item = config.characters[i];
|
|
if (item == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
GameObject row = Instantiate(itemTemplate, listChars);
|
|
row.name = "Item_Char_" + item.id;
|
|
row.SetActive(true);
|
|
|
|
Transform label = row.transform.FindTransform("Txt_Char");
|
|
if (label != null)
|
|
{
|
|
TMP_Text t = label.GetComponent<TMP_Text>();
|
|
if (t != null)
|
|
{
|
|
t.text = string.IsNullOrEmpty(item.displayName) ? item.id : item.displayName;
|
|
}
|
|
}
|
|
|
|
Button btn = row.GetComponent<Button>();
|
|
if (btn != null)
|
|
{
|
|
string captured = item.id;
|
|
btn.onClick.RemoveAllListeners();
|
|
btn.onClick.AddListener(() => OnCharClicked(captured));
|
|
itemButtons.Add(btn);
|
|
itemIds.Add(item.id);
|
|
}
|
|
}
|
|
|
|
RefreshSelection();
|
|
RefreshError();
|
|
}
|
|
|
|
private void OnToggleClicked()
|
|
{
|
|
if (selectPanel == null)
|
|
{
|
|
return;
|
|
}
|
|
selectPanel.SetActive(!selectPanel.activeSelf);
|
|
}
|
|
|
|
private void OnCharClicked(string characterId)
|
|
{
|
|
SwitchTo(characterId);
|
|
RefreshSelection();
|
|
RefreshError();
|
|
UpdateToggleLabel();
|
|
if (selectPanel != null)
|
|
{
|
|
selectPanel.SetActive(false);
|
|
}
|
|
}
|
|
|
|
// 高亮当前选中项(当前项绿色加粗,其余白色)
|
|
private void RefreshSelection()
|
|
{
|
|
for (int i = 0; i < itemButtons.Count; i++)
|
|
{
|
|
Button btn = itemButtons[i];
|
|
if (btn == null)
|
|
{
|
|
continue;
|
|
}
|
|
bool selected = currentConfig != null && currentConfig.id == itemIds[i];
|
|
TMP_Text t = btn.GetComponentInChildren<TMP_Text>(true);
|
|
if (t != null)
|
|
{
|
|
t.color = selected ? new Color(0.34f, 0.84f, 0.55f, 1f) : new Color(0.96f, 0.97f, 1f, 1f);
|
|
t.fontStyle = selected ? FontStyles.Bold : FontStyles.Normal;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void RefreshError()
|
|
{
|
|
if (errorLabel == null)
|
|
{
|
|
return;
|
|
}
|
|
errorLabel.text = errorText ?? string.Empty;
|
|
errorLabel.gameObject.SetActive(!string.IsNullOrEmpty(errorText));
|
|
}
|
|
|
|
private void UpdateToggleLabel()
|
|
{
|
|
if (toggleLabel == null)
|
|
{
|
|
return;
|
|
}
|
|
toggleLabel.text = string.IsNullOrEmpty(CurrentCharacterId) ? "角色" : "角色: " + CurrentCharacterId;
|
|
}
|
|
}
|
|
}
|