// [UNITY-SKILL:SPRITEATLAS]
using UnityEditor.U2D;
using UnityEngine;
using Unity.Collections;
using System.Collections.Generic;
using System.Linq;
///
/// Size-optimized sprite packer that places larger sprites first.
/// Uses a simple bin-packing approach to minimize atlas space usage.
///
public class SizeOptimizedPacker : ScriptablePacker
{
/// Maximum atlas size (width and height) in pixels
public int atlasSize = 2048;
/// Padding between sprites in pixels
public int padding = 4;
///
/// Packs sprites with larger ones first for better space utilization.
/// Sorts sprites by area (width * height) and places them using first-fit bin packing.
///
public override bool Pack(SpriteAtlasPackingSettings config,
SpriteAtlasTextureSettings setting,
PackerData input)
{
NativeArray sprites = input.spriteData;
NativeArray textures = input.textureData;
// Create sorted list by area (largest first)
var sortedIndices = new List();
for (int i = 0; i < sprites.Length; i++)
{
sortedIndices.Add(i);
}
sortedIndices = sortedIndices
.OrderByDescending(i =>
{
var sprite = sprites[i];
return sprite.rect.width * sprite.rect.height;
})
.ToList();
// Simple bin packing
int currentX = padding;
int currentY = padding;
int maxHeightInRow = 0;
foreach (int idx in sortedIndices)
{
SpriteData sprite = sprites[idx];
int spriteWidth = sprite.rect.width;
int spriteHeight = sprite.rect.height;
// Check if we need a new row
if (currentX + spriteWidth + padding > atlasSize)
{
currentX = padding;
currentY += maxHeightInRow + padding;
maxHeightInRow = 0;
}
// Check if atlas is full
if (currentY + spriteHeight + padding > atlasSize)
{
Debug.LogError("Atlas size exceeded. Increase atlas size or reduce sprite count.");
return false;
}
// Set output
sprite.output.x = currentX;
sprite.output.y = currentY;
sprite.output.page = 0;
sprite.output.rot = PackTransform.None;
// Update position for next sprite
currentX += spriteWidth + padding;
maxHeightInRow = Mathf.Max(maxHeightInRow, spriteHeight);
sprites[idx] = sprite;
}
return true;
}
}