- 示例工程
【免费下载链接】Unity3DTraining
【Unity杂货铺】unity大杂烩~
本文基于仓库 Doc/Unity手游开发中所有特殊的文件夹.md 整理而成,系统讲解 Unity 手游开发中六类特殊文件夹——Editor、Editor Default Resources、Gizmos、Plugins、Resources、StreamingAssets 的作用、打包行为、加载 API 与适用场景,并结合本仓库 HotUpdate 下的 AssetBundle 工程源码,展示 StreamingAssets 在资源热更新中的真实落地方式。读完本文,你将能够正确规划 Unity 工程的目录结构,判断哪类资源该放哪个特殊文件夹,并掌握Resources.Load、AssetDatabase、Application.streamingAssetsPath等 API 的精确使用边界。
1. Editor 文件夹:只属于编辑器、绝不进包的代码与资源
特性总结:
- 位置灵活:
Editor文件夹既可以放在工程根目录(Assets/Editor),也可以放在任意子目录(如Assets/xxx/Editor、Assets/Scripts/Editor),只要文件夹名字叫Editor即可,多个Editor文件夹可以共存,效果等同。 - 不进发布包:
Editor文件夹下放置的所有资源文件与脚本文件都不会被打进最终的发布包(.apk / .ipa / 可执行文件)。 - 仅编辑期可用:其中的脚本只能在编辑器环境下运行,不能作为运行时逻辑使用。
典型用途:把工具类脚本、编辑器扩展代码、编辑期使用的 DLL 放在这里。典型场景如技能编辑器——编辑器核心代码放Editor目录,运行时只消费编辑器生成出来的配置/数据文件,而不需要携带编辑器本体代码。
本仓库中有大量此类实践。例如 HotUpdate/AssetBundleDemo/Assets/Scripts/Editor/BundleHelper.cs 正是放在Assets/Scripts/Editor子目录下的打包工具脚本,它通过MenuItem暴露菜单,调用BuildPipeline.BuildAssetBundles将资源输出到Application.streamingAssetsPath(BundleHelper.cs#L25-L40)。这套打包代码只服务于开发期,运行时玩家根本不需要,正是Editor文件夹存在的意义。
从源码结构看,仓库中Assets/Editor一级目录的用法也一致,例如 HotUpdate/AssetBundleFramework/Assets/Editor/BuildeAssets.cs 同样是纯编辑期脚本。凡此类目录中的代码都不会进入最终包体。
2. Editor Default Resources:编辑器的默认资源仓库
注意:这个文件夹的名字中间是有空格的(Editor Default Resources),且必须放在 Project 视图的根目录下(即Assets/Editor Default Resources),不能放在任意子目录。
特性总结:
- 存放编辑器用到的图片、文本等资源;
- 与
Editor文件夹一样不会被打进最终发布包,仅用于开发期; - 可以通过
EditorGUIUtility.Load直接读取其中的资源,无需关心具体路径:
TextAsset text = EditorGUIUtility.Load("test.txt") as TextAsset; Debug.Log(text.text);也就是说,编辑器扩展中常用的图标、模板文本等散碎资源,统一放进Editor Default Resources后,用EditorGUIUtility.Load按文件名即可取到。它与Editor文件夹的分工是:Editor放代码,Editor Default Resources放编辑器运行时需要的原始资源。
3. Gizmos:Scene 视图里的可视化辅助图标
Gizmos文件夹用于存放 Scene 视图中绘制的辅助图标所用图片。
核心用法一:Gizmos.DrawIcon绘制坐标图标
void OnDrawGizmos() { Gizmos.DrawIcon(transform.position, "0.png", true); }- 第一个参数是
Vector3坐标,即图标要显示的 world 位置; - 第二个参数是图片名,图片必须放在
Gizmos文件夹下; - 第三个参数
true表示允许缩放。
核心用法二:Inspector 直接给单个对象设置图标
如果只想把图标挂在某个游戏对象上,无需写代码,直接在 Inspector 中设置即可:
核心用法三:OnDrawGizmos()的机制与典型场景
- 只要脚本继承
MonoBehaviour,在编辑模式下OnDrawGizmos()会每帧执行; - 发布后的游戏运行时不会执行,它只能用于在 Scene 视图中绘制辅助物件;
- 典型场景:做摄像机轨迹预览,用
Gizmos.DrawLine和Gizmos.DrawFrustum在 Scene 视图中画出轨迹线与视锥,方便美术和策划直观地调参,而这些辅助线完全不影响运行时表现。
4. Plugins:原生 SDK 与第三方库的安置处
做手机游戏时,Android 或 iOS 接入 SDK 的依赖库文件——.so(Android 原生库)、.jar(Android Java 库)、.a(iOS 静态库)等——放在Plugins文件夹下,打包时 Unity 会自动把这些文件打进安装包,并按照对应平台目录(如Plugins/Android、Plugins/iOS)正确归档。
这是接入渠道 SDK、广告 SDK、统计 SDK 的标准目录约定:原生代码不进托管层,但必须随包发布,Plugins正是 Unity 约定的"原生库随包"入口。
5. Resources:随包打进的运行时资源
特性总结:
- 位置灵活:
Resources文件夹可以放在根目录,也可以放在子目录(如/xxx/xxx/Resources),多个Resources文件夹可以共存。 - 必进包体:
Resources下的资源不管你是否使用,都会被打进 .apk 或 .ipa,因此它是一把双刃剑——用起来方便,但容易让包体膨胀。
三类加载 API 的边界(务必分清):
| API | 使用时机 | 真机可用 | 路径要求 |
|---|---|---|---|
Resources.Load() | 编辑时与运行时均可 | 是 | 相对于Resources文件夹的路径 |
Resources.LoadAssetAtPath() | 编辑时 / 编辑器运行时 | 否 | "Assets/xx/xx.xxx",须带文件后缀名 |
AssetDatabase.LoadAssetAtPath() | 仅编辑时 | 否 | "Assets/xx/xx.xxx",须带文件后缀名 |
(原文档中写作Resource.Load,实为Resources.Load。)
实践建议:
- 开发期(PC 上)尽量使用
Resources.Load()或Resources.LoadAssetAtPath(),方便快捷; - 如果手机上选择"一部分资源打进 AssetBundle,一部分资源用
Resources.Load()"的混合方案,那么在自动化打包时,可以在打包前用AssetDatabase.MoveAsset()把已经打成 AssetBundle 的原始文件从Resources文件夹下移动出去再打包,这样打出的运行包就不会包含多余文件;打包完成后再把移动出去的文件移回原位。这一招能在保留Resources便利性的同时,避免重复资源进包。
6. StreamingAssets:不压缩、只读的随包目录与热更新基石
特性总结:
- StreamingAssets 下的资源会全部打包进 .apk / .ipa;
- 与
Resources的区别是:Resources会压缩文件,而 StreamingAssets 不压缩、原封不动地打包进去; - 它是一个只读目录:程序运行时只能读、不能写;
- 各平台路径不同,统一用
Application.streamingAssetsPath获取,Unity 会根据当前平台自动返回对应路径。
各平台路径对照(常见形态):
| 平台 | StreamingAssets 实际路径 |
|---|---|
| Windows / macOS 编辑器 | 项目目录/Assets/StreamingAssets |
| Android | jar:file://.../xxx.apk!/assets(压缩包内 assets) |
| iOS | 应用包内的Data/Raw目录 |
热更新标准做法(原文核心流程):
- 将一部分初始 AssetBundle放在
StreamingAssets目录下,随安装包发布; - 运行时把这些初始 AssetBundle 拷贝到
Application.persistentDataPath目录下; - 当有 AssetBundle 更新时,从服务器下载新包,覆盖
persistentDataPath下对应的旧文件; - 后续加载优先从
persistentDataPath取最新版本,StreamingAssets仅作为首次安装的种子数据。
两个关键认知:
Application.persistentDataPath是应用程序的沙盒目录,打包之前这个目录是不存在的,直到应用在手机上安装完毕才被系统创建;- 由于 StreamingAssets 资源不压缩,会比较占空间。例如应用本体装在手机上占 100M,又在 StreamingAssets 放了 100M 的 AssetBundle,那么安装后整体占用约为 200M——规划包体时要把它计入成本。
7. 仓库源码佐证:StreamingAssets 在热更新工程中的真实用法
上述理论在本仓库的 HotUpdate 系列工程中有大量真实落地代码,可直接对照阅读。
7.1 路径常量的平台差异处理
HotUpdate/AssetBundleDemo/Assets/Scripts/AssetBundleMgr.cs#L12-L19 定义了三条路径常量,正是对"StreamingAssets 各平台路径不同"的工程化封装:
public static readonly string streamingAssetPath = Application.streamingAssetsPath; public static readonly string persistentDataPath = Application.persistentDataPath; public static readonly string wwwStreamingAssetPath = #if UNITY_ANDROID Application.streamingAssetsPath; // Android 上 streamingAssetsPath 本身就是可被 WWW 识别的路径 #else "file://" + Application.streamingAssetsPath; // 其他平台需要手动补 file:// 前缀 #endif可见,即便在非 Android 平台,直接拿Application.streamingAssetsPath拼 WWW 地址也需要补协议头,这就是文档所说"各平台路径不同、务必用统一 API 获取"的实战含义。
7.2 从 StreamingAssets 与 persistentDataPath 双向加载
同一文件 AssetBundleMgr.cs#L67-L100 分别提供:
LoadFromStreamingAssetPath:从随包目录加载(同步);LoadFromPersistantDataPath:从沙盒目录加载(同步);- 以及对应的两个异步版本,
LoadAssetBundleAsync(Path.Combine(...))。
这正好对应上文"初始 bundle 放 StreamingAssets,更新后覆盖 persistentDataPath"的双目录设计。
7.3 打包输出直接指向 StreamingAssets
HotUpdate/AssetBundleDemo/Assets/Scripts/Editor/BundleHelper.cs#L25 中abOutputPath = Application.streamingAssetsPath,即打包脚本把 AssetBundle 直接输出到 StreamingAssets 目录,运行时再从这里读取初始资源。
7.4 Manifest 加载与依赖管理的固定写法
HotUpdate/AssetBundleFramework/Assets/Scripts/Manager/BundleManager.cs#L27-L28 将local_Path设为Application.streamingAssetsPath、deposit_DownFilePath设为persistentDataPath下的下载目录;BundleManager.cs#L63-L76 则展示了从StreamingAssets加载StreamingAssets(主 Manifest 的 bundle 名)并解析AssetBundleManifest、再递归加载依赖的完整链路——这是"初始 AssetBundle 放在 StreamingAssets"这一策略的标准读法。
仓库中 HotUpdate/AssetBundleDemo/Assets/StreamingAssets/ 目录下真实存放着main、start、uiloginpanel等 bundle 及对应的.manifest文件,可以直接打开验证目录结构与打包产物形态。
8. 结语:一张表记住六类特殊文件夹
| 文件夹 | 位置要求 | 是否进发布包 | 关键 API / 特性 |
|---|---|---|---|
Editor | 根目录或任意子目录 | 否 | 仅编辑器代码 / 工具脚本 / 编辑期 DLL |
Editor Default Resources | 仅 Project 根目录(注意空格) | 否 | EditorGUIUtility.Load |
Gizmos | 根目录下约定位置 | 否(仅编辑期图标) | Gizmos.DrawIcon、OnDrawGizmos、Inspector Select Icon |
Plugins | 按平台分子目录 | 是(原生库随包) | .so/.jar/.a |
Resources | 根目录或任意子目录 | 是(无论用不用) | Resources.Load(运行时);Resources.LoadAssetAtPath/AssetDatabase.LoadAssetAtPath(仅编辑期);打包前可用AssetDatabase.MoveAsset移出已打 bundle 的源文件 |
StreamingAssets | 根目录 | 是(不压缩原样打包,只读) | Application.streamingAssetsPath;与persistentDataPath配合做资源热更新 |
在 Doc/Unity手游开发中所有特殊的文件夹.md 原文基础上,本文结合仓库 HotUpdate 下的真实 AssetBundle 工程补全了路径平台差异、加载 API 边界、打包输出与 Manifest 依赖管理的源码级细节。规划包体与资源热更架构时,把这六类文件夹的边界吃透,可以避免"Resources 塞满导致包体膨胀""Editor 代码误进包""StreamingAssets 路径写死导致平台兼容崩溃"等经典坑。
- 示例工程
【免费下载链接】Unity3DTraining
【Unity杂货铺】unity大杂烩~
相关推荐
AssetRipper Unity资源提取实战指南:三步把游戏模型、贴图与音频导入自己的工程
AssetRipper Unity资源提取实战指南:三步把游戏模型、贴图与音频导入自己的工程 AssetRipper 是一款开源的 Unity 资源提取工具,它
开发工具逆向工程游戏开发Unity3DTraining项目深度解析:Unity游戏开发的百科全书
Unity3DTraining项目深度解析:Unity游戏开发的百科全书 Unity3DTraining项目是一个综合性的Unity游戏开发知识库,采用模块化架
示例工程Unity 编辑器拓展实战指南:基于 Unity3DTraining 仓库的窗口管理、节点编辑器与资源管线开发
Unity 编辑器拓展实战指南:基于 Unity3DTraining 仓库的窗口管理、节点编辑器与资源管线开发 本文以 Unity3DTraining 仓库 U
示例工程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考