|
@@ -0,0 +1,280 @@
|
|
|
+using System.Collections;
|
|
|
+using System.Collections.Generic;
|
|
|
+using UnityEngine;
|
|
|
+using FairyGUI;
|
|
|
+using System;
|
|
|
+using System.Threading.Tasks;
|
|
|
+
|
|
|
+namespace GFGGame
|
|
|
+{
|
|
|
+ /// <summary>
|
|
|
+ /// 使用异步函数实现多个字同时渐变
|
|
|
+ /// </summary>
|
|
|
+ public class TypingFadeEffectPro: TypingEffect
|
|
|
+ {
|
|
|
+ protected Color32[] _backupColor32s;
|
|
|
+ protected Color32[] _color32s;
|
|
|
+ protected float charFadeDuration = 0.3f;
|
|
|
+
|
|
|
+
|
|
|
+ private float _currentCharFadeTime;
|
|
|
+
|
|
|
+ public Action typeFinishedAction;
|
|
|
+ public float progressShowNextWord = 0.06f;
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ ///
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="textField"></param>
|
|
|
+ public TypingFadeEffectPro(TextField textField) : base(textField) { }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ ///
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="textField"></param>
|
|
|
+ public TypingFadeEffectPro(GTextField textField) : base(textField) { }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 开始打字效果。可以重复调用重复启动。
|
|
|
+ /// </summary>
|
|
|
+ public new void Start()
|
|
|
+ {
|
|
|
+ _textField.graphics.meshModifier -= OnMeshModified;
|
|
|
+ _textField.Redraw();
|
|
|
+ _textField.graphics.meshModifier += OnMeshModified;
|
|
|
+
|
|
|
+ _stroke = false;
|
|
|
+ _shadow = false;
|
|
|
+ _strokeDrawDirs = 4;
|
|
|
+ _mainLayerStart = 0;
|
|
|
+ _mainLayerVertCount = 0;
|
|
|
+ _printIndex = 0;
|
|
|
+ _vertIndex = 0;
|
|
|
+ _currentCharFadeTime = 0.0f;
|
|
|
+ _started = true;
|
|
|
+
|
|
|
+ int vertCount = _textField.graphics.mesh.vertexCount;
|
|
|
+
|
|
|
+ UpdateBackUp();
|
|
|
+
|
|
|
+ // Clear mesh info
|
|
|
+ if (_vertices == null || _vertices.Length != vertCount)
|
|
|
+ _vertices = new Vector3[vertCount];
|
|
|
+
|
|
|
+ if (_color32s == null || _color32s.Length != vertCount)
|
|
|
+ {
|
|
|
+ _color32s = new Color32[vertCount];
|
|
|
+ }
|
|
|
+
|
|
|
+ Vector3 zero = Vector3.zero;
|
|
|
+ for (int i = 0; i < vertCount; i++)
|
|
|
+ _vertices[i] = zero;
|
|
|
+ _textField.graphics.mesh.vertices = _vertices;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ //隐藏所有混排的对象
|
|
|
+ if (_textField.richTextField != null)
|
|
|
+ {
|
|
|
+ int ec = _textField.richTextField.htmlElementCount;
|
|
|
+ for (int i = 0; i < ec; i++)
|
|
|
+ _textField.richTextField.ShowHtmlObject(i, false);
|
|
|
+ }
|
|
|
+
|
|
|
+ int charCount = _textField.charPositions.Count;
|
|
|
+ for (int i = 0; i < charCount; i++)
|
|
|
+ {
|
|
|
+ TextField.CharPosition cp = _textField.charPositions[i];
|
|
|
+ _mainLayerVertCount += cp.vertCount;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (_mainLayerVertCount < vertCount) //说明有描边或者阴影
|
|
|
+ {
|
|
|
+ int repeat = vertCount / _mainLayerVertCount;
|
|
|
+ _stroke = repeat > 2;
|
|
|
+ _shadow = repeat % 2 == 0;
|
|
|
+ _mainLayerStart = vertCount - vertCount / repeat;
|
|
|
+ _strokeLayerStart = _shadow ? (vertCount / repeat) : 0;
|
|
|
+ _strokeDrawDirs = repeat > 8 ? 8 : 4;
|
|
|
+ }
|
|
|
+
|
|
|
+ Timers.inst.StartCoroutine(UpdateFadeProgress());
|
|
|
+ }
|
|
|
+
|
|
|
+ public void PrintFade(int printIndex, byte alpha, int vertIndex)
|
|
|
+ {
|
|
|
+ TextField.CharPosition cp;
|
|
|
+ List<TextField.CharPosition> charPositions = _textField.charPositions;
|
|
|
+ int listCnt = charPositions.Count;
|
|
|
+
|
|
|
+ cp = charPositions[printIndex];
|
|
|
+ if (cp.vertCount > 0)
|
|
|
+ output(cp.vertCount, alpha, vertIndex);
|
|
|
+ if (cp.imgIndex > 0) //这是一个图片
|
|
|
+ {
|
|
|
+ _textField.richTextField.ShowHtmlObject(cp.imgIndex - 1, true);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ else if (!char.IsWhiteSpace(_textField.parsedText[Mathf.Max(printIndex - 1, 0)]))
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void output(int vertCount, byte alpha, int vertIndex)
|
|
|
+ {
|
|
|
+ int start, end;
|
|
|
+
|
|
|
+ start = _mainLayerStart + vertIndex;
|
|
|
+ end = start + vertCount;
|
|
|
+ //Vector3[] vertices = new Vector3[end - start];
|
|
|
+
|
|
|
+ for (int i = start; i < end; i++)
|
|
|
+ {
|
|
|
+ _vertices[i] = _backupVerts[i];
|
|
|
+ _color32s[i] = _backupColor32s[i];
|
|
|
+ _color32s[i].a = alpha;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (_stroke)
|
|
|
+ {
|
|
|
+ start = _strokeLayerStart + vertIndex;
|
|
|
+ end = start + vertCount;
|
|
|
+ for (int i = start; i < end; i++)
|
|
|
+ {
|
|
|
+ for (int j = 0; j < _strokeDrawDirs; j++)
|
|
|
+ {
|
|
|
+ int k = i + _mainLayerVertCount * j;
|
|
|
+ _vertices[k] = _backupVerts[k];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (_shadow)
|
|
|
+ {
|
|
|
+ start = vertIndex;
|
|
|
+ end = start + vertCount;
|
|
|
+ for (int i = start; i < end; i++)
|
|
|
+ {
|
|
|
+ _vertices[i] = _backupVerts[i];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ _textField.graphics.mesh.vertices = _vertices;
|
|
|
+ _textField.graphics.mesh.colors32 = _color32s;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public new void Cancel()
|
|
|
+ {
|
|
|
+ if (!_started)
|
|
|
+ return;
|
|
|
+
|
|
|
+ _started = false;
|
|
|
+ _textField.graphics.meshModifier -= OnMeshModified;
|
|
|
+ _textField.graphics.SetMeshDirty();
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 当打字过程中,文本可能会由于字体纹理更改而发生字体重建,要处理这种情况。
|
|
|
+ /// 图片对象不需要处理,因为HtmlElement.status里设定的隐藏标志不会因为Mesh更新而被冲掉。
|
|
|
+ /// </summary>
|
|
|
+ void OnMeshModified()
|
|
|
+ {
|
|
|
+ if (_textField.graphics.mesh.vertexCount != _backupVerts.Length) //可能文字都改了
|
|
|
+ {
|
|
|
+ Cancel();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ UpdateBackUp();
|
|
|
+
|
|
|
+ int vertCount = _vertices.Length;
|
|
|
+ Vector3 zero = Vector3.zero;
|
|
|
+ for (int i = 0; i < vertCount; i++)
|
|
|
+ {
|
|
|
+ if (_vertices[i] != zero)
|
|
|
+ _vertices[i] = _backupVerts[i];
|
|
|
+ }
|
|
|
+
|
|
|
+ _textField.graphics.mesh.vertices = _vertices;
|
|
|
+ }
|
|
|
+
|
|
|
+ IEnumerator UpdateFadeProgress()
|
|
|
+ {
|
|
|
+ List<TextField.CharPosition> charPositions = _textField.charPositions;
|
|
|
+ int listCnt = charPositions.Count;
|
|
|
+ float timer = 0;
|
|
|
+
|
|
|
+ //for(int i = 0; i < listCnt - 1; i++)
|
|
|
+ //{
|
|
|
+ // PrintFade(i, 0, charPositions[i].vertCount);
|
|
|
+ // yield return new WaitForEndOfFrame();
|
|
|
+ //}
|
|
|
+
|
|
|
+ while (true)
|
|
|
+ {
|
|
|
+ if (!_started)
|
|
|
+ break;
|
|
|
+
|
|
|
+ if(timer>= progressShowNextWord)
|
|
|
+ {
|
|
|
+ timer = 0;
|
|
|
+ if (_printIndex >= listCnt - 1)
|
|
|
+ {
|
|
|
+ Cancel();
|
|
|
+ typeFinishedAction.Invoke();
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ UpdateFadeProgressSingle(_printIndex, _vertIndex);
|
|
|
+ ++_printIndex;
|
|
|
+ _vertIndex += charPositions[_printIndex].vertCount;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ timer += Time.deltaTime;
|
|
|
+ yield return new WaitForEndOfFrame();
|
|
|
+ //yield return new WaitForSeconds(progressShowNextWord);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ async Task UpdateFadeProgressSingle(int printIndex, int vertIndex)
|
|
|
+ {
|
|
|
+ float _currentCharFadeTime = 0;
|
|
|
+ while (true)
|
|
|
+ {
|
|
|
+ if (!_started)
|
|
|
+ break;
|
|
|
+
|
|
|
+ _currentCharFadeTime += 0.016f;
|
|
|
+ float progress = _currentCharFadeTime / charFadeDuration;
|
|
|
+ if (progress >= 1)
|
|
|
+ {
|
|
|
+ PrintFade(printIndex, 255, vertIndex);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ byte alpha = (byte)(progress * 255);
|
|
|
+ PrintFade(printIndex, alpha, vertIndex);
|
|
|
+ }
|
|
|
+ await Task.Delay(16);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Back up origin text info
|
|
|
+ protected void UpdateBackUp()
|
|
|
+ {
|
|
|
+ _backupVerts = _textField.graphics.mesh.vertices;
|
|
|
+ _backupColor32s = _textField.graphics.mesh.colors32;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void SetSpeed(float speed)
|
|
|
+ {
|
|
|
+ charFadeDuration = speed;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|