feat: 帧动画系统Timeline兼容

This commit is contained in:
2026-07-22 02:32:04 +08:00
parent 9b2caf64c9
commit c6c76666ef
48 changed files with 2947 additions and 31 deletions
@@ -10,6 +10,36 @@ using UnityEngine;
namespace AibisDream.FrameAnimation.Editor
{
internal readonly struct FrameAnimationSpriteSourceContext
{
public string SourceId { get; }
public Texture2D Texture { get; }
public TextAsset AsepriteJson { get; }
public Vector2 Pivot { get; }
public bool ManageSpriteSlicing { get; }
public FrameAnimationSpriteSourceContext(
string sourceId,
Texture2D texture,
TextAsset asepriteJson,
Vector2 pivot,
bool manageSpriteSlicing)
{
SourceId = sourceId ?? string.Empty;
Texture = texture;
AsepriteJson = asepriteJson;
Pivot = pivot;
ManageSpriteSlicing = manageSpriteSlicing;
}
public static FrameAnimationSpriteSourceContext From(FrameAnimationImportSource source)
{
return new FrameAnimationSpriteSourceContext(
source?.InternalId, source?.Texture, source?.AsepriteJson,
source?.Pivot ?? new Vector2(0.5f, 0.5f), source?.ManageSpriteSlicing == true);
}
}
internal sealed class FrameAnimationSpritePlan
{
public string TexturePath { get; }
@@ -91,6 +121,15 @@ namespace AibisDream.FrameAnimation.Editor
FrameAnimationImportSource source,
AsepriteSourceDocument document,
FrameAnimationImportSourcePreview preview)
{
return BuildPlan(FrameAnimationSpriteSourceContext.From(source), document, preview);
}
public static FrameAnimationSpritePlan BuildPlan(
FrameAnimationSpriteSourceContext source,
AsepriteSourceDocument document,
IFrameAnimationImportPreviewSink preview,
IReadOnlyCollection<int> includedSourceIndices = null)
{
var texturePath = AssetDatabase.GetAssetPath(source.Texture);
var importer = AssetImporter.GetAtPath(texturePath) as TextureImporter;
@@ -105,8 +144,8 @@ namespace AibisDream.FrameAnimation.Editor
? Array.Empty<SpriteRect>()
: ReadSpriteRects(importer);
return source.ManageSpriteSlicing
? BuildWritablePlan(source, document, preview, texturePath, existingRects)
: BuildReadOnlyPlan(source, document, preview, texturePath, existingRects);
? BuildWritablePlan(source, document, preview, texturePath, existingRects, includedSourceIndices)
: BuildReadOnlyPlan(source, document, preview, texturePath, existingRects, includedSourceIndices);
}
public static Rect ToUnityRect(RectInt asepriteRect, int textureHeight)
@@ -175,7 +214,14 @@ namespace AibisDream.FrameAnimation.Editor
FrameAnimationImportSource source,
IReadOnlyList<SpriteRect> spriteRects = null)
{
if (source == null || source.Texture == null || source.AsepriteJson == null)
return ComputeSourceHash(FrameAnimationSpriteSourceContext.From(source), spriteRects);
}
public static string ComputeSourceHash(
FrameAnimationSpriteSourceContext source,
IReadOnlyList<SpriteRect> spriteRects = null)
{
if (source.Texture == null || source.AsepriteJson == null)
{
return string.Empty;
}
@@ -214,17 +260,18 @@ namespace AibisDream.FrameAnimation.Editor
}
private static FrameAnimationSpritePlan BuildWritablePlan(
FrameAnimationImportSource source,
FrameAnimationSpriteSourceContext source,
AsepriteSourceDocument document,
FrameAnimationImportSourcePreview preview,
IFrameAnimationImportPreviewSink preview,
string texturePath,
IReadOnlyList<SpriteRect> existingRects)
IReadOnlyList<SpriteRect> existingRects,
IReadOnlyCollection<int> includedSourceIndices)
{
var planned = CloneRects(existingRects).ToList();
var originalRects = planned.ToArray();
var assigned = new HashSet<SpriteRect>();
var spriteNamesBySourceIndex = new Dictionary<int, string>();
foreach (var slot in document.SpriteSlots)
foreach (var slot in EnumerateSlots(document, includedSourceIndices))
{
var unityRect = ToUnityRect(slot.Rect, source.Texture.height);
SpriteRect matched = null;
@@ -331,15 +378,16 @@ namespace AibisDream.FrameAnimation.Editor
}
private static FrameAnimationSpritePlan BuildReadOnlyPlan(
FrameAnimationImportSource source,
FrameAnimationSpriteSourceContext source,
AsepriteSourceDocument document,
FrameAnimationImportSourcePreview preview,
IFrameAnimationImportPreviewSink preview,
string texturePath,
IReadOnlyList<SpriteRect> existingRects)
IReadOnlyList<SpriteRect> existingRects,
IReadOnlyCollection<int> includedSourceIndices)
{
var sprites = AssetDatabase.LoadAllAssetsAtPath(texturePath).OfType<Sprite>().ToArray();
var matches = new Dictionary<int, Sprite>();
foreach (var slot in document.SpriteSlots)
foreach (var slot in EnumerateSlots(document, includedSourceIndices))
{
var unityRect = ToUnityRect(slot.Rect, source.Texture.height);
var rectMatches = sprites.Where(sprite => RectEquals(sprite.rect, unityRect)).ToArray();
@@ -382,6 +430,32 @@ namespace AibisDream.FrameAnimation.Editor
}
}
private static IEnumerable<AsepriteSpriteSlot> EnumerateSlots(
AsepriteSourceDocument document,
IReadOnlyCollection<int> includedSourceIndices)
{
if (includedSourceIndices == null)
{
return document.SpriteSlots;
}
var included = new HashSet<int>(includedSourceIndices);
return document.SpriteSlots.Select(slot =>
{
var indices = new List<int>();
var names = new List<string>();
for (var index = 0; index < slot.SourceIndices.Count; index++)
{
if (!included.Contains(slot.SourceIndices[index])) continue;
indices.Add(slot.SourceIndices[index]);
names.Add(slot.FrameNames[index]);
}
return indices.Count == 0
? null
: new AsepriteSpriteSlot(slot.Rect, names[0], indices, names);
}).Where(slot => slot != null);
}
private static string BuildSlotSummary(string prefix, AsepriteSpriteSlot slot)
{
return slot.SourceIndices.Count > 1
@@ -440,15 +514,15 @@ namespace AibisDream.FrameAnimation.Editor
}
private static FrameAnimationImportIssue Error(
FrameAnimationImportSource source,
FrameAnimationSpriteSourceContext source,
FrameAnimationImportIssueCode code,
string message)
{
return new FrameAnimationImportIssue(
FrameAnimationValidationSeverity.Error,
code,
source?.InternalId,
source?.InternalId,
source.SourceId,
source.SourceId,
message);
}
}