using System.Collections.Generic; using Spine.Unity; using UnityEngine; /// /// Spine批量更新管理器(参考UWA优化方案) /// 禁用SkeletonGraphic的Update/LateUpdate自动回调, /// 由Manager统一批量调用,减少大量Spine对象的跨语言调用开销。 /// 支持隔帧更新Mesh,进一步降低CPU开销。 /// public class SpineUpdateManager : MonoBehaviour { private static SpineUpdateManager instance; public static SpineUpdateManager Instance { get { if (instance == null) { var go = new GameObject("[SpineUpdateManager]"); DontDestroyOnLoad(go); instance = go.AddComponent(); } return instance; } } private readonly List managedSpines = new List(); private readonly HashSet managedSet = new HashSet(); private int frameCount; /// /// 注册一个SkeletonGraphic到批量更新管理器。 /// 注册后会禁用其自身的Update/LateUpdate(通过设置freeze=true), /// 改由Manager统一驱动。 /// public void Register(SkeletonGraphic sg) { if (sg == null || managedSet.Contains(sg)) return; managedSpines.Add(sg); managedSet.Add(sg); sg.freeze = true; // 禁用SkeletonGraphic自身的Update/LateUpdate } /// /// 从管理器中移除一个SkeletonGraphic,恢复其自身更新。 /// public void Unregister(SkeletonGraphic sg) { if (sg == null || !managedSet.Contains(sg)) return; managedSpines.Remove(sg); managedSet.Remove(sg); sg.freeze = false; // 恢复自身更新 } void Update() { frameCount++; float dt = Time.deltaTime; for (int i = managedSpines.Count - 1; i >= 0; i--) { var sg = managedSpines[i]; if (sg == null) { managedSpines.RemoveAt(i); managedSet.Remove(sg); continue; } if (!sg.isActiveAndEnabled) continue; sg.Update(dt); } } void LateUpdate() { bool skipMesh = managedSpines.Count > 8 && (frameCount & 1) == 0; for (int i = managedSpines.Count - 1; i >= 0; i--) { var sg = managedSpines[i]; if (sg == null) { managedSpines.RemoveAt(i); managedSet.Remove(sg); continue; } if (!sg.isActiveAndEnabled) continue; if (skipMesh) continue; sg.UpdateMesh(); } } void OnDestroy() { // 恢复所有被管理的Spine自身更新 foreach (var sg in managedSpines) { if (sg != null) sg.freeze = false; } managedSpines.Clear(); managedSet.Clear(); instance = null; } }