TypingFadeEffectPro.cs 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using FairyGUI;
  5. using System;
  6. using System.Threading.Tasks;
  7. using System.Threading;
  8. namespace GFGGame
  9. {
  10. /// <summary>
  11. /// 使用异步函数实现多个字同时渐变
  12. /// </summary>
  13. public class TypingFadeEffectPro: TypingEffect
  14. {
  15. protected Color32[] _backupColor32s;
  16. protected Color32[] _color32s;
  17. public Action typeFinishedAction;
  18. // 出现下一个字符的间隔
  19. protected float showNextWordInternal = 0.06f;
  20. // 字符渐变时间
  21. protected float charFadeDuration = 0.15f;
  22. // 异步函数的取消控制
  23. private CancellationTokenSource _cancellationTokenSource;
  24. /// <summary>
  25. ///
  26. /// </summary>
  27. /// <param name="textField"></param>
  28. public TypingFadeEffectPro(TextField textField) : base(textField) { }
  29. /// <summary>
  30. ///
  31. /// </summary>
  32. /// <param name="textField"></param>
  33. public TypingFadeEffectPro(GTextField textField) : base(textField) { }
  34. /// <summary>
  35. /// 开始打字效果。可以重复调用重复启动。
  36. /// </summary>
  37. public new void Start()
  38. {
  39. _textField.graphics.meshModifier -= OnMeshModified;
  40. _textField.Redraw();
  41. _textField.graphics.meshModifier += OnMeshModified;
  42. _stroke = false;
  43. _shadow = false;
  44. _strokeDrawDirs = 4;
  45. _mainLayerStart = 0;
  46. _mainLayerVertCount = 0;
  47. _printIndex = 0;
  48. _vertIndex = 0;
  49. _started = true;
  50. _cancellationTokenSource = new CancellationTokenSource();
  51. int vertCount = _textField.graphics.mesh.vertexCount;
  52. UpdateBackUp();
  53. // Clear mesh info
  54. if (_vertices == null || _vertices.Length != vertCount)
  55. _vertices = new Vector3[vertCount];
  56. if (_color32s == null || _color32s.Length != vertCount)
  57. {
  58. _color32s = new Color32[vertCount];
  59. }
  60. Vector3 zero = Vector3.zero;
  61. for (int i = 0; i < vertCount; i++)
  62. _vertices[i] = zero;
  63. _textField.graphics.mesh.vertices = _vertices;
  64. //隐藏所有混排的对象
  65. if (_textField.richTextField != null)
  66. {
  67. int ec = _textField.richTextField.htmlElementCount;
  68. for (int i = 0; i < ec; i++)
  69. _textField.richTextField.ShowHtmlObject(i, false);
  70. }
  71. int charCount = _textField.charPositions.Count;
  72. for (int i = 0; i < charCount; i++)
  73. {
  74. TextField.CharPosition cp = _textField.charPositions[i];
  75. _mainLayerVertCount += cp.vertCount;
  76. }
  77. if (_mainLayerVertCount < vertCount) //说明有描边或者阴影
  78. {
  79. int repeat = vertCount / _mainLayerVertCount;
  80. _stroke = repeat > 2;
  81. _shadow = repeat % 2 == 0;
  82. _mainLayerStart = vertCount - vertCount / repeat;
  83. _strokeLayerStart = _shadow ? (vertCount / repeat) : 0;
  84. _strokeDrawDirs = repeat > 8 ? 8 : 4;
  85. }
  86. Timers.inst.StartCoroutine(UpdateFadeProgress());
  87. }
  88. public void PrintFade(int printIndex, byte alpha, int vertIndex)
  89. {
  90. TextField.CharPosition cp;
  91. List<TextField.CharPosition> charPositions = _textField.charPositions;
  92. int listCnt = charPositions.Count;
  93. cp = charPositions[printIndex];
  94. if (cp.vertCount > 0)
  95. output(cp.vertCount, alpha, vertIndex);
  96. if (cp.imgIndex > 0) //这是一个图片
  97. {
  98. _textField.richTextField.ShowHtmlObject(cp.imgIndex - 1, true);
  99. return;
  100. }
  101. else if (!char.IsWhiteSpace(_textField.parsedText[Mathf.Max(printIndex - 1, 0)]))
  102. return;
  103. }
  104. private void output(int vertCount, byte alpha, int vertIndex)
  105. {
  106. int start, end;
  107. start = _mainLayerStart + vertIndex;
  108. end = start + vertCount;
  109. //Vector3[] vertices = new Vector3[end - start];
  110. for (int i = start; i < end; i++)
  111. {
  112. _vertices[i] = _backupVerts[i];
  113. _color32s[i] = _backupColor32s[i];
  114. _color32s[i].a = alpha;
  115. }
  116. if (_stroke)
  117. {
  118. start = _strokeLayerStart + vertIndex;
  119. end = start + vertCount;
  120. for (int i = start; i < end; i++)
  121. {
  122. for (int j = 0; j < _strokeDrawDirs; j++)
  123. {
  124. int k = i + _mainLayerVertCount * j;
  125. _vertices[k] = _backupVerts[k];
  126. }
  127. }
  128. }
  129. if (_shadow)
  130. {
  131. start = vertIndex;
  132. end = start + vertCount;
  133. for (int i = start; i < end; i++)
  134. {
  135. _vertices[i] = _backupVerts[i];
  136. }
  137. }
  138. _textField.graphics.mesh.vertices = _vertices;
  139. _textField.graphics.mesh.colors32 = _color32s;
  140. }
  141. public new void Cancel()
  142. {
  143. if (!_started)
  144. return;
  145. StopMyAsyncFunction();
  146. _started = false;
  147. _textField.graphics.meshModifier -= OnMeshModified;
  148. _textField.graphics.SetMeshDirty();
  149. }
  150. /// <summary>
  151. /// 当打字过程中,文本可能会由于字体纹理更改而发生字体重建,要处理这种情况。
  152. /// 图片对象不需要处理,因为HtmlElement.status里设定的隐藏标志不会因为Mesh更新而被冲掉。
  153. /// </summary>
  154. void OnMeshModified()
  155. {
  156. if (_textField.graphics.mesh.vertexCount != _backupVerts.Length) //可能文字都改了
  157. {
  158. Cancel();
  159. return;
  160. }
  161. UpdateBackUp();
  162. int vertCount = _vertices.Length;
  163. Vector3 zero = Vector3.zero;
  164. for (int i = 0; i < vertCount; i++)
  165. {
  166. if (_vertices[i] != zero)
  167. _vertices[i] = _backupVerts[i];
  168. }
  169. _textField.graphics.mesh.vertices = _vertices;
  170. }
  171. IEnumerator UpdateFadeProgress()
  172. {
  173. List<TextField.CharPosition> charPositions = _textField.charPositions;
  174. int listCnt = charPositions.Count;
  175. float timer = 0;
  176. //for(int i=0;i<= listCnt - 1; i++)
  177. //{
  178. // PrintFade(i, 0, _vertIndex);
  179. // _vertIndex += charPositions[_printIndex].vertCount;
  180. //}
  181. //_vertIndex = 0;
  182. while (true)
  183. {
  184. if (!_started)
  185. break;
  186. if(timer>= showNextWordInternal)
  187. {
  188. timer = 0;
  189. if (_printIndex >= listCnt - 1)
  190. {
  191. Cancel();
  192. typeFinishedAction.Invoke();
  193. break;
  194. }
  195. else
  196. {
  197. UpdateFadeProgressSingle(_printIndex, _vertIndex, _cancellationTokenSource.Token);
  198. ++_printIndex;
  199. if(_printIndex < listCnt - 1 && _printIndex < charPositions.Count)
  200. {
  201. _vertIndex += charPositions[_printIndex].vertCount;
  202. }
  203. }
  204. }
  205. timer += Time.deltaTime;
  206. yield return new WaitForEndOfFrame();
  207. }
  208. }
  209. async Task UpdateFadeProgressSingle(int printIndex, int vertIndex, CancellationToken cancellationToken)
  210. {
  211. float _currentCharFadeTime = 0;
  212. while (true)
  213. {
  214. if (!_started)
  215. break;
  216. _currentCharFadeTime += 0.016f;
  217. float progress = _currentCharFadeTime / charFadeDuration;
  218. if (progress >= 1)
  219. {
  220. PrintFade(printIndex, 255, vertIndex);
  221. break;
  222. }
  223. else
  224. {
  225. byte alpha = (byte)(progress * 255);
  226. PrintFade(printIndex, alpha, vertIndex);
  227. }
  228. await Task.Delay(16, cancellationToken);
  229. }
  230. }
  231. // Back up origin text info
  232. protected void UpdateBackUp()
  233. {
  234. _backupVerts = _textField.graphics.mesh.vertices;
  235. _backupColor32s = _textField.graphics.mesh.colors32;
  236. }
  237. public void SetSpeed(float speed)
  238. {
  239. //charFadeDuration /= speed;
  240. showNextWordInternal /= speed;
  241. charFadeDuration = showNextWordInternal + 0.05f;
  242. }
  243. // 取消异步函数
  244. public void StopMyAsyncFunction()
  245. {
  246. if (_cancellationTokenSource != null)
  247. {
  248. _cancellationTokenSource.Cancel();
  249. _cancellationTokenSource.Dispose();
  250. _cancellationTokenSource = null;
  251. }
  252. }
  253. }
  254. }