This commit is contained in:
陈思海 2025-03-14 16:03:00 +08:00
parent dadd04238a
commit 392768b9de
5 changed files with 251 additions and 2 deletions

View File

@ -6,7 +6,8 @@
"GUID:760f1778adc613f49a4394fb41ff0bbc", "GUID:760f1778adc613f49a4394fb41ff0bbc",
"GUID:75b6f2078d190f14dbda4a5b747d709c", "GUID:75b6f2078d190f14dbda4a5b747d709c",
"GUID:a19b414bea3b97240a91aeab9a8eab36", "GUID:a19b414bea3b97240a91aeab9a8eab36",
"GUID:83a193b118cfbef48a344187e07f53bb" "GUID:83a193b118cfbef48a344187e07f53bb",
"GUID:acfef7cabed3b0a42b25edb1cd4fa259"
], ],
"includePlatforms": [ "includePlatforms": [
"Editor" "Editor"

View File

@ -7,7 +7,9 @@
"GUID:75b6f2078d190f14dbda4a5b747d709c", "GUID:75b6f2078d190f14dbda4a5b747d709c",
"GUID:a19b414bea3b97240a91aeab9a8eab36", "GUID:a19b414bea3b97240a91aeab9a8eab36",
"GUID:198eb6af143bbc4488e2779d96697e06", "GUID:198eb6af143bbc4488e2779d96697e06",
"GUID:80ecb87cae9c44d19824e70ea7229748" "GUID:80ecb87cae9c44d19824e70ea7229748",
"GUID:f51ebe6a0ceec4240a699833d6309b23",
"GUID:33661e06c33d31b4c9223810bf503247"
], ],
"includePlatforms": [], "includePlatforms": [],
"excludePlatforms": [], "excludePlatforms": [],

8
Runtime/Extension.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: dc3fb1c1caf6fbd40a900ca46f204e07
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,236 @@
// using UnityEngine;
//
// using System;
// using System.Collections.Generic;
// using Cysharp.Threading.Tasks;
// using Cysharp.Threading.Tasks.Triggers;
// using TMPro;
// using UnityEngine;
// using UnityEngine.Pool;
// using System.Threading;
// using System.Runtime.CompilerServices;
// using Cysharp.Text;
//
// namespace text
// {
// public static class ZeroGCTypewriterPro
// {
// #region 核心结构体
//
// private struct TypewriterHandle : IEquatable<TypewriterHandle>
// {
// public int InstanceID;
// public int Version;
//
// public bool Equals(TypewriterHandle other) =>
// InstanceID == other.InstanceID && Version == other.Version;
// }
//
// private struct TypewriterJob
// {
// public TypewriterHandle Handle;
// public TMP_Text Target;
// public string Content;
// public float Speed;
// public int LoopCount;
// public Action<int> OnUpdate;
// public Action OnComplete;
// public CancellationToken ExternalToken;
// }
//
// #endregion
//
// #region 状态管理
//
// private static readonly Dictionary<int, ActiveJob> activeJobs =
// new Dictionary<int, ActiveJob>(32);
//
// private struct ActiveJob
// {
// public int Version;
// public CancellationTokenSource Cts;
// }
//
// private static readonly ObjectPool<CancellationTokenSource> ctsPool =
// ObjectPool<CancellationTokenSource>(
// createFunc: () => new CancellationTokenSource(),
// actionOnRelease: cts => cts.Cancel(),
// collectionCheck: false
// );
//
// #endregion
//
// #region 公开接口
//
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// public static void Play(
// this TMP_Text text,
// string content,
// float charsPerSecond = 30,
// int loopCount = 0,
// Action<int> onUpdate = null,
// Action onComplete = null,
// CancellationToken externalToken = default)
// {
// var instanceID = text.GetInstanceID();
//
// // 停止当前任务(如果有)
// if (activeJobs.TryGetValue(instanceID, out var existingJob))
// {
// ctsPool.Release(existingJob.Cts);
// activeJobs.Remove(instanceID);
// }
//
// // 从对象池获取CTS
// var cts = ctsPool.Get();
// var linkedToken = CombineTokens(
// text.GetCancellationTokenOnDestroy(),
// externalToken,
// cts.Token
// );
//
// // 创建新任务
// var newVersion = activeJobs.TryGetValue(instanceID, out var job) ? job.Version + 1 : 1;
//
// activeJobs[instanceID] = new ActiveJob
// {
// Version = newVersion,
// Cts = cts
// };
//
// RunJob(new TypewriterJob
// {
// Handle = new TypewriterHandle
// {
// InstanceID = instanceID,
// Version = newVersion
// },
// Target = text,
// Content = content,
// Speed = Mathf.Max(0.01f, charsPerSecond),
// LoopCount = loopCount,
// OnUpdate = onUpdate,
// OnComplete = onComplete,
// ExternalToken = linkedToken
// }).Forget();
// }
//
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// public static void Stop(this TMP_Text text)
// {
// var instanceID = text.GetInstanceID();
// if (activeJobs.TryGetValue(instanceID, out var job))
// {
// ctsPool.Release(job.Cts);
// activeJobs.Remove(instanceID);
// ResetTextState(text);
// }
// }
//
// #endregion
//
// #region 核心逻辑
//
// private static async UniTaskVoid RunJob(TypewriterJob job)
// {
// try
// {
// var target = job.Target;
// using (var sb = ZString.CreateStringBuilder())
// {
// sb.Append(job.Content);
// target.text = sb.ToString();
// target.ForceMeshUpdate();
//
// int currentLoop = 0;
// var chars = sb.AsSpan();
// var interval = 1f / job.Speed;
// var timer = 0f;
//
// while (IsLoopValid(currentLoop, job.LoopCount))
// {
// target.maxVisibleCharacters = 0;
//
// for (int i = 0; i < chars.Length; i++)
// {
// // 版本校验
// if (!IsHandleValid(job.Handle)) return;
//
// // 基于时间的更新
// timer += Time.deltaTime;
// var required = (int)(timer * job.Speed);
//
// if (required > i)
// {
// target.maxVisibleCharacters = required;
// job.OnUpdate?.Invoke(required);
// }
//
// await UniTask.Yield(PlayerLoopTiming.Update, job.ExternalToken);
// }
//
// currentLoop++;
// timer = 0f;
// job.OnComplete?.Invoke();
// }
// }
// }
// finally
// {
// if (IsHandleValid(job.Handle))
// {
// activeJobs.Remove(job.Handle.InstanceID);
// ResetTextState(job.Target);
// }
// }
// }
//
// #endregion
//
// #region 工具方法
//
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// private static bool IsHandleValid(TypewriterHandle handle)
// {
// return activeJobs.TryGetValue(handle.InstanceID, out var job) &&
// job.Version == handle.Version;
// }
//
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// private static bool IsLoopValid(int current, int max) =>
// max < 0 || current <= max;
//
// private static CancellationToken CombineTokens(
// CancellationToken token1,
// CancellationToken token2,
// CancellationToken token3)
// {
// if (token1.CanBeCanceled && token2.CanBeCanceled && token3.CanBeCanceled)
// return CancellationTokenSource.CreateLinkedTokenSource(
// token1, token2, token3).Token;
//
// if (token1.CanBeCanceled && token2.CanBeCanceled)
// return CancellationTokenSource.CreateLinkedTokenSource(
// token1, token2).Token;
//
// return token1.CanBeCanceled ? token1 : token2;
// }
//
// private static void ResetTextState(TMP_Text text)
// {
// if (text != null)
// {
// text.maxVisibleCharacters = int.MaxValue;
// text.SetVerticesDirty();
// }
// }
//
// private static CancellationToken GetCancellationTokenOnDestroy(this TMP_Text text)
// {
// return text.gameObject.GetCancellationTokenOnDestroy();
// }
//
// #endregion
// }
//
// }

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: dd18a7ac84917984dbbf48f71872add9