using System.Collections; using System.Collections.Generic; using UnityEngine; using FairyGUI; using System; using System.Threading.Tasks; using System.Threading; namespace GFGGame { /// /// 使用异步函数实现多个字同时渐变 /// public class TypingFadeEffectPro: TypingEffect { protected Color32[] _backupColor32s; protected Color32[] _color32s; public Action typeFinishedAction; // 出现下一个字符的间隔 protected float showNextWordInternal = 0.06f; // 字符渐变时间 protected float charFadeDuration = 0.15f; // 异步函数的取消控制 private CancellationTokenSource _cancellationTokenSource; /// /// /// /// public TypingFadeEffectPro(TextField textField) : base(textField) { } /// /// /// /// public TypingFadeEffectPro(GTextField textField) : base(textField) { } /// /// 开始打字效果。可以重复调用重复启动。 /// 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; _started = true; _cancellationTokenSource = new CancellationTokenSource(); 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 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; StopMyAsyncFunction(); _started = false; _textField.graphics.meshModifier -= OnMeshModified; _textField.graphics.SetMeshDirty(); } /// /// 当打字过程中,文本可能会由于字体纹理更改而发生字体重建,要处理这种情况。 /// 图片对象不需要处理,因为HtmlElement.status里设定的隐藏标志不会因为Mesh更新而被冲掉。 /// 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 charPositions = _textField.charPositions; int listCnt = charPositions.Count; float timer = 0; //for(int i=0;i<= listCnt - 1; i++) //{ // PrintFade(i, 0, _vertIndex); // _vertIndex += charPositions[_printIndex].vertCount; //} //_vertIndex = 0; while (true) { if (!_started) break; if(timer>= showNextWordInternal) { timer = 0; if (_printIndex >= listCnt - 1) { Cancel(); typeFinishedAction.Invoke(); break; } else { UpdateFadeProgressSingle(_printIndex, _vertIndex, _cancellationTokenSource.Token); ++_printIndex; if(_printIndex < listCnt - 1 && _printIndex < charPositions.Count) { _vertIndex += charPositions[_printIndex].vertCount; } } } timer += Time.deltaTime; yield return new WaitForEndOfFrame(); } } async Task UpdateFadeProgressSingle(int printIndex, int vertIndex, CancellationToken cancellationToken) { 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, cancellationToken); } } // 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; showNextWordInternal /= speed; charFadeDuration = showNextWordInternal + 0.05f; } // 取消异步函数 public void StopMyAsyncFunction() { if (_cancellationTokenSource != null) { _cancellationTokenSource.Cancel(); _cancellationTokenSource.Dispose(); _cancellationTokenSource = null; } } } }