← Files UnityARCHIVED FILE

skills/manage-sprite-atlas/resources/updatebuildscripts.cs

11.6 KB · Oct 5, 2026 · 18:34 UTC

↓ Download file

// [UNITY-SKILL:SPRITEATLAS]
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEditor.U2D;
using UnityEngine;

/// <summary>
/// Demonstrates updating build scripts for SpriteAtlas V2.
/// Shows how to migrate from old build patterns to the prebuild pipeline.
/// </summary>
public static class UpdateBuildScriptsDocumentation
{
    /// <summary>
    /// OLD Pattern: Manual atlas packing in build script (NO LONGER RECOMMENDED)
    ///
    /// ❌ OLD CODE:
    /// public static void BuildGame()
    /// {
    ///     // Manually pack atlases before build
    ///     SpriteAtlasUtility.PackAtlases(atlases, target);
    ///     BuildPipeline.BuildPlayer(...);
    /// }
    ///
    /// ✅ NEW V2 CODE:
    /// Implement IPreprocessBuildWithReport for automatic packing
    /// </summary>
    public static void Update_BuildScript_Packing()
    {
        // ===== UPDATING: Build Script with Manual Packing =====

        // ❌ OLD (V1 - Not recommended):
        /*
        [MenuItem("Tools/Build Game")]
        public static void BuildGame()
        {
            // Manually pack atlases
            var guids = AssetDatabase.FindAssets("t:SpriteAtlasAsset", new[] { "Assets" });
            var atlases = new SpriteAtlas[guids.Length];
            for (int i = 0; i < guids.Length; i++)
            {
                atlases[i] = AssetDatabase.LoadAssetAtPath<SpriteAtlas>(
                    AssetDatabase.GUIDToAssetPath(guids[i]));
            }

            // Manual packing before build
            SpriteAtlasUtility.PackAtlases(atlases, EditorUserBuildSettings.activeBuildTarget);

            // Then build
            BuildPipeline.BuildPlayer(...);
        }
        */

        // ✅ NEW (V2 - Recommended):
        /*
        // Implement this as a prebuild processor instead:
        public class AtlasPreprocessor : IPreprocessBuildWithReport
        {
            public int callbackOrder => 0;

            public void OnPreprocessBuild(BuildTarget target, string path)
            {
                // Atlases are automatically packed during build
                // Use this for generation/configuration only
            }
        }

        [MenuItem("Tools/Build Game")]
        public static void BuildGame()
        {
            // Just build - atlases are handled automatically
            BuildPipeline.BuildPlayer(...);
        }
        */
    }

    /// <summary>
    /// OLD Pattern: Building with Addressables (REQUIRES UPDATES)
    ///
    /// ❌ OLD CODE:
    /// public static void BuildWithAddressables()
    /// {
    ///     // Manually build atlases
    ///     BuildPipeline.BuildAssetBundles(...);
    ///     AddressableAssetSettings.BuildPlayerContent();
    /// }
    ///
    /// ✅ NEW V2 CODE:
    /// Use IPreprocessBuildWithReport for atlas generation,
    /// IPostprocessBuildWithReport for Addressables content building
    /// </summary>
    public static void Update_BuildScript_Addressables()
    {
        // ===== UPDATING: Build Script with Addressables =====

        // ❌ OLD (V1 - Requires updates):
        /*
        [MenuItem("Tools/Build With Addressables")]
        public static void BuildWithAddressables()
        {
            // Generate atlases
            GenerateAtlases();

            // Build asset bundles
            BuildPipeline.BuildAssetBundles(...);

            // Build addressables content
            AddressableAssetSettings.BuildPlayerContent();
        }
        */

        // ✅ NEW (V2 - Recommended):
        /*
        // Step 1: Prebuild processor for atlas generation
        public class AtlasPreprocessor : IPreprocessBuildWithReport
        {
            public void OnPreprocessBuild(BuildTarget target, string path)
            {
                GenerateAtlases(); // Generate atlases before build
            }
        }

        // Step 2: Postprocess processor for Addressables
        public class AddressablesPostprocessor : IPostprocessBuildWithReport
        {
            public void OnPostprocessBuild(BuildTarget target, string path)
            {
                AddressableAssetSettings.BuildPlayerContent();
            }
        }

        // Step 3: Simple build script
        [MenuItem("Tools/Build With Addressables")]
        public static void BuildWithAddressables()
        {
            // Atlases and addressables are handled automatically
            BuildPipeline.BuildPlayer(...);
        }
        */
    }

    /// <summary>
    /// Complete example: Updated build pipeline with prebuild.
    /// </summary>
    public static void Complete_UpdatedBuildPipeline()
    {
        // ===== COMPLETE: Updated Build Pipeline (V2) =====

        /*
        // ============================================
        // PREBUILD: Generate atlases automatically
        // ============================================

        public class AtlasPreprocessor : IPreprocessBuildWithReport
        {
            public int callbackOrder => 0;

            public void OnPreprocessBuild(BuildTarget target, string path)
            {
                Debug.Log("Generating atlases before build...");

                // Find all sprite folders
                var folderConfigs = new[]
                {
                    new { Folder = "Assets/Art/UI", Output = "Assets/Atlases/UI.spriteatlasv2" },
                    new { Folder = "Assets/Art/Characters", Output = "Assets/Atlases/Characters.spriteatlasv2" }
                };

                foreach (var config in folderConfigs)
                {
                    GenerateAtlasByFolder(config.Folder, config.Output);
                }

                Debug.Log("Atlas generation complete.");
            }

            private void GenerateAtlasByFolder(string folderPath, string outputPath)
            {
                // Find sprites in folder
                var guids = AssetDatabase.FindAssets("t:Sprite", new[] { folderPath });

                // Load sprites
                var sprites = new Object[guids.Length];
                for (int i = 0; i < guids.Length; i++)
                {
                    sprites[i] = AssetDatabase.LoadAssetAtPath<Sprite>(
                        AssetDatabase.GUIDToAssetPath(guids[i]));
                }

                // Create atlas asset
                var asset = new SpriteAtlasAsset();
                asset.Add(sprites);

                // Save and import
                SpriteAtlasAsset.Save(asset, outputPath);
                AssetDatabase.ImportAsset(outputPath);

                // Configure via importer
                var importer = AssetImporter.GetAtPath(outputPath) as SpriteAtlasImporter;
                if (importer != null)
                {
                    importer.includeInBuild = true;
                    importer.packingSettings.tightPacking = true;
                    importer.SaveAndReimport();
                }
            }
        }

        // ============================================
        // BUILD: Simple build script
        // ============================================

        [MenuItem("Tools/Build Game")]
        public static void BuildGame()
        {
            Debug.Log("Starting build...");

            // Atlases are automatically generated by preprocessor
            // No manual packing needed!

            var buildResult = BuildPipeline.BuildPlayer(GetBuildOptions());
            if (buildResult.summary.result == BuildResult.Succeeded)
            {
                Debug.Log($"Build succeeded: {buildResult.outputPath}");
            }
        }

        private static BuildPlayerOptions GetBuildOptions()
        {
            return new BuildPlayerOptions
            {
                scenes = EditorBuildSettings.scenes,
                locationPathName = "Builds/Game.exe",
                target = EditorUserBuildSettings.activeBuildTarget,
                options = BuildOptions.None
            };
        }
        */
    }

    /// <summary>
    /// Migration checklist for build scripts:
    ///
    /// [ ] Remove manual SpriteAtlasUtility.PackAtlases() calls
    /// [ ] Implement IPreprocessBuildWithReport for atlas generation
    /// [ ] Use IPostprocessBuildWithReport for post-build steps (Addressables, etc.)
    /// [ ] Simplify build scripts - most work is now automated
    /// </summary>
    public static void Migration_Checklist()
    {
        /*
        MIGRATION CHECKLIST:
        ====================

        1. Remove Manual Packing
           - OLD: SpriteAtlasUtility.PackAtlases() in build script
           - NEW: Automatic during build (remove manual calls)

        2. Add Prebuild Processor
           - Implement IPreprocessBuildWithReport.OnPreprocessBuild()
           - Generate or update atlases here

        3. Add Postbuild Processor (if needed)
           - Implement IPostprocessBuildWithReport.OnPostprocessBuild()
           - Handle Addressables, asset bundles, etc.

        4. Simplify Build Script
           - Remove manual atlas generation/packing
           - Just call BuildPipeline.BuildPlayer()

        5. Test Build Pipeline
           - Verify atlases are generated before build
           - Check that atlases are included in build output
        */
    }
}

/// <summary>
/// Example: Complete prebuild processor for atlas generation.
/// </summary>
public class CompletePreprocessor : IPreprocessBuildWithReport
{
    public int callbackOrder => 0;
    public void OnPreprocessBuild(BuildReport report)
    {
        Debug.Log($"[AtlasPreprocessor] Generating atlases...");

        // Generate atlases by folder
        GenerateAtlasByFolder("Assets/Art/UI", "Assets/Atlases/UI.spriteatlasv2");
        GenerateAtlasByFolder("Assets/Art/Characters", "Assets/Atlases/Characters.spriteatlasv2");

        Debug.Log("[AtlasPreprocessor] Atlas generation complete.");
    }

    private void GenerateAtlasByFolder(string folderPath, string outputPath)
    {
        // Find sprites in folder
        var guids = AssetDatabase.FindAssets("t:Sprite", new[] { folderPath });

        if (guids.Length == 0)
            return;

        Debug.Log($"[AtlasPreprocessor] Found {guids.Length} sprites in {folderPath}");

        // Load sprites
        var sprites = new Object[guids.Length];
        for (int i = 0; i < guids.Length; i++)
        {
            sprites[i] = AssetDatabase.LoadAssetAtPath<Sprite>(
                AssetDatabase.GUIDToAssetPath(guids[i]));
        }

        // Create or update atlas asset
        SpriteAtlasAsset asset;
        if (System.IO.File.Exists(outputPath))
        {
            asset = AssetDatabase.LoadAssetAtPath<SpriteAtlasAsset>(outputPath);
        }
        else
        {
            asset = new SpriteAtlasAsset();
        }

        asset.Add(sprites);

        // Save and import
        SpriteAtlasAsset.Save(asset, outputPath);
        AssetDatabase.ImportAsset(outputPath);

        // Configure via importer
        var importer = AssetImporter.GetAtPath(outputPath) as SpriteAtlasImporter;
        if (importer != null)
        {
            importer.includeInBuild = true;
            var packingSettings = importer.packingSettings;
            packingSettings.enableTightPacking = true;
            importer.packingSettings = packingSettings;

            // Platform-specific settings
            importer.SetPlatformSettings(new TextureImporterPlatformSettings
            {
                name = "Android",
                maxTextureSize = 1024,
                format = TextureImporterFormat.ETC2_RGB4
            });

            importer.SetPlatformSettings(new TextureImporterPlatformSettings
            {
                name = "Standalone",
                maxTextureSize = 2048,
                format = TextureImporterFormat.DXT5
            });

            importer.SaveAndReimport();
        }
    }
}

SHA-256: dda02af27384dd743812db6ef5c3ea2536f2b977f21e90b5adc705ca9b61ab02