这篇按资源问题来查:文件放哪、怎么引用、Resources 怎么用、Addressables 怎么加载释放、Prefab 和 ScriptableObject 注意什么。
快速索引
| 我想做什么 |
优先方式 |
| 固定依赖资源 |
Inspector 直接拖引用 |
| 少量路径加载 |
Resources.Load |
| 中大型异步加载 |
Addressables |
| 原样打包外部文件 |
StreamingAssets |
| 配置数据 |
ScriptableObject / 表格 |
| 运行时频繁创建对象 |
Prefab + 对象池 |
| 热更新资源 |
Addressables / YooAssets 等资源系统 |
| 避免资源丢引用 |
保留 .meta,不要系统外乱移动 |
0. 推荐目录
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| Assets/ _Project/ # 项目自研内容 Runtime/ # 运行时代码 Gameplay/ UI/ Systems/ Editor/ # 编辑器工具代码 Scenes/ # 场景 Prefabs/ # 预制体 ScriptableObjects/ # 配置资产 Materials/ # 材质 Textures/ # 贴图 Audio/ # 音频 Animations/ # 动画 Shaders/ # Shader Plugins/ # 插件 ThirdParty/ # 第三方库 Resources/ # Resources.Load 用,少放 StreamingAssets/ # 原样打包
|
1. Inspector 引用
1 2 3
| [SerializeField] private GameObject enemyPrefab; [SerializeField] private AudioClip hitSfx; [SerializeField] private Sprite icon;
|
适合:
1 2 3 4
| Prefab 固定依赖 UI 固定图标 音效、材质、配置 场景里明确存在的对象
|
优点:
1 2 3 4
| 引用关系可见 不靠字符串路径 构建依赖更清晰 运行时不需要查找
|
2. Resources.Load
资源路径:
1
| Assets/Resources/Enemies/Goblin.prefab
|
加载写法:
1
| GameObject prefab = Resources.Load<GameObject>("Enemies/Goblin");
|
实例化:
1
| GameObject instance = Instantiate(prefab);
|
路径集中管理:
1 2 3 4
| public static class ResourcePaths { public const string Goblin = "Enemies/Goblin"; }
|
慎用:
1 2 3
| 大量资源全放 Resources # 包体和内存管理变混乱 路径字符串到处写 # 改名后全项目坏 运行中频繁同步 Load # 可能卡顿
|
3. Addressables 基础
异步加载:
1 2 3 4 5 6 7 8 9 10 11
| using UnityEngine.AddressableAssets; using UnityEngine.ResourceManagement.AsyncOperations;
private AsyncOperationHandle<GameObject> handle;
private async void LoadEnemy() { handle = Addressables.LoadAssetAsync<GameObject>("Enemy/Goblin"); GameObject prefab = await handle.Task; Instantiate(prefab); }
|
释放:
1 2 3 4 5 6 7
| private void OnDestroy() { if (handle.IsValid()) { Addressables.Release(handle); } }
|
实例化 Addressables:
1 2
| AsyncOperationHandle<GameObject> instanceHandle = Addressables.InstantiateAsync("Enemy/Goblin", spawnPoint.position, spawnPoint.rotation);
|
释放实例:
1
| Addressables.ReleaseInstance(instance);
|
检查项:
1 2 3 4 5
| 地址是否唯一 Group 是否规划清楚 公共依赖是否重复打包 Load 后是否 Release 远程资源是否构建并上传
|
4. StreamingAssets
常见用途:
1 2 3 4
| 视频文件 本地配置 外部库需要读取的原始文件 首包内置数据
|
路径:
1
| string path = Path.Combine(Application.streamingAssetsPath, "config.json");
|
注意:
1 2 3
| Android 上 StreamingAssets 在 apk 内,不能直接当普通文件读 需要 UnityWebRequest 或平台适配 StreamingAssets 会原样打包,体积要控制
|
5. ScriptableObject 配置
定义配置:
1 2 3 4 5 6 7 8 9
| using UnityEngine;
[CreateAssetMenu(menuName = "Game/Enemy Config")] public sealed class EnemyConfig : ScriptableObject { public int maxHp = 100; public float moveSpeed = 3f; public GameObject prefab; }
|
使用配置:
1 2 3 4 5 6
| [SerializeField] private EnemyConfig config;
private void Spawn() { GameObject enemy = Instantiate(config.prefab); }
|
注意:
1 2 3
| ScriptableObject 适合静态配置 不要把运行时状态直接写回配置资产 运行时需要复制一份数据再改
|
6. Prefab 管理
1 2 3 4
| Prefab 不要引用场景对象 # 实例化后引用容易失效 Prefab 命名清楚 # Enemy_Goblin、UI_BagItem Prefab Variant 控制层级 # 公共基础 + 差异变体 修改 Prefab 后检查场景实例 # 防止覆盖或丢引用
|
实例化后初始化:
1 2
| Enemy enemy = Instantiate(enemyPrefab, spawnPoint.position, spawnPoint.rotation); enemy.Init(config);
|
7. 资源释放
普通对象:
Resources 清理:
1 2
| await Resources.UnloadUnusedAssets(); System.GC.Collect();
|
Addressables:
1 2
| Addressables.Release(handle); Addressables.ReleaseInstance(instance);
|
1 2 3 4 5
| .meta 保存 GUID Unity 引用靠 GUID,不只靠文件名 移动资源尽量在 Unity Editor 内操作 Git 必须提交 .meta 删除 .meta 会导致引用丢失
|
9. 常见坑速查
1 2 3 4 5 6 7
| 所有资源都塞 Resources # 包体和加载不可控 Addressables Load 后不 Release # 内存增长 Prefab 引用场景对象 # 实例化后丢引用 运行时修改 ScriptableObject # 编辑器配置可能被污染 改资源路径但字符串没改 # Resources 加载失败 删除或重建 .meta # 引用大面积丢失 StreamingAssets 在 Android 当 File 读 # 读取失败
|
系列导航