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;
}
}