You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity Editor如何通过代码访问已切片纹理内的子Sprite对象

Unity编辑器脚本获取已切片PNG下Sprite资源返回null问题

需求背景

  • 需要在自定义Editor工具中,无交互访问当前选中的、已在Sprite Editor完成切片的PNG资源下的所有Sprite子资源
  • 场景示例:自定义GUIEditor已可识别当前选中的Druid_jump纹理,需要直接获取从Druid_Jump_0_00到Druid_Jump_3_03的所有Sprite对象,用于配置4组动画剪辑
  • 参考截图:
    示例截图

问题复现代码

List<Texture2D> textures = new List<Texture2D>(Selection.GetFiltered<Texture2D>(SelectionMode.Unfiltered));
foreach (Texture texture in textures)
{
    if (texture != null)
    {
        string path = AssetDatabase.GetAssetPath(texture);
        string containingFolder = null;
        if (string.IsNullOrEmpty(containingFolder))
        {
            containingFolder = path.Remove(path.LastIndexOf('/'));
        }
        var importer = AssetImporter.GetAtPath(path) as TextureImporter;
        List<Sprite> currentFrames = new List<Sprite>();
        int index = 0;
        foreach (SpriteMetaData spriteMetaData in importer.spritesheet)
        {
            string[] slice = spriteMetaData.name.Split('_');
            if (slice[2] != index.ToString())
            {
                //CreateAnimation(currentFrames.Count, currentFrames);
                currentFrames = new List<Sprite>();
                index++;
            }

            // 代码执行到此处前均正常,需要获取Sprite类型对象完成动画创建
            Sprite sprite = AssetDatabase.LoadAssetAtPath<Sprite>($"{containingFolder}/{spriteMetaData.name}");
            //currentFrames.Add(sprite);
            Debug.Log(sprite.name);
        }
    }
}

问题现象

代码执行到获取Sprite实例的逻辑前均可正常运行,遍历importer.spritesheet可正确返回所有切片的Sprite名称,但用于加载单个Sprite的代码AssetDatabase.LoadAssetAtPath<Sprite>($"{containingFolder}/{spriteMetaData.name}")始终返回null,无法拿到Sprite类型对象完成后续动画创建逻辑。


解决方案

返回null的核心原因是加载路径错误。Sprite Editor切分生成的Sprite不是存放在资源同级目录下的独立文件,是挂载在原PNG纹理下的子资源,拼接的{containingFolder}/{spriteMetaData.name}路径不存在对应资源,自然返回null。
两种可直接落地的修复方式:

  • 方式1:批量加载所有子Sprite做映射(推荐,性能更好)
    在遍历spritesheet前一次性加载当前PNG下的所有Sprite,按名称建立字典,循环内直接匹配即可:
// 遍历spritesheet前执行,加载当前纹理下所有Sprite建立映射
Dictionary<string, Sprite> spriteLookup = AssetDatabase.LoadAllAssetsAtPath(path)
    .OfType<Sprite>()
    .ToDictionary(s => s.name, s => s);

foreach (SpriteMetaData spriteMetaData in importer.spritesheet)
{
    // 其余原有分组逻辑不变
    Sprite sprite = spriteLookup[spriteMetaData.name];
    currentFrames.Add(sprite);
    Debug.Log(sprite.name);
}
  • 方式2:按子资源路径格式加载
    Unity加载子资源的路径格式为主资源路径/子资源名称,不需要拼接文件夹路径,直接用PNG本身的asset路径拼接Sprite名即可:
// 替换原有加载Sprite的代码
Sprite sprite = AssetDatabase.LoadAssetAtPath<Sprite>($"{path}/{spriteMetaData.name}");

额外注意:现有分组逻辑存在遗漏,切换分组时注释的CreateAnimation方法不会触发,最后一组动画帧也不会走到创建分支,需要补全对应处理。


内容的提问来源于stack exchange,提问作者James D

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 21:12:24