mirror of
https://github.com/Donchitos/Claude-Code-Game-Studios
synced 2026-04-29 08:57:19 +00:00
379 lines
7.9 KiB
Markdown
379 lines
7.9 KiB
Markdown
|
|
# Unity 6.3 — Addressables
|
||
|
|
|
||
|
|
**Last verified:** 2026-02-13
|
||
|
|
**Status:** Production-Ready
|
||
|
|
**Package:** `com.unity.addressables` (Package Manager)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Overview
|
||
|
|
|
||
|
|
**Addressables** is Unity's advanced asset management system that replaces `Resources.Load()`
|
||
|
|
with async loading, remote content delivery, and better memory control.
|
||
|
|
|
||
|
|
**Use Addressables for:**
|
||
|
|
- Async asset loading (non-blocking)
|
||
|
|
- DLC and remote content
|
||
|
|
- Memory optimization (load/unload on demand)
|
||
|
|
- Asset dependency management
|
||
|
|
- Large projects with many assets
|
||
|
|
|
||
|
|
**DON'T use Addressables for:**
|
||
|
|
- Tiny projects (overhead not worth it)
|
||
|
|
- Assets needed immediately at startup (use direct references)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Installation
|
||
|
|
|
||
|
|
### Install via Package Manager
|
||
|
|
|
||
|
|
1. `Window > Package Manager`
|
||
|
|
2. Unity Registry > Search "Addressables"
|
||
|
|
3. Install `Addressables`
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Core Concepts
|
||
|
|
|
||
|
|
### 1. **Addressable Assets**
|
||
|
|
- Assets marked as "Addressable" (assigned unique keys)
|
||
|
|
- Can be loaded by key at runtime
|
||
|
|
|
||
|
|
### 2. **Asset Groups**
|
||
|
|
- Organize assets (e.g., "UI", "Weapons", "Level1")
|
||
|
|
- Groups determine build settings (local vs remote)
|
||
|
|
|
||
|
|
### 3. **Async Loading**
|
||
|
|
- All loading is async (non-blocking)
|
||
|
|
- Returns `AsyncOperationHandle`
|
||
|
|
|
||
|
|
### 4. **Reference Counting**
|
||
|
|
- Addressables tracks asset usage
|
||
|
|
- Must manually release assets when done
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Setup
|
||
|
|
|
||
|
|
### 1. Mark Assets as Addressable
|
||
|
|
|
||
|
|
1. Select asset in Project window
|
||
|
|
2. Inspector > Check "Addressable"
|
||
|
|
3. Assign key (e.g., "Enemies/Goblin")
|
||
|
|
|
||
|
|
**OR via script:**
|
||
|
|
```csharp
|
||
|
|
#if UNITY_EDITOR
|
||
|
|
using UnityEditor.AddressableAssets;
|
||
|
|
using UnityEditor.AddressableAssets.Settings;
|
||
|
|
|
||
|
|
AddressableAssetSettings.AddAssetEntry(guid, "MyAssetKey", "Default Local Group");
|
||
|
|
#endif
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### 2. Create Groups
|
||
|
|
|
||
|
|
`Window > Asset Management > Addressables > Groups`
|
||
|
|
|
||
|
|
- **Default Local Group**: Bundled with build
|
||
|
|
- **Remote Group**: Hosted on server (CDN)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Basic Loading
|
||
|
|
|
||
|
|
### Load Asset Async
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
using UnityEngine.AddressableAssets;
|
||
|
|
using UnityEngine.ResourceManagement.AsyncOperations;
|
||
|
|
|
||
|
|
public class AssetLoader : MonoBehaviour {
|
||
|
|
async void Start() {
|
||
|
|
// ✅ Load asset asynchronously
|
||
|
|
AsyncOperationHandle<GameObject> handle = Addressables.LoadAssetAsync<GameObject>("Enemies/Goblin");
|
||
|
|
await handle.Task;
|
||
|
|
|
||
|
|
if (handle.Status == AsyncOperationStatus.Succeeded) {
|
||
|
|
GameObject prefab = handle.Result;
|
||
|
|
Instantiate(prefab);
|
||
|
|
} else {
|
||
|
|
Debug.LogError("Failed to load asset");
|
||
|
|
}
|
||
|
|
|
||
|
|
// ⚠️ IMPORTANT: Release when done
|
||
|
|
Addressables.Release(handle);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Load and Instantiate
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
async void SpawnEnemy() {
|
||
|
|
// ✅ Load and instantiate in one step
|
||
|
|
AsyncOperationHandle<GameObject> handle = Addressables.InstantiateAsync("Enemies/Goblin");
|
||
|
|
await handle.Task;
|
||
|
|
|
||
|
|
GameObject enemy = handle.Result;
|
||
|
|
// Use enemy...
|
||
|
|
|
||
|
|
// ✅ Release when destroying
|
||
|
|
Addressables.ReleaseInstance(enemy);
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Load Multiple Assets
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
async void LoadAllWeapons() {
|
||
|
|
// Load all assets with label "Weapons"
|
||
|
|
AsyncOperationHandle<IList<GameObject>> handle = Addressables.LoadAssetsAsync<GameObject>("Weapons", null);
|
||
|
|
await handle.Task;
|
||
|
|
|
||
|
|
foreach (var weapon in handle.Result) {
|
||
|
|
Debug.Log($"Loaded: {weapon.name}");
|
||
|
|
}
|
||
|
|
|
||
|
|
Addressables.Release(handle);
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Asset Labels (Tags)
|
||
|
|
|
||
|
|
### Assign Labels
|
||
|
|
|
||
|
|
1. `Window > Asset Management > Addressables > Groups`
|
||
|
|
2. Select asset > Inspector > Labels > Add label (e.g., "Level1", "UI")
|
||
|
|
|
||
|
|
### Load by Label
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
// Load all assets with label "Level1"
|
||
|
|
Addressables.LoadAssetsAsync<GameObject>("Level1", null);
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Remote Content (DLC)
|
||
|
|
|
||
|
|
### Setup Remote Groups
|
||
|
|
|
||
|
|
1. Create new group: `Window > Addressables > Groups > Create New Group > Packed Assets`
|
||
|
|
2. Group Settings:
|
||
|
|
- **Build Path**: `ServerData/[BuildTarget]`
|
||
|
|
- **Load Path**: `http://yourcdn.com/content/[BuildTarget]`
|
||
|
|
|
||
|
|
### Build Remote Content
|
||
|
|
|
||
|
|
1. `Window > Asset Management > Addressables > Build > New Build > Default Build Script`
|
||
|
|
2. Upload `ServerData/` folder to CDN
|
||
|
|
3. Game loads assets from remote server
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Preloading / Caching
|
||
|
|
|
||
|
|
### Download Dependencies
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
async void PreloadLevel() {
|
||
|
|
// Download all assets in group without loading into memory
|
||
|
|
AsyncOperationHandle handle = Addressables.DownloadDependenciesAsync("Level1");
|
||
|
|
await handle.Task;
|
||
|
|
|
||
|
|
// Now "Level1" assets are cached, load instantly
|
||
|
|
Addressables.Release(handle);
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Check Download Size
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
async void CheckDownloadSize() {
|
||
|
|
AsyncOperationHandle<long> handle = Addressables.GetDownloadSizeAsync("Level1");
|
||
|
|
await handle.Task;
|
||
|
|
|
||
|
|
long sizeInBytes = handle.Result;
|
||
|
|
Debug.Log($"Download size: {sizeInBytes / (1024 * 1024)} MB");
|
||
|
|
|
||
|
|
Addressables.Release(handle);
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Memory Management
|
||
|
|
|
||
|
|
### Release Assets
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
// ✅ Always release when done
|
||
|
|
Addressables.Release(handle);
|
||
|
|
|
||
|
|
// ✅ For instantiated objects
|
||
|
|
Addressables.ReleaseInstance(gameObject);
|
||
|
|
```
|
||
|
|
|
||
|
|
### Check Reference Count
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
// Addressables uses reference counting
|
||
|
|
// Asset is unloaded when refCount == 0
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Asset References (Inspector-Assigned)
|
||
|
|
|
||
|
|
### Use AssetReference
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
using UnityEngine.AddressableAssets;
|
||
|
|
|
||
|
|
public class EnemySpawner : MonoBehaviour {
|
||
|
|
// ✅ Assign in Inspector (drag & drop)
|
||
|
|
public AssetReference enemyPrefab;
|
||
|
|
|
||
|
|
async void SpawnEnemy() {
|
||
|
|
AsyncOperationHandle<GameObject> handle = enemyPrefab.InstantiateAsync();
|
||
|
|
await handle.Task;
|
||
|
|
|
||
|
|
GameObject enemy = handle.Result;
|
||
|
|
// Use enemy...
|
||
|
|
|
||
|
|
enemyPrefab.ReleaseInstance(enemy);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Scenes
|
||
|
|
|
||
|
|
### Load Addressable Scene
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
using UnityEngine.SceneManagement;
|
||
|
|
|
||
|
|
async void LoadScene() {
|
||
|
|
AsyncOperationHandle<SceneInstance> handle = Addressables.LoadSceneAsync("MainMenu", LoadSceneMode.Additive);
|
||
|
|
await handle.Task;
|
||
|
|
|
||
|
|
SceneInstance sceneInstance = handle.Result;
|
||
|
|
// Scene loaded
|
||
|
|
|
||
|
|
// Unload scene
|
||
|
|
await Addressables.UnloadSceneAsync(handle).Task;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Common Patterns
|
||
|
|
|
||
|
|
### Lazy Loading (Load on Demand)
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
Dictionary<string, AsyncOperationHandle<GameObject>> loadedAssets = new();
|
||
|
|
|
||
|
|
async Task<GameObject> GetAsset(string key) {
|
||
|
|
if (!loadedAssets.ContainsKey(key)) {
|
||
|
|
var handle = Addressables.LoadAssetAsync<GameObject>(key);
|
||
|
|
await handle.Task;
|
||
|
|
loadedAssets[key] = handle;
|
||
|
|
}
|
||
|
|
return loadedAssets[key].Result;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Cleanup on Scene Unload
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
void OnDestroy() {
|
||
|
|
// Release all handles
|
||
|
|
foreach (var handle in loadedAssets.Values) {
|
||
|
|
Addressables.Release(handle);
|
||
|
|
}
|
||
|
|
loadedAssets.Clear();
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Content Catalog Updates (Live Updates)
|
||
|
|
|
||
|
|
### Check for Catalog Updates
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
async void CheckForUpdates() {
|
||
|
|
AsyncOperationHandle<List<string>> handle = Addressables.CheckForCatalogUpdates();
|
||
|
|
await handle.Task;
|
||
|
|
|
||
|
|
if (handle.Result.Count > 0) {
|
||
|
|
Debug.Log("Updates available");
|
||
|
|
await Addressables.UpdateCatalogs(handle.Result).Task;
|
||
|
|
}
|
||
|
|
|
||
|
|
Addressables.Release(handle);
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Performance Tips
|
||
|
|
|
||
|
|
- **Preload** frequently used assets at startup
|
||
|
|
- **Release** assets immediately when not needed
|
||
|
|
- Use **labels** to batch-load related assets
|
||
|
|
- **Cache** remote content for offline use
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Debugging
|
||
|
|
|
||
|
|
### Addressables Event Viewer
|
||
|
|
|
||
|
|
`Window > Asset Management > Addressables > Event Viewer`
|
||
|
|
|
||
|
|
- Shows all load/release operations
|
||
|
|
- Memory usage per asset
|
||
|
|
- Reference counts
|
||
|
|
|
||
|
|
### Addressables Profiler
|
||
|
|
|
||
|
|
`Window > Asset Management > Addressables > Profiler`
|
||
|
|
|
||
|
|
- Real-time asset usage
|
||
|
|
- Bundle loading stats
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Migration from Resources
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
// ❌ OLD: Resources.Load (synchronous, blocks frame)
|
||
|
|
GameObject prefab = Resources.Load<GameObject>("Enemies/Goblin");
|
||
|
|
|
||
|
|
// ✅ NEW: Addressables (async, non-blocking)
|
||
|
|
var handle = await Addressables.LoadAssetAsync<GameObject>("Enemies/Goblin").Task;
|
||
|
|
GameObject prefab = handle.Result;
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Sources
|
||
|
|
- https://docs.unity3d.com/Packages/com.unity.addressables@2.0/manual/index.html
|
||
|
|
- https://learn.unity.com/tutorial/addressables
|