681 lines
27 KiB
C#
681 lines
27 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using UnityEditor;
|
||
using UnityEditor.U2D.Sprites;
|
||
using UnityEngine;
|
||
|
||
namespace AibisDream.SystemEditor
|
||
{
|
||
public static class AnimationClipGeneratorCore
|
||
{
|
||
// 检查SpriteMode
|
||
public static SpriteImportMode CheckSpriteMode(string texturePath)
|
||
{
|
||
TextureImporter textureImporter = AssetImporter.GetAtPath(texturePath) as TextureImporter;
|
||
if (textureImporter == null)
|
||
{
|
||
throw new Exception($"无法加载纹理导入器: {texturePath}");
|
||
}
|
||
return textureImporter.spriteImportMode;
|
||
}
|
||
|
||
// 解析Aseprite JSON
|
||
public static ProcessedAnimationData ParseAsepriteJson(string jsonPath, string texturePath)
|
||
{
|
||
string jsonContent = File.ReadAllText(jsonPath);
|
||
|
||
// Unity的JsonUtility不支持Dictionary,需要手动解析frames对象
|
||
// 使用SimpleJSON或手动解析
|
||
ProcessedAnimationData result = ParseAsepriteJsonManual(jsonContent);
|
||
|
||
if (result.frames == null || result.frames.Count == 0)
|
||
{
|
||
throw new Exception("无效的Aseprite JSON格式:无法解析frames");
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
private static ProcessedAnimationData ParseAsepriteJsonManual(string jsonContent)
|
||
{
|
||
List<FrameData> frames = new List<FrameData>();
|
||
List<ProcessedAnimationClip> animations = new List<ProcessedAnimationClip>();
|
||
|
||
try
|
||
{
|
||
// 解析meta部分
|
||
int metaStart = jsonContent.IndexOf("\"meta\":");
|
||
if (metaStart == -1)
|
||
{
|
||
throw new Exception("找不到meta部分");
|
||
}
|
||
|
||
// 找到meta对象的结束位置
|
||
int metaBraceStart = jsonContent.IndexOf('{', metaStart);
|
||
int metaBraceEnd = FindMatchingBrace(jsonContent, metaBraceStart);
|
||
string metaJson = jsonContent.Substring(metaBraceStart, metaBraceEnd - metaBraceStart + 1);
|
||
|
||
// 移除可能的尾随逗号
|
||
metaJson = metaJson.TrimEnd(',', ' ', '\n', '\r');
|
||
|
||
AsepriteMeta meta = JsonUtility.FromJson<AsepriteMeta>(metaJson);
|
||
|
||
// 解析frameTags
|
||
if (meta.frameTags != null)
|
||
{
|
||
foreach (var tag in meta.frameTags)
|
||
{
|
||
List<int> frameIndices = new List<int>();
|
||
int start = tag.from;
|
||
int end = tag.to;
|
||
|
||
if (tag.direction == "forward" || tag.direction == "pingpong" || string.IsNullOrEmpty(tag.direction))
|
||
{
|
||
for (int i = start; i <= end; i++)
|
||
{
|
||
frameIndices.Add(i);
|
||
}
|
||
}
|
||
else if (tag.direction == "reverse")
|
||
{
|
||
for (int i = end; i >= start; i--)
|
||
{
|
||
frameIndices.Add(i);
|
||
}
|
||
}
|
||
|
||
animations.Add(new ProcessedAnimationClip
|
||
{
|
||
name = tag.name,
|
||
frameIndices = frameIndices,
|
||
loop = true,
|
||
frameDuration = 0,
|
||
sampleRate = 100
|
||
});
|
||
}
|
||
}
|
||
|
||
// 解析frames对象 - 使用正则表达式或手动解析
|
||
int framesStart = jsonContent.IndexOf("\"frames\":");
|
||
if (framesStart == -1)
|
||
{
|
||
throw new Exception("找不到frames部分");
|
||
}
|
||
|
||
// 找到frames对象的开始和结束
|
||
int framesBraceStart = jsonContent.IndexOf('{', framesStart);
|
||
int framesBraceEnd = FindMatchingBrace(jsonContent, framesBraceStart);
|
||
string framesContent = jsonContent.Substring(framesBraceStart + 1, framesBraceEnd - framesBraceStart - 1);
|
||
|
||
// 解析每个帧条目
|
||
ParseFramesContent(framesContent, frames);
|
||
|
||
// 按名称排序帧(确保顺序正确)
|
||
frames = frames.OrderBy(f => ExtractFrameNumber(f.name)).ThenBy(f => f.name).ToList();
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
throw new Exception($"解析Aseprite JSON失败: {e.Message}\n{e.StackTrace}");
|
||
}
|
||
|
||
return new ProcessedAnimationData
|
||
{
|
||
frames = frames,
|
||
animations = animations
|
||
};
|
||
}
|
||
|
||
private static void ParseFramesContent(string framesContent, List<FrameData> frames)
|
||
{
|
||
int pos = 0;
|
||
while (pos < framesContent.Length)
|
||
{
|
||
// 跳过空白字符和逗号
|
||
while (pos < framesContent.Length && (char.IsWhiteSpace(framesContent[pos]) || framesContent[pos] == ','))
|
||
pos++;
|
||
|
||
if (pos >= framesContent.Length) break;
|
||
|
||
// 查找帧名称(在引号中)
|
||
if (framesContent[pos] != '"')
|
||
{
|
||
pos++;
|
||
continue;
|
||
}
|
||
|
||
int nameStart = pos + 1;
|
||
int nameEnd = framesContent.IndexOf('"', nameStart);
|
||
if (nameEnd == -1) break;
|
||
|
||
string frameName = framesContent.Substring(nameStart, nameEnd - nameStart);
|
||
pos = nameEnd + 1;
|
||
|
||
// 跳过冒号和空白
|
||
while (pos < framesContent.Length && (char.IsWhiteSpace(framesContent[pos]) || framesContent[pos] == ':'))
|
||
pos++;
|
||
|
||
if (pos >= framesContent.Length) break;
|
||
|
||
// 查找帧数据对象
|
||
if (framesContent[pos] != '{')
|
||
{
|
||
continue;
|
||
}
|
||
|
||
int dataStart = pos;
|
||
int dataEnd = FindMatchingBrace(framesContent, dataStart);
|
||
if (dataEnd == -1) break;
|
||
|
||
string frameDataJson = framesContent.Substring(dataStart, dataEnd - dataStart + 1);
|
||
pos = dataEnd + 1;
|
||
|
||
try
|
||
{
|
||
AsepriteFrameInfo frameInfo = JsonUtility.FromJson<AsepriteFrameInfo>(frameDataJson);
|
||
if (frameInfo.frame != null)
|
||
{
|
||
frames.Add(new FrameData
|
||
{
|
||
name = frameName,
|
||
x = frameInfo.frame.x,
|
||
y = frameInfo.frame.y,
|
||
width = frameInfo.frame.w,
|
||
height = frameInfo.frame.h,
|
||
duration = frameInfo.duration
|
||
});
|
||
}
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Debug.LogWarning($"解析帧数据失败: {frameName}, 错误: {e.Message}");
|
||
}
|
||
}
|
||
}
|
||
|
||
private static int ExtractFrameNumber(string frameName)
|
||
{
|
||
// 尝试从帧名称中提取数字(例如 "调酒妹侧头 0.aseprite" -> 0)
|
||
int lastSpace = frameName.LastIndexOf(' ');
|
||
if (lastSpace >= 0 && lastSpace < frameName.Length - 1)
|
||
{
|
||
string numberPart = frameName.Substring(lastSpace + 1);
|
||
int dotIndex = numberPart.IndexOf('.');
|
||
if (dotIndex > 0)
|
||
{
|
||
numberPart = numberPart.Substring(0, dotIndex);
|
||
}
|
||
|
||
if (int.TryParse(numberPart, out int number))
|
||
{
|
||
return number;
|
||
}
|
||
}
|
||
return int.MaxValue; // 如果无法解析,放在最后
|
||
}
|
||
|
||
private static int FindMatchingBrace(string str, int startIndex)
|
||
{
|
||
if (startIndex < 0 || startIndex >= str.Length) return -1;
|
||
|
||
int braceCount = 0;
|
||
bool foundStart = false;
|
||
|
||
for (int i = startIndex; i < str.Length; i++)
|
||
{
|
||
if (str[i] == '{')
|
||
{
|
||
braceCount++;
|
||
foundStart = true;
|
||
}
|
||
else if (str[i] == '}')
|
||
{
|
||
braceCount--;
|
||
if (braceCount == 0 && foundStart)
|
||
{
|
||
return i;
|
||
}
|
||
}
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
// 解析手动JSON
|
||
public static ProcessedAnimationData ParseManualJson(string jsonPath, string texturePath)
|
||
{
|
||
string jsonContent = File.ReadAllText(jsonPath);
|
||
ManualJsonData manualData = JsonUtility.FromJson<ManualJsonData>(jsonContent);
|
||
|
||
if (manualData.layout == null || manualData.animations == null)
|
||
{
|
||
throw new Exception("无效的手动JSON格式");
|
||
}
|
||
|
||
// 验证layout参数
|
||
if (manualData.layout.rows <= 0 || manualData.layout.columns <= 0)
|
||
{
|
||
throw new Exception("rows和columns必须大于0");
|
||
}
|
||
|
||
// 读取图片尺寸
|
||
TextureImporter textureImporter = AssetImporter.GetAtPath(texturePath) as TextureImporter;
|
||
if (textureImporter == null)
|
||
{
|
||
throw new Exception($"无法加载纹理导入器: {texturePath}");
|
||
}
|
||
|
||
Texture2D texture = AssetDatabase.LoadAssetAtPath<Texture2D>(texturePath);
|
||
if (texture == null)
|
||
{
|
||
throw new Exception($"无法加载纹理: {texturePath}");
|
||
}
|
||
|
||
int imageWidth = texture.width;
|
||
int imageHeight = texture.height;
|
||
|
||
// 计算sprite尺寸
|
||
int spriteWidth = imageWidth / manualData.layout.columns;
|
||
int spriteHeight = imageHeight / manualData.layout.rows;
|
||
|
||
// 验证图片尺寸能被行列数整除
|
||
if (imageWidth % manualData.layout.columns != 0 || imageHeight % manualData.layout.rows != 0)
|
||
{
|
||
throw new Exception($"图片尺寸({imageWidth}x{imageHeight})无法被行列数({manualData.layout.columns}x{manualData.layout.rows})整除");
|
||
}
|
||
|
||
// 计算总帧数
|
||
int totalFrames = manualData.layout.frameCount ?? (manualData.layout.rows * manualData.layout.columns);
|
||
if (totalFrames > manualData.layout.rows * manualData.layout.columns)
|
||
{
|
||
throw new Exception($"frameCount({totalFrames})不能超过rows*columns({manualData.layout.rows * manualData.layout.columns})");
|
||
}
|
||
|
||
// 生成帧数据
|
||
List<FrameData> frames = new List<FrameData>();
|
||
bool isHorizontal = manualData.layout.direction == "horizontal";
|
||
|
||
for (int frameIndex = 0; frameIndex < totalFrames; frameIndex++)
|
||
{
|
||
int row, column;
|
||
if (isHorizontal)
|
||
{
|
||
// 横向排列:按行扫描,从左到右,从上到下
|
||
row = frameIndex / manualData.layout.columns;
|
||
column = frameIndex % manualData.layout.columns;
|
||
}
|
||
else
|
||
{
|
||
// 纵向排列:按列扫描,从上到下,从左到右
|
||
column = frameIndex / manualData.layout.rows;
|
||
row = frameIndex % manualData.layout.rows;
|
||
}
|
||
|
||
// 使用左上角为(0,0)的坐标系,向右向下为正轴
|
||
// 在SliceSprites中会统一转换为Unity的左下角坐标系
|
||
int x = column * spriteWidth;
|
||
int y = row * spriteHeight;
|
||
|
||
frames.Add(new FrameData
|
||
{
|
||
name = $"frame_{frameIndex}",
|
||
x = x,
|
||
y = y,
|
||
width = spriteWidth,
|
||
height = spriteHeight,
|
||
duration = manualData.frameDuration
|
||
});
|
||
}
|
||
|
||
// 处理动画片段
|
||
List<ProcessedAnimationClip> animations = new List<ProcessedAnimationClip>();
|
||
foreach (var anim in manualData.animations)
|
||
{
|
||
// 应用参数覆盖逻辑
|
||
float frameDuration = anim.frameDuration ?? manualData.frameDuration;
|
||
int sampleRate = anim.sampleRate ?? manualData.sampleRate;
|
||
|
||
animations.Add(new ProcessedAnimationClip
|
||
{
|
||
name = anim.name,
|
||
frameIndices = anim.frameIndices,
|
||
loop = anim.loop,
|
||
frameDuration = frameDuration,
|
||
sampleRate = sampleRate
|
||
});
|
||
}
|
||
|
||
return new ProcessedAnimationData
|
||
{
|
||
frames = frames,
|
||
animations = animations
|
||
};
|
||
}
|
||
|
||
// 根据JSON信息切图
|
||
public static void SliceSprites(string texturePath, List<FrameData> frames, Vector2 pivot)
|
||
{
|
||
TextureImporter textureImporter = AssetImporter.GetAtPath(texturePath) as TextureImporter;
|
||
if (textureImporter == null)
|
||
{
|
||
throw new Exception($"无法加载纹理导入器: {texturePath}");
|
||
}
|
||
|
||
// 获取纹理尺寸
|
||
Texture2D texture = AssetDatabase.LoadAssetAtPath<Texture2D>(texturePath);
|
||
if (texture == null)
|
||
{
|
||
throw new Exception($"无法加载纹理: {texturePath}");
|
||
}
|
||
int textureHeight = texture.height;
|
||
|
||
// 设置spriteMode为Multiple
|
||
textureImporter.spriteImportMode = SpriteImportMode.Multiple;
|
||
|
||
// 使用新的Sprite Editor Data Provider API (Unity 2020.2+)
|
||
var spriteDataProviderFactories = new SpriteDataProviderFactories();
|
||
spriteDataProviderFactories.Init();
|
||
var dataProvider = spriteDataProviderFactories.GetSpriteEditorDataProviderFromObject(textureImporter);
|
||
|
||
if (dataProvider == null)
|
||
{
|
||
throw new Exception($"无法获取Sprite Editor Data Provider: {texturePath}");
|
||
}
|
||
|
||
dataProvider.InitSpriteEditorDataProvider();
|
||
|
||
// 创建SpriteRect数组
|
||
// 注意:JSON中的坐标是以左上角为(0,0),向右向下为正轴
|
||
// Unity的纹理坐标系统是左下角为(0,0),向上为正轴
|
||
// 需要将Y坐标从左上角坐标系转换为Unity的左下角坐标系
|
||
var spriteRects = new SpriteRect[frames.Count];
|
||
for (int i = 0; i < frames.Count; i++)
|
||
{
|
||
var frame = frames[i];
|
||
|
||
// 坐标转换:从左上角(0,0)坐标系转换为Unity左下角(0,0)坐标系
|
||
// Unity Y = 纹理高度 - (原始Y + 高度)
|
||
float unityY = textureHeight - (frame.y + frame.height);
|
||
|
||
// 根据 pivot 值确定 alignment
|
||
SpriteAlignment alignment = SpriteAlignment.Custom;
|
||
if (pivot == new Vector2(0.5f, 0.5f))
|
||
alignment = SpriteAlignment.Center;
|
||
else if (pivot == new Vector2(0f, 1f))
|
||
alignment = SpriteAlignment.TopLeft;
|
||
else if (pivot == new Vector2(1f, 1f))
|
||
alignment = SpriteAlignment.TopRight;
|
||
else if (pivot == new Vector2(0f, 0f))
|
||
alignment = SpriteAlignment.BottomLeft;
|
||
else if (pivot == new Vector2(1f, 0f))
|
||
alignment = SpriteAlignment.BottomRight;
|
||
else if (pivot == new Vector2(0.5f, 1f))
|
||
alignment = SpriteAlignment.TopCenter;
|
||
else if (pivot == new Vector2(0.5f, 0f))
|
||
alignment = SpriteAlignment.BottomCenter;
|
||
else if (pivot == new Vector2(0f, 0.5f))
|
||
alignment = SpriteAlignment.LeftCenter;
|
||
else if (pivot == new Vector2(1f, 0.5f))
|
||
alignment = SpriteAlignment.RightCenter;
|
||
|
||
spriteRects[i] = new SpriteRect
|
||
{
|
||
name = frame.name,
|
||
rect = new Rect(frame.x, unityY, frame.width, frame.height),
|
||
pivot = pivot,
|
||
alignment = alignment
|
||
};
|
||
}
|
||
|
||
dataProvider.SetSpriteRects(spriteRects);
|
||
dataProvider.Apply();
|
||
|
||
AssetDatabase.ImportAsset(texturePath, ImportAssetOptions.ForceUpdate);
|
||
}
|
||
|
||
// 创建或更新 AnimationClip(若已存在则在原资源上就地更新,避免引用丢失)
|
||
public static AnimationClip CreateAnimationClip(
|
||
ProcessedAnimationClip animationData,
|
||
List<FrameData> frames,
|
||
Sprite[] sprites,
|
||
string outputPath,
|
||
bool isImageAnimation = false)
|
||
{
|
||
// 先计算目标资源路径
|
||
string fullPath = Path.Combine(outputPath, $"{animationData.name}.anim");
|
||
string assetPath = fullPath.Replace('\\', '/');
|
||
if (!assetPath.StartsWith("Assets/"))
|
||
{
|
||
// 转换为相对路径
|
||
string projectPath = Application.dataPath.Replace("Assets", "");
|
||
if (assetPath.StartsWith(projectPath))
|
||
{
|
||
assetPath = assetPath.Substring(projectPath.Length);
|
||
}
|
||
}
|
||
|
||
// 如果已经存在同名 AnimationClip,则复用该资源,在其上就地更新
|
||
AnimationClip clip = AssetDatabase.LoadAssetAtPath<AnimationClip>(assetPath);
|
||
bool isNewClip = false;
|
||
if (clip == null)
|
||
{
|
||
clip = new AnimationClip();
|
||
isNewClip = true;
|
||
}
|
||
|
||
clip.name = animationData.name;
|
||
|
||
// 设置采样率
|
||
AnimationClipSettings settings = AnimationUtility.GetAnimationClipSettings(clip);
|
||
clip.frameRate = animationData.sampleRate;
|
||
|
||
// 创建Sprite关键帧
|
||
List<ObjectReferenceKeyframe> keyframes = new List<ObjectReferenceKeyframe>();
|
||
float currentTime = 0f;
|
||
|
||
foreach (int frameIndex in animationData.frameIndices)
|
||
{
|
||
if (frameIndex < 0 || frameIndex >= sprites.Length)
|
||
{
|
||
Debug.LogWarning($"帧索引{frameIndex}超出范围,跳过");
|
||
continue;
|
||
}
|
||
|
||
Sprite sprite = sprites[frameIndex];
|
||
if (sprite == null)
|
||
{
|
||
Debug.LogWarning($"帧索引{frameIndex}的Sprite为空,跳过");
|
||
continue;
|
||
}
|
||
|
||
// 使用帧的duration(如果是Aseprite格式)或动画的frameDuration(手动格式)
|
||
float frameDuration = frames[frameIndex].duration > 0
|
||
? frames[frameIndex].duration / 1000f // 毫秒转秒
|
||
: animationData.frameDuration / 1000f;
|
||
|
||
keyframes.Add(new ObjectReferenceKeyframe
|
||
{
|
||
time = currentTime,
|
||
value = sprite
|
||
});
|
||
|
||
currentTime += frameDuration;
|
||
}
|
||
|
||
if (keyframes.Count == 0)
|
||
{
|
||
throw new Exception($"动画片段{animationData.name}没有有效的关键帧");
|
||
}
|
||
|
||
// 设置循环
|
||
if (animationData.loop && keyframes.Count > 1)
|
||
{
|
||
// 添加最后一帧的重复,确保循环
|
||
keyframes.Add(new ObjectReferenceKeyframe
|
||
{
|
||
time = currentTime,
|
||
value = keyframes[^1].value
|
||
});
|
||
}
|
||
|
||
// 创建EditorCurveBinding - 根据动画类型选择不同的组件
|
||
EditorCurveBinding curveBinding = new EditorCurveBinding
|
||
{
|
||
path = "",
|
||
type = isImageAnimation ? typeof(UnityEngine.UI.Image) : typeof(SpriteRenderer),
|
||
propertyName = "m_Sprite"
|
||
};
|
||
|
||
// 设置曲线
|
||
AnimationUtility.SetObjectReferenceCurve(clip, curveBinding, keyframes.ToArray());
|
||
|
||
// 设置循环
|
||
settings.loopTime = animationData.loop;
|
||
AnimationUtility.SetAnimationClipSettings(clip, settings);
|
||
|
||
// 强制更新动画长度 (m_StopTime) - 修复复用已有 clip 时长度未更新的问题
|
||
float totalDuration = keyframes.Count > 0 ? keyframes[keyframes.Count - 1].time : 0f;
|
||
SerializedObject serializedClip = new SerializedObject(clip);
|
||
SerializedProperty stopTimeProp = serializedClip.FindProperty("m_StopTime");
|
||
if (stopTimeProp != null)
|
||
{
|
||
stopTimeProp.floatValue = totalDuration;
|
||
serializedClip.ApplyModifiedProperties();
|
||
}
|
||
|
||
// 保存 / 更新 AnimationClip 资源
|
||
if (isNewClip)
|
||
{
|
||
// 不存在则创建新资源
|
||
AssetDatabase.CreateAsset(clip, assetPath);
|
||
}
|
||
else
|
||
{
|
||
// 已存在则标记为已修改,保持原 GUID 与引用
|
||
EditorUtility.SetDirty(clip);
|
||
}
|
||
|
||
AssetDatabase.SaveAssets();
|
||
|
||
return clip;
|
||
}
|
||
|
||
// 主流程:生成AnimationClip
|
||
public static void GenerateClips(string texturePath, string jsonPath, string outputPath, bool isImageAnimation = false, Vector2 pivot = default)
|
||
{
|
||
// 如果没有提供 pivot,使用默认值(中心)
|
||
if (pivot == default)
|
||
{
|
||
pivot = new Vector2(0.5f, 0.5f);
|
||
}
|
||
// 确保 pivot 值在有效范围内
|
||
pivot.x = Mathf.Clamp01(pivot.x);
|
||
pivot.y = Mathf.Clamp01(pivot.y);
|
||
try
|
||
{
|
||
EditorUtility.DisplayProgressBar("生成AnimationClip", "检查SpriteMode...", 0f);
|
||
|
||
// 检查SpriteMode
|
||
SpriteImportMode spriteMode = CheckSpriteMode(texturePath);
|
||
if (spriteMode == SpriteImportMode.Multiple)
|
||
{
|
||
Debug.Log("图片的SpriteMode已经是Multiple,将使用现有的Sprite切图");
|
||
}
|
||
|
||
EditorUtility.DisplayProgressBar("生成AnimationClip", "解析JSON...", 0.2f);
|
||
|
||
// 判断JSON类型并解析
|
||
ProcessedAnimationData processedData;
|
||
string jsonContent = File.ReadAllText(jsonPath);
|
||
|
||
if (jsonContent.Contains("\"type\":\"manual\"") || jsonContent.Contains("\"type\": \"manual\""))
|
||
{
|
||
// 手动格式
|
||
processedData = ParseManualJson(jsonPath, texturePath);
|
||
}
|
||
else
|
||
{
|
||
// Aseprite格式
|
||
processedData = ParseAsepriteJson(jsonPath, texturePath);
|
||
}
|
||
|
||
// Debug.Log($"processedData: {processedData.ToString()}");
|
||
|
||
EditorUtility.DisplayProgressBar("生成AnimationClip", "切图...", 0.4f);
|
||
|
||
// 如果是Single模式,需要切图
|
||
if (spriteMode == SpriteImportMode.Single)
|
||
{
|
||
SliceSprites(texturePath, processedData.frames, pivot);
|
||
// 重新加载以确保sprites可用
|
||
AssetDatabase.Refresh();
|
||
}
|
||
|
||
EditorUtility.DisplayProgressBar("生成AnimationClip", "加载Sprites...", 0.6f);
|
||
|
||
// 加载所有Sprites
|
||
Sprite[] allSpritesArray = AssetDatabase.LoadAllAssetsAtPath(texturePath)
|
||
.OfType<Sprite>()
|
||
.ToArray();
|
||
|
||
if (allSpritesArray.Length == 0)
|
||
{
|
||
throw new Exception("无法加载任何Sprite,请检查切图设置");
|
||
}
|
||
|
||
// 创建Sprite字典以便快速查找
|
||
Dictionary<string, Sprite> spriteDict = allSpritesArray.ToDictionary(s => s.name, s => s);
|
||
|
||
// 按照frames列表的顺序创建Sprite数组
|
||
Sprite[] allSprites = new Sprite[processedData.frames.Count];
|
||
for (int i = 0; i < processedData.frames.Count; i++)
|
||
{
|
||
string frameName = processedData.frames[i].name;
|
||
if (spriteDict.TryGetValue(frameName, out Sprite sprite))
|
||
{
|
||
allSprites[i] = sprite;
|
||
}
|
||
else
|
||
{
|
||
Debug.LogWarning($"找不到名为{frameName}的Sprite");
|
||
// 尝试使用索引查找
|
||
if (i < allSpritesArray.Length)
|
||
{
|
||
allSprites[i] = allSpritesArray[i];
|
||
}
|
||
}
|
||
}
|
||
|
||
// 确保输出目录存在
|
||
if (!Directory.Exists(outputPath))
|
||
{
|
||
Directory.CreateDirectory(outputPath);
|
||
}
|
||
|
||
EditorUtility.DisplayProgressBar("生成AnimationClip", "创建AnimationClip...", 0.8f);
|
||
|
||
// 为每个动画片段创建AnimationClip
|
||
int animationCount = processedData.animations.Count;
|
||
for (int i = 0; i < animationCount; i++)
|
||
{
|
||
var anim = processedData.animations[i];
|
||
EditorUtility.DisplayProgressBar("生成AnimationClip",
|
||
$"创建动画片段: {anim.name}", 0.8f + (i / (float)animationCount) * 0.2f);
|
||
|
||
CreateAnimationClip(anim, processedData.frames, allSprites, outputPath, isImageAnimation);
|
||
}
|
||
|
||
EditorUtility.ClearProgressBar();
|
||
Debug.Log($"成功生成{animationCount}个AnimationClip到: {outputPath}");
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
EditorUtility.ClearProgressBar();
|
||
Debug.LogError($"生成AnimationClip失败: {e.Message}");
|
||
throw;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|