Addressables na Unity: Carregar Assets sob Demanda
O unity addressables é o sistema da Unity para carregar assets pelo endereço, na hora em que você precisa, e tirar da memória quando não precisa mais. O uso básico: marcar o asset como Addressable, guardar um AssetReference no script, carregar com LoadAssetAsync ou InstantiateAsync esperando com await, e liberar com Release ou ReleaseInstance. É isso que impede o jogo de carregar todos os chefes, músicas e fases logo na abertura.
Antes de instalar, a pergunta honesta: o seu projeto precisa disso? Este post mostra quando não usar, e para quem precisa, o passo a passo no Unity 6.3 LTS com código C# que compila, a contagem de referências que evita vazamento, grupos locais e remotos, e os erros mais comuns.
O problema que Addressables resolve
Quando um script tem um campo [SerializeField] private GameObject bossPrefab; apontando para um prefab, a Unity carrega esse prefab, e tudo que ele usa (malhas, texturas, sons, animações), junto com a cena. Mesmo que o chefe só apareça daqui a 40 minutos de jogo.
Em projeto pequeno, isso não importa. Em projeto com muitas fases, personagens com texturas grandes ou trilha sonora pesada, a memória enche, o carregamento inicial demora e, no celular, o sistema fecha o app.
O Addressables troca a referência direta por uma referência por endereço. O asset fica fora da cena e só entra na memória quando o código pede. Também permite agrupar conteúdo em pacotes que podem ser baixados depois da instalação.
Quando NÃO usar Addressables
- Jogo de jam ou protótipo: a complexidade não se paga.
- Jogo pequeno que cabe inteiro na memória do aparelho mais fraco que você suporta: referência direta no Inspector é mais simples, mais rápida de depurar e não tem como esquecer
Release. - Poucas fases leves: dividir em cenas e trocar de cena já descarrega o que a cena anterior usava.
- Só para reduzir o tamanho do instalador: o Addressables ajuda, mas o primeiro passo é revisar compressão de textura e áudio, assunto do post sobre reduzir o tamanho da build na Unity.
A pasta Resources continua funcionando, mas tudo que está nela entra na build e fica num índice carregado no início, sem controle de dependência. Ela serve para poucos arquivos pequenos e sempre necessários. Para conteúdo grande e opcional, Addressables é o caminho.
Use quando: o jogo tem muito conteúdo que não precisa estar na memória ao mesmo tempo, você quer baixar conteúdo depois da instalação (fases extras, eventos), ou o celular alvo está ficando sem memória.
Instalar e marcar assets como Addressable
- Window > Package Management > Package Manager, Unity Registry, instale Addressables (
com.unity.addressables). O manual do Unity 6.3 indica a versão 2.10.3 para o editor 6000.3 e lista a linha 4.x como disponível também. - Abra Window > Asset Management > Addressables > Groups e clique em Create Addressables Settings. Isso cria a pasta
AddressableAssetsDatacom as configurações e o grupo padrão. - Selecione um prefab, áudio ou textura no Project e marque a caixa Addressable no topo do Inspector. Ele ganha um endereço (por padrão, o caminho do arquivo). Renomeie para algo curto, como
Boss/Dragao. - Na janela Groups, crie grupos com clique direito > Create New Group > Packed Assets e arraste assets para organizar (ex.:
Fase1,Chefes,Musica).
Na barra da janela Groups, Play Mode Script define como o editor carrega no Play Mode:
- Use Asset Database (fastest): carrega direto dos arquivos do projeto. Rápido para iterar, mas não testa a build de conteúdo.
- Use Existing Build (requires built groups): usa o conteúdo gerado por Build > New Build > Default Build Script. É o teste fiel.
Unity Addressables: carregar com AssetReference
O AssetReference é um campo no Inspector onde você arrasta um asset Addressable, sem criar referência direta. As versões tipadas (AssetReferenceGameObject, AssetReferenceT<AudioClip>) limitam o que pode ser arrastado.
Arquivo BossSpawner.cs:
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
public class BossSpawner : MonoBehaviour
{
[SerializeField] private AssetReferenceGameObject bossPrefab;
[SerializeField] private Transform spawnPoint;
private GameObject bossInstance;
public async Task SpawnBossAsync()
{
if (bossInstance != null)
{
return;
}
AsyncOperationHandle<GameObject> handle = bossPrefab.InstantiateAsync(spawnPoint.position, spawnPoint.rotation);
GameObject instance = await handle.Task;
if (handle.Status != AsyncOperationStatus.Succeeded)
{
Debug.LogError("Falha ao carregar o chefe: " + handle.OperationException);
Addressables.Release(handle);
return;
}
bossInstance = instance;
}
public void DespawnBoss()
{
if (bossInstance == null)
{
return;
}
bossPrefab.ReleaseInstance(bossInstance);
bossInstance = null;
}
private void OnDestroy()
{
DespawnBoss();
}
}
O await handle.Task espera o carregamento sem travar o jogo: enquanto o chefe carrega, o resto continua rodando. Chame SpawnBossAsync() de um gatilho de área com _ = spawner.SpawnBossAsync(); ou de um método async. Na linha 4.x do pacote, o changelog informa que também dá para escrever await handle direto, com exceção em caso de falha.
Para assets que não são instanciados (áudio, sprite, ScriptableObject), carregue e guarde o handle. Arquivo MusicLoader.cs:
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
public class MusicLoader : MonoBehaviour
{
[SerializeField] private AssetReferenceT<AudioClip> bossMusic;
[SerializeField] private AudioSource musicSource;
private AsyncOperationHandle<AudioClip> musicHandle;
public async Task PlayBossMusicAsync()
{
StopAndRelease();
musicHandle = Addressables.LoadAssetAsync<AudioClip>(bossMusic);
AudioClip clip = await musicHandle.Task;
if (musicHandle.Status == AsyncOperationStatus.Succeeded)
{
musicSource.clip = clip;
musicSource.Play();
}
}
public void StopAndRelease()
{
musicSource.Stop();
musicSource.clip = null;
if (musicHandle.IsValid())
{
Addressables.Release(musicHandle);
}
}
private void OnDestroy()
{
StopAndRelease();
}
}
Liberar memória e contagem de referências
O Addressables conta referências. Cada carregamento soma 1 ao asset e às dependências dele; cada Release tira 1. Quando chega a zero, o asset pode sair da memória (e o pacote que o contém, quando nada mais dele está em uso).
As regras que evitam vazamento:
- Todo
LoadAssetAsynctem umReleasecorrespondente, com o mesmo handle. - Todo
InstantiateAsynctem umReleaseInstance. ChamarDestroyna instância apaga o GameObject, mas a contagem continua lá. - Guarde o handle num campo. Sem ele, você não tem o que liberar.
- Não use o asset depois do
Release: a referência pode virar nula ou apontar para algo descarregado.
Para ver se está vazando, abra Window > Analysis > Profiler e adicione o módulo Asset Loading, ou use o Memory Profiler e compare duas capturas antes e depois de entrar e sair de uma fase.
Carregar e liberar um chefe é o exemplo fácil. O difícil é desenhar o fluxo de conteúdo de um jogo inteiro: o que carrega no início, o que entra por fase, o que fica sempre, e como menus, save e transições conversam com isso sem travar a tela. Essa arquitetura de projeto é o que mais falta para quem aprende por tutorial isolado.
Grupos, labels e build de conteúdo
Grupos decidem como os assets viram pacotes (AssetBundles). Assets do mesmo grupo podem cair no mesmo pacote, e um pacote só sai da memória quando nada dele está em uso. Por isso, agrupe por momento de uso: tudo da Fase 1 junto, cada chefe separado, músicas separadas. Um grupo gigante com tudo derrota o propósito.
Labels marcam vários assets para carregar juntos. Selecione assets na janela Groups, coluna Labels, e crie uma, como inimigos-fase1. Depois:
AsyncOperationHandle<IList<GameObject>> handle =
Addressables.LoadAssetsAsync<GameObject>("inimigos-fase1", prefab => Debug.Log("Carregado: " + prefab.name));
(com using System.Collections.Generic;). O callback roda para cada asset, e um único Addressables.Release(handle) libera todos.
Build de conteúdo: na janela Groups, Build > New Build > Default Build Script gera os pacotes. Confira em AddressableAssetSettings a opção de construir o conteúdo junto com a build do jogo, para não publicar um jogo sem os pacotes atualizados.
Use Window > Asset Management > Addressables > Analyze e rode as regras de dependência duplicada. Elas mostram assets que entraram em mais de um pacote sem você perceber, o que gasta memória e espaço.
Conteúdo remoto: visão geral
Cada grupo tem Build Path e Load Path, configurados em Profiles (Window > Asset Management > Addressables > Profiles). Com o grupo apontando para o caminho Remote, os pacotes são gerados numa pasta que você sobe para um servidor ou CDN, e o jogo baixa quando precisa, guardando em cache.
Isso permite fases extras e eventos sem nova versão na loja, e reduz o download inicial. Exige cuidar de catálogo (o índice de endereços), versão de conteúdo e atualização. A Unity oferece o Cloud Content Delivery como hospedagem integrada, mas qualquer servidor HTTP serve. Para um primeiro projeto, deixe tudo local e domine carga e liberação antes.
Erros comuns: vazamento, InvalidKeyException
- Memória que só cresce:
LoadAssetAsyncsemRelease, ouDestroyem instância criada porInstantiateAsync. InvalidKeyException: endereço digitado errado, asset desmarcado como Addressable, label vazia ou Play Mode Script em Use Existing Build com conteúdo velho. Refaça o Default Build Script.- "Attempting to load AssetReference that has already been loaded": chamou
LoadAssetAsyncduas vezes no mesmoAssetReference. Use o handle guardado ouAddressables.LoadAssetAsynccom a referência como chave. - Funciona no editor, falha na build: Play Mode Script estava em Use Asset Database, e a build de conteúdo não foi gerada ou ficou desatualizada.
- Asset duplicado na memória: o mesmo asset está numa cena (referência direta) e num grupo Addressable. Rode o Analyze.
- Material rosa na build: shader removido no stripping porque só um asset Addressable o usava. Confira as variantes de shader na build.
Próximo passo
Pegue um único asset pesado do seu jogo, como a música de chefe ou um prefab grande, transforme em Addressable e carregue com o BossSpawner ou o MusicLoader acima. Meça a memória no Profiler antes e depois. Se o ganho for pequeno, você aprendeu algo barato e pode parar por ali. Se o problema for muitos objetos criados e destruídos durante o jogo, o padrão certo é outro: veja object pooling. E para o panorama de memória, CPU e GPU, leia otimização de performance para 60 FPS.
Perguntas frequentes
Qual versão do Addressables usar no Unity 6.3?
O manual do Unity 6.3 indica a versão 2.10.3 como a lançada para o editor 6000.3, e lista também a linha 4.x como disponível. O código deste post usa a API comum às duas (LoadAssetAsync, InstantiateAsync, Release e handle.Task). A 4.x acrescenta await direto no handle.
Addressables ou Resources: qual usar?
Para projeto pequeno, que cabe todo na memória do aparelho alvo, referência direta no Inspector resolve e é mais simples. Resources ainda funciona, mas tudo que está na pasta entra na build e não dá para controlar dependências. Addressables vale quando você precisa carregar e descarregar conteúdo sob demanda ou baixar conteúdo depois da instalação.
O que causa InvalidKeyException no Addressables?
A chave pedida não existe no catálogo carregado. Normalmente é endereço digitado diferente, asset que deixou de ser Addressable, label sem nenhum asset, ou Play Mode Script em Use Existing Build com o conteúdo desatualizado. Refaça a build de conteúdo ou volte para Use Asset Database para conferir.
Preciso chamar Release depois de carregar?
Sim. O Addressables conta referências: cada LoadAssetAsync soma uma, cada Release tira uma, e o asset só sai da memória quando a contagem chega a zero. Destruir o GameObject não libera o que foi carregado. Instância criada com InstantiateAsync se libera com ReleaseInstance.



