// [UNITY-SKILL:SPRITEATLAS] using UnityEngine; using UnityEngine.U2D; /// /// Demonstrates proper handling of late-binding for SpriteAtlases. /// Late-binding allows atlases to be loaded on-demand when sprites are first accessed. /// public class HandleLateBinding : MonoBehaviour { /// Prefix used for atlas resources [SerializeField] private string _atlasResourcePrefix = "Atlases/"; /// Whether to automatically load atlases [SerializeField] private bool _autoLoad = true; private void Awake() { if (_autoLoad) { RegisterLateBinding(); } } private void OnDestroy() { UnregisterLateBinding(); } /// /// Registers for late-binding via SpriteAtlasManager. /// When a sprite needs an atlas, the registration callback will be invoked. /// public void RegisterLateBinding() { SpriteAtlasManager.atlasRequested += RequestLateBindingAtlas; SpriteAtlasManager.atlasRegistered += AtlasRegistered; Debug.Log("Late-binding registered"); } /// /// Unregisters late-binding callbacks. /// Call this when the component is destroyed or no longer needs late-binding. /// public void UnregisterLateBinding() { SpriteAtlasManager.atlasRequested -= RequestLateBindingAtlas; SpriteAtlasManager.atlasRegistered -= AtlasRegistered; Debug.Log("Late-binding unregistered"); } /// /// Callback invoked when a sprite needs its atlas but it's not loaded yet. /// This is where you implement the late-binding logic. /// void RequestLateBindingAtlas(string tag, System.Action action) { // Determine which atlas should contain this sprite string atlasName = GetAtlasNameForSprite(tag); if (string.IsNullOrEmpty(atlasName)) { Debug.LogWarning($"Could not determine atlas for sprite: {tag}"); return; } // Load the atlas asynchronously LoadAtlasAsync(atlasName); } /// /// Gets the atlas name for a given sprite. /// This is project-specific logic - adjust based on your naming conventions. /// private string GetAtlasNameForSprite(string tag) { // Pattern 1: Use sprite name prefix if (tag.StartsWith("btn_")) return "UI_Buttons"; else if (tag.StartsWith("icon_")) return "UI_Icons"; else if (tag.StartsWith("char_")) return "Characters"; return "Default"; } /// /// Loads an atlas asynchronously. /// In a real implementation, this would use Addressables or AssetBundle loading. /// private void LoadAtlasAsync(string atlasName) { // Example using Resources.Load (not recommended for production) // SpriteAtlas atlas = Resources.Load(atlasName); // For production with Addressables: /* var handle = Addressables.LoadAssetAsync(atlasName); handle.Completed += op => { if (op.Status == AsyncOperationStatus.Succeeded) { Debug.Log($"Late-bound atlas loaded: {atlasName}"); } else { Debug.LogError($"Failed to load late-bound atlas: {atlasName}"); } }; */ Debug.Log($"Loading late-bound atlas: {atlasName}"); } void AtlasRegistered(SpriteAtlas spriteAtlas) { Debug.LogFormat("Registered {0}.", spriteAtlas.name); } /// /// Forces loading of a specific atlas (for manual control). /// public void ForceLoadAtlas(string atlasName) { LoadAtlasAsync(atlasName); } } /// /// Example of using late-binding in a scene with multiple objects. /// Each object can request its atlas to be loaded. /// public class LateBindingConsumer : MonoBehaviour { [SerializeField] private Sprite _spriteToDisplay; private void Start() { // Accessing the sprite will trigger late-binding if needed SpriteRenderer renderer = GetComponent(); if (renderer != null && _spriteToDisplay != null) { renderer.sprite = _spriteToDisplay; Debug.Log($"Set sprite: {_spriteToDisplay.name}"); } } }