using System; using System.Globalization; using AibisDream.Framework; using AibisDream.Kit; using AibisDream.Utility; using Febucci.UI.Core; using TMPro; using UnityEngine; using UnityEngine.UI; namespace AibisDream { public class Bubble : MonoBehaviour, IBubble { private TypewriterCore _typewriter; private TMP_Text _actorName; private TMP_Text _lineText; private LayoutElement _layoutElement; private LayoutGroup _layoutGroup; private RectTransform _rect; private Image _bubbleImage; #region 参数 [Header("参数")] [SerializeField] private ActorRole role; [SerializeField] private int idx; [SerializeField] private int maxWidth; [SerializeField] private int minWidth; public ActorRole Role => role; public int Idx => idx; #endregion public event Action OnDisposed; public event Action OnLineShown; public void LoadConfig(BubbleSlotData data) { InitRefs(); role = data.actorRole; idx = data.idx; maxWidth = data.maxWidth; minWidth = data.minWidth; var rect = transform as RectTransform; rect.localPosition = UIManager.GetDialogUIPos(data.slotPosition); // 设置style SetStyle(data.bubbleStyle, data.pivotType); // 注册事件 _typewriter.onTextShowed.AddListener(InvokeLineShown); EnumEventSystem.Global.Register(SettingChangeEvent.TextSpeed, OnTextSpeedChanged); } private void InvokeLineShown() { OnLineShown?.Invoke(); OnLineShown = null; } private void SetStyle(BubbleStyle bubbleStyle, PivotType pivotType) { _bubbleImage.color = bubbleStyle.imageColor; // padding内容 _layoutGroup.padding = bubbleStyle.BubblePadding; _lineText.margin = bubbleStyle.linePadding; _lineText.fontSize = bubbleStyle.lineFontSize; _actorName.margin = bubbleStyle.actorPadding; _actorName.fontSize = bubbleStyle.actorFontSize; // 是否展示名称 _actorName.gameObject.SetActive(bubbleStyle.hasActorName); // 锚点相关 _rect.pivot = CommonUtil.GetPivotByType(pivotType); var spritePath = bubbleStyle.bubbleSpriteAddress.EndsWith("]") ? $"{bubbleStyle.bubbleSpriteAddress}" : $"{bubbleStyle.bubbleSpriteAddress}[{pivotType}]"; _bubbleImage.sprite = ResourceKit.LoadAssetSync(spritePath); // 初始化文字速度 if (Application.isPlaying) { var speedStr = SettingLoader.Instance.TryRead("TextSpeed", out string textSpeed) ? textSpeed : "1"; OnTextSpeedChanged(speedStr); } } private void OnTextSpeedChanged(string value) { float speed = float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out float result) ? result : 1f; _typewriter.SetTypewriterSpeed(speed); } private void InitRefs() { _typewriter = GetComponentInChildren(); _actorName = transform.Find("名称").GetComponent(); _typewriter.onTextShowed.RemoveAllListeners(); _typewriter.onTextShowed.AddListener(() => EnumEventSystem.Global.Send(DialogEventEnum.LineShown)); // 获取内容文字 _lineText = _typewriter.GetComponent(); _layoutElement = _typewriter.GetComponent(); // 气泡自身 _layoutGroup = GetComponent(); _bubbleImage = GetComponent(); _rect = _bubbleImage.rectTransform; } public void ShowActorName(CharacterVo characterVo) { if (_actorName == null) return; _actorName.text = string.IsNullOrEmpty(characterVo.GetActorName()) ? string.Empty : characterVo.GetActorName(); } public void ShowLine(string line) { _typewriter.TextAnimator.SetText(""); gameObject.SetActive(true); HandleLayout(line); _typewriter.ShowText(line); } public bool SkipLine() { if (_typewriter.isShowingText) { _typewriter.SkipTypewriter(); return true; } else { return false; } } public void Hide() { gameObject.SetActive(false); } public void Dispose() { Hide(); _typewriter.onTextShowed.RemoveAllListeners(); OnDisposed?.Invoke(this); OnDisposed = null; } private void HandleLayout(string line) { // 先去除富文本标签 var width = BubbleGroup.Instance.EstimateTextWidth(line.RemoveRichTextTags(), _lineText.fontSize); if (width > maxWidth) { _layoutElement.preferredWidth = maxWidth; } else { _layoutElement.preferredWidth = -1; } _layoutElement.minWidth = minWidth; LayoutRebuilder.ForceRebuildLayoutImmediate(_rect); } #if UNITY_EDITOR [Header("测试参数")] public int testMinWidth; public int testMaxWidth; public BubbleStyle testBubbleStyle; public PivotType testPivotType; public void LoadStyle() { InitRefs(); SetStyle(testBubbleStyle, testPivotType); _layoutElement.minWidth = testMinWidth; _layoutElement.preferredWidth = testMaxWidth; } public void SaveStyle() { if (!testBubbleStyle) return; InitRefs(); testBubbleStyle.linePadding = _lineText.margin; testBubbleStyle.lineFontSize = _lineText.fontSize; testBubbleStyle.actorPadding = _actorName.margin; testBubbleStyle.actorFontSize = _actorName.fontSize; testBubbleStyle.BubblePadding = _layoutGroup.padding; testBubbleStyle.hasActorName = _actorName.gameObject.activeSelf; } #endif } public interface IBubble { public ActorRole Role { get; } public int Idx { get; } public event Action OnLineShown; public void ShowActorName(CharacterVo characterVo); public void ShowLine(string line); public bool SkipLine(); public void Hide(); } }