using System.Collections.Generic;
|
using Spine.Unity;
|
using UnityEngine;
|
|
/// <summary>
|
/// Spine批量更新管理器(参考UWA优化方案)
|
/// 禁用SkeletonGraphic的Update/LateUpdate自动回调,
|
/// 由Manager统一批量调用,减少大量Spine对象的跨语言调用开销。
|
/// 支持隔帧更新Mesh,进一步降低CPU开销。
|
/// </summary>
|
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<SpineUpdateManager>();
|
}
|
return instance;
|
}
|
}
|
|
private readonly List<SkeletonGraphic> managedSpines = new List<SkeletonGraphic>();
|
private readonly HashSet<SkeletonGraphic> managedSet = new HashSet<SkeletonGraphic>();
|
private int frameCount;
|
|
/// <summary>
|
/// 注册一个SkeletonGraphic到批量更新管理器。
|
/// 注册后会禁用其自身的Update/LateUpdate(通过设置freeze=true),
|
/// 改由Manager统一驱动。
|
/// </summary>
|
public void Register(SkeletonGraphic sg)
|
{
|
if (sg == null || managedSet.Contains(sg)) return;
|
managedSpines.Add(sg);
|
managedSet.Add(sg);
|
sg.freeze = true; // 禁用SkeletonGraphic自身的Update/LateUpdate
|
}
|
|
/// <summary>
|
/// 从管理器中移除一个SkeletonGraphic,恢复其自身更新。
|
/// </summary>
|
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;
|
}
|
}
|