// [UNITY-SKILL:SPRITEATLAS]
using UnityEngine;
using UnityEngine.U2D;
///
/// Demonstrates registering SpriteAtlasManager callbacks early in the lifecycle.
/// Always register callbacks in Awake() or OnEnable(), not in Start().
///
public class RegisterCallbacksExample : MonoBehaviour
{
///
/// Registers atlas loading callbacks when the component awakens.
/// This is the correct place - before any sprites might need atlases.
///
private void Awake()
{
RegisterAtlasCallbacks();
}
///
/// Registers SpriteAtlasManager callbacks for dynamic atlas loading.
/// Called during Awake() to ensure callbacks are ready before any sprite access.
///
private void RegisterAtlasCallbacks()
{
// Register for atlas load events
SpriteAtlasManager.atlasRequested += RequestLateBindingAtlas;
SpriteAtlasManager.atlasRegistered += AtlasRegistered;
Debug.Log("SpriteAtlas callbacks registered");
}
///
/// Unregisters callbacks when the component is destroyed.
/// Always unregister to prevent memory leaks and errors.
///
private void OnDestroy()
{
SpriteAtlasManager.atlasRequested -= RequestLateBindingAtlas;
SpriteAtlasManager.atlasRegistered -= AtlasRegistered;
Debug.Log("SpriteAtlas callbacks 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);
}
}
///
/// Alternative pattern using OnEnable/OnDisable instead of Awake/OnDestroy.
/// Use this if the component can be enabled/disabled dynamically.
///
public class RegisterCallbacksWithEnable : MonoBehaviour
{
private void OnEnable()
{
RegisterAtlasCallbacks();
}
private void OnDisable()
{
UnregisterAtlasCallbacks();
}
private void RegisterAtlasCallbacks()
{
SpriteAtlasManager.atlasRequested += RequestLateBindingAtlas;
SpriteAtlasManager.atlasRegistered += OnAtlasLoaded;
}
private void UnregisterAtlasCallbacks()
{
SpriteAtlasManager.atlasRequested -= RequestLateBindingAtlas;
SpriteAtlasManager.atlasRegistered -= OnAtlasLoaded;
}
private void OnAtlasLoaded(SpriteAtlas atlas) { }
private void RequestLateBindingAtlas(string tag, System.Action action) { }
}