Danro/Assets/Editor/SpriteAssetGenerator.cs
Danil Iarosh 77f7f9ef39
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
Use prize icons in rules page and align them vertically (with scale and position alignment)
- Добавлен Editor-скрипт SpriteAssetGenerator для автоматической генерации TMP Sprite Asset'ов из текстур призов.
- Сгенерированы TMP Sprite Asset'ы (Prize, Prize_Hopper, Prize_Marbles, Prize_QR, Prize_Tickets) в папке Assets/Resources/Sprite Assets.
- Настроены FaceInfo и вертикальное центрирование спрайтов относительно текста.
- Обновлен RulesPrizeListPage.cs: вместо текстовых названий призов выводятся соответствующие пиктограммы с помощью тегов <sprite>.
- Добавлены новые файлы текстур призов и их мета-файлы в коммит.
2026-08-03 16:42:43 +03:00

163 lines
6.3 KiB
C#

using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;
using UnityEngine.TextCore;
using TMPro;
public static class SpriteAssetGenerator
{
[MenuItem("Tools/Generate Prize Sprite Assets")]
public static void Generate()
{
string sourceDir = "Assets/Resources/Sprites/UI/Labels";
string destDir = "Assets/Resources/Sprite Assets";
if (!Directory.Exists(destDir))
{
Directory.CreateDirectory(destDir);
AssetDatabase.Refresh();
}
if (!Directory.Exists(sourceDir))
{
Debug.LogError($"[SpriteAssetGenerator] Source directory not found: {sourceDir}");
return;
}
string[] pngFiles = Directory.GetFiles(sourceDir, "*.png");
if (pngFiles.Length == 0)
{
Debug.LogWarning($"[SpriteAssetGenerator] No PNG files found in {sourceDir}");
return;
}
foreach (string pngPath in pngFiles)
{
try
{
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(pngPath);
string assetPath = $"{destDir}/{fileNameWithoutExtension}.asset";
Texture2D sourceTex = AssetDatabase.LoadAssetAtPath<Texture2D>(pngPath);
if (sourceTex == null)
{
Debug.LogWarning($"[SpriteAssetGenerator] Failed to load Texture2D at: {pngPath}");
continue;
}
// Create new Sprite Asset
TMP_SpriteAsset spriteAsset = ScriptableObject.CreateInstance<TMP_SpriteAsset>();
spriteAsset.name = fileNameWithoutExtension;
spriteAsset.spriteInfoList = new List<TMP_Sprite>();
// Set version to 1.1.0 to avoid UpgradeSpriteAsset trigger in Awake/UpdateLookupTables
var versionField = typeof(TMP_Asset).GetField("m_Version", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
if (versionField != null)
{
versionField.SetValue(spriteAsset, "1.1.0");
}
spriteAsset.hashCode = TMP_TextUtilities.GetSimpleHashCode(fileNameWithoutExtension);
spriteAsset.spriteSheet = sourceTex;
// Populate tables
List<TMP_SpriteGlyph> spriteGlyphTable = new List<TMP_SpriteGlyph>();
List<TMP_SpriteCharacter> spriteCharacterTable = new List<TMP_SpriteCharacter>();
// Get all sprites contained in this texture file
Sprite[] sprites = AssetDatabase.LoadAllAssetsAtPath(pngPath)
.Select(x => x as Sprite)
.Where(x => x != null)
.OrderByDescending(x => x.rect.y)
.ThenBy(x => x.rect.x)
.ToArray();
if (sprites.Length == 0)
{
Debug.LogWarning($"[SpriteAssetGenerator] No sprites sliced inside texture {pngPath}. Make sure it is sliced as Sprite (Multiple) or Sprite (Single).");
continue;
}
// Configure FaceInfo to scale the sprites properly
float baseHeight = sprites[0].rect.height;
FaceInfo faceInfo = spriteAsset.faceInfo;
faceInfo.pointSize = (int)baseHeight;
faceInfo.scale = 1.0f;
faceInfo.ascentLine = baseHeight;
faceInfo.capLine = baseHeight * 0.7f;
faceInfo.baseline = 0;
faceInfo.descentLine = 0;
spriteAsset.faceInfo = faceInfo;
for (int i = 0; i < sprites.Length; i++)
{
Sprite sprite = sprites[i];
TMP_SpriteGlyph spriteGlyph = new TMP_SpriteGlyph();
spriteGlyph.index = (uint)i;
float spriteHeight = sprite.rect.height;
// Center the sprite vertically around the cap-height (70% of font size)
float bearingY = spriteHeight * 0.85f;
float bearingX = 0f;
spriteGlyph.metrics = new GlyphMetrics(sprite.rect.width, sprite.rect.height, bearingX, bearingY, sprite.rect.width);
spriteGlyph.glyphRect = new GlyphRect(sprite.rect);
spriteGlyph.scale = 1.0f;
spriteGlyph.sprite = sprite;
spriteGlyphTable.Add(spriteGlyph);
TMP_SpriteCharacter spriteCharacter = new TMP_SpriteCharacter(0xFFFE, spriteGlyph);
spriteCharacter.name = sprite.name;
spriteCharacter.scale = 1.0f;
spriteCharacterTable.Add(spriteCharacter);
}
spriteAsset.spriteCharacterTable.Clear();
spriteAsset.spriteCharacterTable.AddRange(spriteCharacterTable);
spriteAsset.spriteGlyphTable.Clear();
spriteAsset.spriteGlyphTable.AddRange(spriteGlyphTable);
// Add default material
Shader shader = Shader.Find("TextMeshPro/Sprite");
if (shader == null)
{
shader = Shader.Find("UI/Default");
}
if (shader == null)
{
Debug.LogError("[SpriteAssetGenerator] Shader not found!");
continue;
}
Material material = new Material(shader);
material.SetTexture(ShaderUtilities.ID_MainTex, sourceTex);
material.name = fileNameWithoutExtension + " Material";
AssetDatabase.CreateAsset(spriteAsset, assetPath);
AssetDatabase.AddObjectToAsset(material, spriteAsset);
spriteAsset.material = material;
spriteAsset.UpdateLookupTables();
EditorUtility.SetDirty(spriteAsset);
Debug.Log($"[SpriteAssetGenerator] Created Sprite Asset at: {assetPath} with {sprites.Length} sprites.");
}
catch (System.Exception ex)
{
Debug.LogException(ex);
}
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
}