← Files UnityARCHIVED FILE
skills/manage-sprite-atlas/resources/spriteatlasprebuildgenerator.cs
7.9 KB · Oct 3, 2026 · 06:34 UTC
// [UNITY-SKILL:SPRITEATLAS]
// [TYPE:PREBUILD]
// Generated by SpriteAtlas V2 Skill
// This script automatically generates SpriteAtlas assets during prebuild
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEditor.U2D;
using UnityEngine;
using UnityEngine.U2D;
using System.Linq;
using System.Collections.Generic;
#if UNITY_ADDRESSABLES
using UnityEditor.AddressableAssets;
using UnityEditor.AddressableAssets.Settings;
#endif
public class SpriteAtlasPrebuildGenerator : IPreprocessBuildWithReport
{
public int callbackOrder => 0;
private List<string> generatedAtlasPaths = new List<string>();
public void OnPreprocessBuild(BuildReport report)
{
Debug.Log("[SpriteAtlas] Generating atlases for late-binding via Addressables...");
// CRITICAL: Enable Sprite Packer mode
EditorSettings.spritePackerMode = SpritePackerMode.SpriteAtlasV2;
generatedAtlasPaths.Clear();
// Customize these paths - includeInBuild is FALSE for Addressables
GenerateAtlasByFolder("Assets/Art/UI", "Assets/Atlases/UI_Atlas.spriteatlasv2", includeInBuild: false);
GenerateAtlasByFolder("Assets/Art/Characters", "Assets/Atlases/Characters_Atlas.spriteatlasv2", includeInBuild: false);
GenerateAtlasByNaming("Assets/Art/Items", "item_", "Assets/Atlases/Items_Atlas.spriteatlasv2", includeInBuild: false);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
// Setup Addressables for all generated atlases
SetupAddressables();
}
private void SetupAddressables()
{
#if UNITY_ADDRESSABLES
var settings = AddressableAssetSettingsDefaultObject.Settings;
if (settings == null)
{
Debug.LogError("[SpriteAtlas] Addressables is not initialized. Please install and setup Addressables package.");
return;
}
var group = settings.DefaultGroup;
if (group == null)
{
Debug.LogError("[SpriteAtlas] Default Addressables group not found.");
return;
}
foreach (var atlasPath in generatedAtlasPaths)
{
var guid = AssetDatabase.AssetPathToGUID(atlasPath);
if (string.IsNullOrEmpty(guid))
{
Debug.LogWarning($"[SpriteAtlas] Could not find GUID for {atlasPath}");
continue;
}
// Check if already exists
var existingEntry = settings.FindAssetEntry(guid);
if (existingEntry != null)
{
Debug.Log($"[SpriteAtlas] Atlas already addressable: {atlasPath}");
continue;
}
// Create addressable entry
var entry = settings.CreateOrMoveEntry(guid, group, false, false);
var atlasName = System.IO.Path.GetFileNameWithoutExtension(atlasPath);
entry.address = atlasName; // Use atlas name as address
Debug.Log($"[SpriteAtlas] Added to Addressables: {atlasName} at {atlasPath}");
}
settings.SetDirty(AddressableAssetSettings.ModificationEvent.EntryAdded, null, true);
#else
Debug.LogError("[SpriteAtlas] Addressables package is not installed. Please install 'com.unity.addressables' package.");
#endif
}
// CRITICAL: Validate sprite is from project Assets folder only
private bool IsValidProjectSprite(string assetPath)
{
return assetPath.StartsWith("Assets/") &&
!assetPath.Contains("/Packages/");
}
private void GenerateAtlasByFolder(string spriteFolder, string atlasPath, bool includeInBuild)
{
// Find all sprites in folder - with path validation
string[] guids = AssetDatabase.FindAssets("t:Sprite", new[] { spriteFolder });
Object[] sprites = guids
.Select(g => AssetDatabase.GUIDToAssetPath(g))
.Where(path => IsValidProjectSprite(path))
.Select(path => AssetDatabase.LoadAssetAtPath<Sprite>(path))
.Where(s => s != null)
.Cast<Object>()
.ToArray();
if (sprites.Length == 0)
{
Debug.LogWarning($"[SpriteAtlas] No sprites found in {spriteFolder}");
return;
}
// Create or load existing atlas
SpriteAtlasAsset atlasAsset;
if (System.IO.File.Exists(atlasPath))
{
atlasAsset = SpriteAtlasAsset.Load(atlasPath);
var spriteAtlas = AssetDatabase.LoadAssetAtPath<SpriteAtlas>(atlasPath);
atlasAsset.Remove(spriteAtlas.GetPackables()); // Clear existing
}
else
{
atlasAsset = new SpriteAtlasAsset();
System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(atlasPath));
}
// Add sprites and save
atlasAsset.Add(sprites);
SpriteAtlasAsset.Save(atlasAsset, atlasPath);
AssetDatabase.ImportAsset(atlasPath);
// Configure via importer
ConfigureAtlasImporter(atlasPath, includeInBuild);
// Track for Addressables setup
generatedAtlasPaths.Add(atlasPath);
Debug.Log($"[SpriteAtlas] Generated {atlasPath} with {sprites.Length} sprites (includeInBuild={includeInBuild})");
}
private void GenerateAtlasByNaming(string searchFolder, string namePrefix, string atlasPath, bool includeInBuild)
{
// Find sprites matching naming convention - with path validation
string[] guids = AssetDatabase.FindAssets("t:Sprite", new[] { searchFolder });
Object[] sprites = guids
.Select(g => AssetDatabase.GUIDToAssetPath(g))
.Where(path => IsValidProjectSprite(path))
.Select(path => AssetDatabase.LoadAssetAtPath<Sprite>(path))
.Where(s => s != null && s.name.StartsWith(namePrefix))
.Cast<Object>()
.ToArray();
if (sprites.Length == 0) return;
// Create or update atlas (same pattern as folder-based)
SpriteAtlasAsset atlasAsset = System.IO.File.Exists(atlasPath)
? SpriteAtlasAsset.Load(atlasPath)
: new SpriteAtlasAsset();
if (System.IO.File.Exists(atlasPath))
{
var spriteAtlas = AssetDatabase.LoadAssetAtPath<SpriteAtlas>(atlasPath);
atlasAsset.Remove(spriteAtlas.GetPackables());
}
atlasAsset.Add(sprites);
SpriteAtlasAsset.Save(atlasAsset, atlasPath);
AssetDatabase.ImportAsset(atlasPath);
ConfigureAtlasImporter(atlasPath, includeInBuild);
// Track for Addressables setup
generatedAtlasPaths.Add(atlasPath);
}
private void ConfigureAtlasImporter(string atlasPath, bool includeInBuild)
{
SpriteAtlasImporter importer = AssetImporter.GetAtPath(atlasPath) as SpriteAtlasImporter;
if (importer == null) return;
// Texture settings
var textureSettings = importer.textureSettings;
textureSettings.filterMode = FilterMode.Bilinear;
textureSettings.generateMipMaps = false;
importer.textureSettings = textureSettings;
// Packing settings
var packingSettings = importer.packingSettings;
packingSettings.padding = 4;
packingSettings.enableAlphaDilation = true;
importer.packingSettings = packingSettings;
// Platform settings
SetPlatformSettings(importer, "Android", TextureImporterFormat.ASTC_6x6);
SetPlatformSettings(importer, "iOS", TextureImporterFormat.ASTC_4x4);
// Set build inclusion based on delivery mechanism
importer.includeInBuild = includeInBuild;
importer.SaveAndReimport();
}
private void SetPlatformSettings(SpriteAtlasImporter importer, string platformName, TextureImporterFormat format)
{
var settings = new TextureImporterPlatformSettings
{
name = platformName,
overridden = true,
maxTextureSize = 2048,
format = format
};
importer.SetPlatformSettings(settings);
}
}
SHA-256: c590f3d8ff89da10030233a4c769ccea049f9bcf271337decd600de4c69edeeb