using System; using System.Collections; using AibisDream.Framework; using AibisDream.Kit; using DG.Tweening; using TMPro; using UnityEngine; namespace AibisDream.FixSystem { public class ScreenSystem : MonoBehaviour, IScreen, IDialogView { private static readonly int DirectionalAlphaFadeFade = Shader.PropertyToID("_DirectionalAlphaFadeFade"); #region 效果参数 public float rotateDuration = 0.5f; public float typeSpeed = 0.05f; public int maxTextLine; #endregion #region 索引 private Transform _textScreen; [SerializeField] private TMP_Text title; [SerializeField] private TMP_Text text; [SerializeField] private SpriteRenderer screenImage; private Material _imageMaterial; private Action _nextStep; private TextGenerator _generator; private TextGenerationSettings _generationSettings; private IUnRegister _plugOutRmv; #endregion private void Awake() { InitComponentRefs(); Register(); } private void InitComponentRefs() { _textScreen = transform.Find("旋转屏幕"); _imageMaterial = screenImage.material; _generator = new TextGenerator(); _generationSettings = new TextGenerationSettings { font = text.font.sourceFontFile, fontSize = Mathf.RoundToInt(text.fontSize), lineSpacing = text.lineSpacing, horizontalOverflow = HorizontalWrapMode.Wrap, verticalOverflow = VerticalWrapMode.Truncate, generationExtents = new Vector2(text.rectTransform.rect.width, Mathf.Infinity), resizeTextForBestFit = false }; } private void Register() { FixSystemCenter.SystemDic.Register(this); DialogCanvasManager.Instance.RegisterDialogView(DialogViewType.Screen, this); } private void OnDestroy() { FixSystemCenter.SystemDic.Unregister(); DialogCanvasManager.Instance.UnregisterDialogView(DialogViewType.Screen); } #region 基础功能 public void OpenTextScreen() { // 旋转 _textScreen.DORotate(new Vector3(0, 0, 0), rotateDuration); } public void ShowTitle(string targetTitle) { title.text = targetTitle; } public IEnumerator ShowText(string targetText) { // 先换行 if (!string.IsNullOrEmpty(text.text)) { text.text += "\n"; } // 先估算新增行数 var targetLineNum = EstimateLineNum(targetText); // 截断超出屏幕的部分 var oldText = ""; if (targetLineNum + text.textInfo.lineCount > maxTextLine) { var cutLineNum = targetLineNum + text.textInfo.lineCount - maxTextLine; if (cutLineNum <= text.textInfo.lineCount) { var lastCharIndex = text.textInfo.lineInfo[cutLineNum - 1].lastCharacterIndex; if (lastCharIndex + 1 < text.text.Length) { oldText = text.text.Substring(lastCharIndex + 1); } else { oldText = string.Empty; } } } else { oldText = text.text; } var targetLength = oldText.Length + targetText.Length; // 逐个字符添加 yield return DOTween.To(() => oldText.Length, x => UpdateText(x, targetText, oldText), targetLength, targetText.Length * typeSpeed).WaitForCompletion(); EnumEventSystem.Global.Send(DialogEventEnum.LineShown); yield return new WaitForSeconds(0.5f); EnumEventSystem.Global.Send(DialogEventEnum.LineEnd); _nextStep.Invoke(); } private int EstimateLineNum(string str) { var height = _generator.GetPreferredHeight(str, _generationSettings); var lineHeight = text.fontSize * 1.2f; // 简单估算行高 return Mathf.CeilToInt(height / lineHeight); } private void UpdateText(int currentLength, string nextText, string oldText) { var appendLength = currentLength - oldText.Length; text.text = oldText + nextText[..appendLength]; } public Tween ShowImage(Sprite sprite) { // 先回归隐藏状态 _imageMaterial.SetFloat(DirectionalAlphaFadeFade, 0); // 切换图片 screenImage.sprite = sprite; // 逐渐展示 return DOTween.To(() => _imageMaterial.GetFloat(DirectionalAlphaFadeFade), value => _imageMaterial.SetFloat(DirectionalAlphaFadeFade, value), 10f, 0.5f); } public void ClearImage() { _imageMaterial.SetFloat(DirectionalAlphaFadeFade, 0); screenImage.sprite = null; } public void ClearTextScreen() { title.text = ""; text.SetText(""); } public void CloseTextScreen() { // 先清除文字 ClearTextScreen(); // 旋转隐藏 if (transform.eulerAngles.z >= -80f) { _textScreen.DORotate(new Vector3(0, 0, -90), rotateDuration, RotateMode.FastBeyond360); } } #endregion #region 状态切换 /// /// 插头链接时播放内容 /// /// 需要播放的图片 /// public IEnumerator OnLink(Sprite sprite) { EnumEventSystem.Global.Send(EventEnum.OpenScreen); // 右侧加载图片 var tween = ShowImage(sprite); yield return tween.WaitForCompletion(); // 左侧打开副屏 OpenTextScreen(); yield return new WaitForSeconds(rotateDuration + 0.2f); } /// /// 收回屏幕时触发 /// /// public IEnumerator OnUnlink() { // 隐藏图片 ClearImage(); yield return new WaitForSeconds(0.3f); // 左侧回收屏幕 CloseTextScreen(); yield return new WaitForSeconds(rotateDuration + 0.2f); EnumEventSystem.Global.Send(EventEnum.CloseScreen); } #endregion #region 对话框功能实现 public void ShowLine(string dialogLine, CharacterVo character, Action nextStep, string lineId, bool isAutoSkip = false) { ShowTitle(character.GetActorName()); StartCoroutine(ShowText(dialogLine)); // 每行自动跳过 _nextStep = nextStep; } public void ShowOptions(DialogOption[] dialogueOptions) { Debug.Log("不能在显示屏显示对话"); } public void HideDialog() { // HideDialog应该由其他函数控制 } public bool TrySkipLine(bool isAutoSkip) { // 这里不能跳过对话 return true; } public void NextStep() { // 这里不能手动跳到下一行 } #endregion } /// /// 屏幕接口 /// public interface IScreen { // 打开副屏 void OpenTextScreen(); // 显示标题文字 void ShowTitle(string title); // 显示正文 IEnumerator ShowText(string text); // 显示图片 Tween ShowImage(Sprite sprite); // 清除图片 void ClearImage(); // 清空屏幕 void ClearTextScreen(); // 关闭副屏 void CloseTextScreen(); } }