using System; using System.Collections; using AibisDream.Utility; using DG.Tweening; using UnityEngine; namespace AibisDream.FixSystem { public class CharacterViewer : MonoBehaviour { private string _curCharacterName; private GameObject _curCharacter; private float _characterAlpha; private Coroutine _autoBlinkCoroutine; private Transform FaceGroup => _curCharacter.transform.Find("表情"); private Transform PoseGroup => _curCharacter.transform.Find("动作"); private Transform LinkDevice => _curCharacter.transform.Find("换液设备"); private SpriteRenderer _blinkLayer; public CharacterData characterData; public event Action CharacterChangeEvent; public IEnumerator CharacterInit(string characterName) { // 异步加载角色预制体(psb) ResourceRequest request = Resources.LoadAsync($"Characters/{characterName}"); yield return request; #if DEBUG if (request.asset == null) { Debug.Log($"{characterName}没有找到"); yield break; } #endif // 先卸载旧的 if (_curCharacter != null) { Destroy(_curCharacter); _curCharacter = null; } characterData = new CharacterData(); characterData.characterName = characterName; // 加载新的 GameObject characterPrefab = request.asset as GameObject; _curCharacter = Instantiate(characterPrefab, transform); // 初始化处理 _curCharacter.SetActive(false); _blinkLayer = _curCharacter.transform.Find("闭眼").GetComponent(); _blinkLayer.enabled = false; // 表情和动作只留一种 characterData.faceName = ActiveLayer(FaceGroup); characterData.poseName = ActiveLayer(PoseGroup); // 换液设备先隐藏 RemoveLinkDevice(); // 初始化角色透明度 SetCharacterAlpha(0); // 等待一帧,确保初始化完成 yield return new WaitForSeconds(1); // 激活角色 _curCharacter.SetActive(true); characterData.isShow = false; UpdateCharacterData(); } private void UpdateCharacterData() { CharacterChangeEvent?.Invoke(characterData); } private static string ActiveLayer(Transform root, string layerName = null) { var childLayers = root.GetComponentsInChildren(true); if (childLayers.Length == 0) return null; foreach (var layer in childLayers) { layer.enabled = layer.gameObject.name == layerName; } // 如果输入为空,就默认激活一层 if (layerName == null) { childLayers[0].enabled = true; return childLayers[0].gameObject.name; } return layerName; } private void SetCharacterAlpha(float alpha) { _characterAlpha = alpha; SpriteRenderer[] renderers = _curCharacter.GetComponentsInChildren(true); Array.ForEach(renderers, spriteRenderer => { spriteRenderer.SetAlpha(alpha); }); } public IEnumerator CharacterFadeIn(float duration = 1f) { if (_curCharacter) { yield return FadeCharacter(1, duration); characterData.isShow = true; UpdateCharacterData(); } } public IEnumerator CharacterFadeOut(float duration = 1f) { if (_curCharacter != null) { yield return FadeCharacter(0, duration); characterData.isShow = false; UpdateCharacterData(); } } private IEnumerator FadeCharacter(float toAlpha, float duration) { yield return DOTween.To(() => _characterAlpha, x => SetCharacterAlpha(x), toAlpha, duration) .WaitForCompletion(); } public void SwitchPose(string poseName) { characterData.poseName = ActiveLayer(PoseGroup, poseName); UpdateCharacterData(); } public void SwitchFace(string faceName) { StopAutoBlink(); characterData.faceName = ActiveLayer(FaceGroup, faceName); UpdateCharacterData(); } public void Blink() { _blinkLayer.enabled = true; _ = CommonUtil.Delay(100, () => { _blinkLayer.enabled = false; }); } public void AutoBlink() { StopAutoBlink(); _autoBlinkCoroutine = StartCoroutine(AutoBlinkAsync()); } public void StopAutoBlink() { if (_autoBlinkCoroutine != null) { StopCoroutine(_autoBlinkCoroutine); } } private IEnumerator AutoBlinkAsync() { while (true) { yield return new WaitForSeconds(6f); Blink(); } } public void AddLinkDevice() { characterData.hasDevice = true; UpdateCharacterData(); LinkDevice.gameObject.SetActive(true); } public void RemoveLinkDevice() { characterData.hasDevice = false; UpdateCharacterData(); LinkDevice.gameObject.SetActive(false); } public void CharacterShow(string characterName = "") { if (_curCharacter != null) { characterData.isShow = true; UpdateCharacterData(); // 将角色的透明度设置为 1 SetCharacterAlpha(1); } else { Debug.LogError($"Character {characterName} not found in loaded characters."); } } public void OnDestroy() { characterData = new CharacterData(); UpdateCharacterData(); } } public struct CharacterData { public string characterName; public string faceName; public string poseName; public bool hasDevice; public bool isShow; } }