大家在 Unity 里做项目是不是经常看到这样的 Hierarchy 和 Project 面板Cube Cube (1) Cube (2) New Material New Material (1) Sphere (2) (3)一开始觉得没什么资源多了以后就彻底乱套美术不知道给哪个材质加贴图程序找不到自己刚导入的模型策划改完场景根本认不出哪个是哪个。更难受的是一个“New Material (5)”被六个预制体引用谁也不敢删。最近在整理项目资源时我专门把团队资源命名规范做了一次系统化梳理顺手做了一套资源检查工具。本文就把 Unity 资源命名这块的完整经验整理出来从命名规则、目录结构再到编辑器自动化检查一次性讲透新手可以直接拿来规范自己的项目有经验的同学也可以参考里面的检查工具思路。1. 为什么说 Unity 资源命名是项目工程的“地基”1.1 Unity 默认命名方式为什么靠不住Unity 新建对象时默认名字就是GameObject、Cube、Sphere、New Material。当你重复创建同类型资源Unity 会自动追加(1)、(2)这样的数字后缀。这个自动命名机制本身没有问题它只是为了避免同名冲突。但问题在于资源一旦多了Cube (7)根本看不出它放在哪个场景、代表什么物体。同名资源被多个预制体引用后你在 Project 窗口里搜索New Material一下子出来十几个根本不敢乱删因为不知道哪个被引用。版本管理时Map_001、Map (2)、Map_final_最终版这类名字会让你无法快速定位版本差异。从商店或第三方工具导入的资源命名风格五花八门混进项目后极易出现重复或覆盖。简单说Unity 默认命名只解决“不重名”不解决“可读、可查、可维护”。项目早期还能靠脑子记等到十几个场景、上千个资源的时候谁都记不住。1.2 不规范命名引发哪些真实问题我整理了几类高频问题大家在真实项目里大概率都遇到过问题现象典型场景排查成本资源重复导入两个人同时导入New Material后导入的覆盖了先导入的低素材认领困难美术改了Material (3)程序员不知道对应哪个 UI 界面中预制体引用丢失重命名后没同步引用导致预制体材质丢失高场景定位混乱场景里全是Cube (1) (2)无法通过名字找到逻辑节点高SVN/Git 冲突频繁多人同时修改同名资源每次合并都在处理冲突中上面这些问题的根因都是没有建立一套从“创建”到“引用”全环节可控的命名体系。1.3 命名规范的本质是什么命名规范不是“规定怎么写好看”而是解决三类问题唯一性通过规则保证资源在整个项目内唯一不会因为同名产生覆盖或冲突。可读性从资源名字能快速判断出它的类型、归属模块、用途。可检索性命名中包含的关键字足够稳定通过搜索就能快速筛选。只要这三个目标达成资源再多也不会失控。2. 环境准备与版本说明在开始实践前先说明本文涉及的环境和版本情况。Unity 版本本文示例以 Unity 2021 LTS 和 Unity 2022 LTS 为主编辑器脚本使用UnityEditor命名空间较早的 2019/2020 版本同样适用。脚本语言C#使用 Unity 内置的 Editor 脚本机制不需要额外安装第三方插件。操作系统Windows / macOS 均可路径分隔符在代码中统一使用Path.Combine或/处理。示例项目结构一个空 Unity 项目仅包含Assets目录和少量资源文件。自动化检查方案使用MenuItem加静态函数扫描资源不依赖第三方资源检查工具。如果你的 Unity 版本较旧某些 API 可能需要微调本文会标注核心 API 的用途方便你按实际版本适配。3. 命名规则核心拆解3.1 常见命名格式总览目前比较通用的资源命名格式是“前缀 名称 后缀”。一个标准命名可以拆成四段[类型前缀]_[模块/用途]__[名称]_[版本或序号]具体含义字段示例说明类型前缀T_、M_、V_、S_表示资源类型如 Texture、Material、VFX、Shader模块/用途UI_、Char_、Env_、FX_表示资源所属模块如 UI、角色、环境、特效名称BtnStart、Hero_Knight描述资源具体内容按功能或对象名命名后缀_01、_v2、_HD表示版本、序号或附加状态例如T_UI_BtnStart_01.png M_Char_HeroKnight_HD.mat V_Env_ForestFire_01.prefab S_FX_Explosion_Basic.shader这种命名方式的好处很明显前三位就能知道这个资源是什么、属于哪个模块。搜索时按前缀过滤结果极快。不同模块之间天然隔离不容易重名。版本后缀避免“最终版”“最终版2”这类命名。3.2 类型前缀设计前缀是命名体系里最重要的一环。推荐按资源类型固定前缀团队内保持一致。我整理的常见前缀表如下资源类型前缀示例纹理/贴图T_T_UI_BtnStart.png材质M_M_Char_HeroKnight.mat预制体V_V_Env_ForestTree_01.prefab特效FX_FX_Attack_FireSlash.prefab动画A_A_Player_Run.fbx动画控制器AC_AC_Player_Locomotion.controller着色器S_S_Toon_Basic.shader脚本C_C_PlayerController.cs音频AU_AU_BGM_MainTheme.mp3UI 图集UI_UI_MainMenu_BtnAtlas.spriteatlas场景SC_SC_Level_01.unity注意脚本命名比较特殊很多团队直接用 PascalCase 命名 C# 文件因为类名需要和文件名保持一致。如果你用C_PlayerController.cs类名必须写成C_PlayerController这在 C# 里合法但不符合社区通用习惯。更推荐的做法是脚本类名使用 PascalCase例如PlayerController.cs。配置、数据类资源使用Data_或Config_前缀。具体是否使用C_前缀建议团队内部统一后再执行。3.3 文件重命名后引用会怎样这是很多人不敢重命名的原因在 Unity 里直接改资源文件名会不会导致预制体、场景、材质引用丢Unity 自带一个比较重要的机制Unity 使用.meta文件记录资源的 GUID全局唯一标识符。只要你是在 Unity 编辑器内重命名文件而不是在操作系统资源管理器中改名Unity 会重新生成 meta 文件内容并更新依赖引用。换句话说在 Unity 里重命名 安全操作 在 Windows/macOS 中改名 高危操作在操作系统层面改名或移动文件Unity 会认为旧文件被删除、新文件被导入所有引用旧 GUID 的资源就会丢失引用。很多人“一改资源名所有材质全丢”的问题基本都是在系统文件管理器里操作的。所以做资源整理时一定要通过 Unity 的 Project 窗口操作。3.4 目录结构配合命名规则命名规则解决“单个资源叫什么”目录结构解决“资源放在哪里”。两者配合才有意义。推荐目录结构Assets/ ├── Art/ │ ├── Characters/ │ │ ├── Knight/ │ │ │ ├── Textures/ │ │ │ ├── Materials/ │ │ │ └── Prefabs/ │ ├── Env/ │ │ ├── Forest/ │ │ └── City/ │ └── FX/ ├── Scripts/ │ ├── Player/ │ ├── UI/ │ └── Manager/ ├── UI/ │ ├── Atlas/ │ └── Prefabs/ ├── Audio/ │ ├── BGM/ │ └── SFX/ └── Scenes/资源命名里已经带前缀目录可以按模块划分不需要再出现复数层级。比如一个骑士角色的贴图路径为Assets/Art/Characters/Knight/Textures/T_Char_Knight_Body.png层级负责模块归属前缀负责类型识别两者独立又互补。4. 完整实战案例用编辑器脚本自动检查资源命名命名规范理念再好靠人肉检查总会漏。更有效的做法是把规则写成编辑器脚本一键扫描整个 Assets 目录自动标记不符合规范的资源。下面实现一个完整的资源命名检查工具。4.1 创建编辑器脚本目录在 Unity 项目中创建Assets/Editor/ResourceNamingChecker.csUnity 中所有 Editor 脚本必须放在名为Editor的文件夹下编译后才会进入编辑器程序集。4.2 检查目标设计这个工具检查三类问题文件名没有按照前缀_模块_名称三段式规则命名。文件包含空格、中文括号、全角字符等不推荐字符。文件重名排除不同目录下的同名资源。检查规则我们定义为文件名必须匹配一个三级前缀结构由下划线连接前缀_模块_名称前缀从允许列表中取值。允许列表可以维护到编辑器的静态配置区域。4.3 核心代码实现下面是完整的ResourceNamingChecker.cs// 文件路径Assets/Editor/ResourceNamingChecker.cs using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.RegularExpressions; using UnityEditor; using UnityEngine; public class ResourceNamingChecker { // 允许的资源扩展名列表可按项目需求调整 private static readonly string[] ResourceExtensions new string[] { .prefab, .mat, .png, .jpg, .tga, .fbx, .anim, .controller, .asset, .wav, .mp3, .ogg, .shader, .spriteatlas, .unity }; // 允许的命名前缀对应资源类型 private static readonly string[] AllowedPrefixes new string[] { T_, M_, V_, FX_, A_, AC_, S_, C_, AU_, UI_, SC_ }; // 不建议出现在文件名中的字符 private static readonly string ForbiddenCharsPattern [\s\(\)【】\[\]]; // 三段式命名正则前缀_模块_名称 private static readonly string NamePattern ^[A-Za-z0-9]_[A-Za-z0-9]_[A-Za-z0-9]$; [MenuItem(Tools/资源检查/检查命名规范)] public static void CheckAllAssetNames() { string[] guids AssetDatabase.FindAssets(, new[] { Assets }); Liststring errors new Liststring(); Liststring warnings new Liststring(); Dictionarystring, Liststring duplicateMap new Dictionarystring, Liststring(); int totalCount 0; int skipCount 0; foreach (string guid in guids) { string assetPath AssetDatabase.GUIDToAssetPath(guid); string fileName Path.GetFileName(assetPath); string extension Path.GetExtension(assetPath); if (extension .meta) continue; // 只检查项目关心的资源类型 if (!ResourceExtensions.Contains(extension)) continue; totalCount; string nameWithoutExt Path.GetFileNameWithoutExtension(assetPath); // 场景文件单独处理场景名通常不带前缀 if (extension .unity) { if (!Regex.IsMatch(nameWithoutExt, ^SC_[A-Za-z0-9]_[A-Za-z0-9]$)) { warnings.Add($场景文件未使用 SC_ 前缀规范{assetPath}); } continue; } // 检查禁用字符 if (Regex.IsMatch(nameWithoutExt, ForbiddenCharsPattern)) { errors.Add($文件名包含空格或全角括号等字符{assetPath}); } // 检查三段式命名 bool hasAllowedPrefix AllowedPrefixes.Any(p nameWithoutExt.StartsWith(p, System.StringComparison.Ordinal)); if (!hasAllowedPrefix) { errors.Add($资源缺少合法类型前缀{assetPath}); } else if (!Regex.IsMatch(nameWithoutExt, NamePattern)) { errors.Add($资源命名不符合 前缀_模块_名称 格式{assetPath}); } // 统计重名资源重名判断以不含扩展名的文件名为准 if (duplicateMap.ContainsKey(nameWithoutExt)) { duplicateMap[nameWithoutExt].Add(assetPath); } else { duplicateMap[nameWithoutExt] new Liststring { assetPath }; } } // 筛查真正重名的资源文件名相同且不是场景文件 Liststring duplicateErrors new Liststring(); foreach (var pair in duplicateMap) { if (pair.Value.Count 1) { duplicateErrors.Add($存在同名资源 {pair.Key}{string.Join(, , pair.Value)}); } } // 输出结果 if (errors.Count 0 duplicateErrors.Count 0 warnings.Count 0) { Debug.Log($[资源检查] 检查通过共扫描 {totalCount} 个资源无命名问题。); return; } Debug.LogWarning($[资源检查] 扫描 {totalCount} 个资源发现 {errors.Count} 个错误、{duplicateErrors.Count} 个重名、{warnings.Count} 个警告。); foreach (string err in errors) { Debug.LogError([资源命名错误] err); } foreach (string err in duplicateErrors) { Debug.LogError([资源命名重名] err); } foreach (string warning in warnings) { Debug.LogWarning([资源命名警告] warning); } } // 增加一个全自动选择不符合规范的资源方便快速定位 [MenuItem(Tools/资源检查/定位命名异常资源)] public static void SelectInvalidAssets() { string[] guids AssetDatabase.FindAssets(, new[] { Assets }); ListObject invalidAssets new ListObject(); foreach (string guid in guids) { string assetPath AssetDatabase.GUIDToAssetPath(guid); string extension Path.GetExtension(assetPath); if (extension .meta) continue; if (!ResourceExtensions.Contains(extension)) continue; string nameWithoutExt Path.GetFileNameWithoutExtension(assetPath); bool hasAllowedPrefix AllowedPrefixes.Any(p nameWithoutExt.StartsWith(p, System.StringComparison.Ordinal)); if (!hasAllowedPrefix || Regex.IsMatch(nameWithoutExt, ForbiddenCharsPattern)) { Object asset AssetDatabase.LoadAssetAtPathObject(assetPath); if (asset ! null) { invalidAssets.Add(asset); } } } if (invalidAssets.Count 0) { Selection.objects invalidAssets.ToArray(); EditorUtility.DisplayDialog(资源检查, $已选中 {invalidAssets.Count} 个命名异常资源请在 Project 窗口中查看, 确定); } else { EditorUtility.DisplayDialog(资源检查, 未发现命名异常资源, 确定); } } }这段代码里几个关键点说明一下AssetDatabase.FindAssets可以遍历Assets目录下的所有资源 GUID。Path.GetFileName和Path.GetFileNameWithoutExtension用于提取文件名。正则表达式^[A-Za-z0-9]_[A-Za-z0-9]_[A-Za-z0-9]$限制三段都必须由字母或数字组成。编辑器菜单用MenuItem特性挂在Tools菜单下点击即可运行。Selection.objects invalidAssets.ToArray()能直接在 Project 窗口选中所有异常资源方便统一处理。4.4 运行与常见报错说明打开 Unity在顶部菜单栏点击Tools - 资源检查 - 检查命名规范Console 面板会输出检查结果。如果你导入的资源里有New Material (1).mat运行后会看到[资源命名错误] 资源命名不符合 前缀_模块_名称 格式Assets/Materials/New Material (1).mat [资源命名重名] 存在同名资源 New MaterialAssets/Materials/New Material.mat, Assets/Materials/New Material (1).mat如果脚本提示ISerialization或其他编译错误大概率是脚本里使用了当前 Unity 版本不存在的 API。上面的代码只用到了非常稳定和基础的 UnityEditor API一般不会出问题。4.5 扩展一键重命名为规范格式人肉修改几十个文件名依然容易出错我们可以在检查工具里加一个批量修正功能。下面这个示例演示如何把New Material (1)自动改为M_Resource_NewMaterial_01// 追加到 ResourceNamingChecker.cs [MenuItem(Tools/资源检查/一键规范化材质命名)] public static void RenameMaterialsToStandard() { string[] guids AssetDatabase.FindAssets(t:Material, new[] { Assets }); int renamedCount 0; foreach (string guid in guids) { string assetPath AssetDatabase.GUIDToAssetPath(guid); string directory Path.GetDirectoryName(assetPath); string fileName Path.GetFileNameWithoutExtension(assetPath); // 跳过已经符合规范的命名 if (fileName.StartsWith(M_, System.StringComparison.Ordinal)) continue; // 清理非法字符去掉括号和空格保留字母数字 string cleanName Regex.Replace(fileName, [^A-Za-z0-9], ); if (string.IsNullOrEmpty(cleanName)) continue; string module General; string objectName cleanName; string sequence ; // 如果是带数字后缀的资源如 NewMaterial1将数字提取成序号 Match match Regex.Match(cleanName, ^(.*?)(\d)$); if (match.Success) { objectName match.Groups[1].Value; sequence _ match.Groups[2].Value; } string newName $M_{module}_{objectName}{sequence}.mat; if (newName Path.GetFileName(assetPath)) continue; string newPath Path.Combine(directory, newName); // 防止目标路径已存在同名文件 if (File.Exists(newPath)) continue; string error AssetDatabase.RenameAsset(assetPath, Path.GetFileNameWithoutExtension(newPath)); if (string.IsNullOrEmpty(error)) { renamedCount; Debug.Log($重命名成功{assetPath} - {newPath}); } else { Debug.LogWarning($重命名失败{assetPath}原因{error}); } } AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); Debug.Log($[资源检查] 材质批量重命名完成共修改 {renamedCount} 个资源。); }注意批量重命名脚本一定要在测试分支验证后再合入主工程。特别是被多个预制体引用的材质虽然 Unity 会同步引用但任何自动化改名操作都有风险建议先在副本项目上跑一遍。5. 常见问题与排查思路5.1 重命名导致材质和引用丢失问题现象常见原因解决思路改名后模型变紫色或材质丢失在系统文件管理器中重命名meta 文件 GUID 失效恢复旧名字回到 Unity Project 窗口重命名或把资源放回原路径后重新导入预制体所有组件引用全部丢失删除了旧资源再导入同名新文件GUID 变化不要删除旧资源用AssetDatabase.RenameAsset改名修改目录后贴图引用失效目录移动时未通过 Project 窗口操作在 Unity 内拖拽目录Unity 会自动更新引用外部移动目录后使用AssetDatabase.Refresh资源命名整理的底线原则是所有文件操作必须在 Unity 编辑器内完成。5.2 命名规范与第三方插件冲突第三方资源包里的文件名带有自己的前缀或没有前缀。强制全部改名会破坏插件内部的字段引用特别是 ScriptableObject 配置和序列化引用。推荐的策略是第三方资源保留在Assets/Plugins或Assets/ThirdParty目录不执行命名检查。主工程自有资源统一走规范。检查工具里通过目录黑名单跳过第三方目录。如果要给检查工具添加跳过目录可以在检查函数开头加入private static readonly string[] IgnoreFolders new string[] { Assets/ThirdParty, Assets/Plugins, Assets/AssetStoreTools };然后在循环内判断路径是否以这些目录开头是则跳过。5.3 中文字符命名问题有些团队资源用了中文名比如英雄_骑士_模型.fbx。在个人项目中能跑通但多人协作时要谨慎不同操作系统对中文文件名的编码兼容性不同。打包和热更新时可能导致路径不稳定。部分版本控制工具对中文路径处理有差异。从工程角度更推荐统一使用英文命名如果一定要用中文也建议只作为功能注释写在组件上不用于文件名。6. 最佳实践与工程建议6.1 命名规则应与美术和策划达成共识命名规范不是程序单方面规定美术、策划、音频都会参与资源生产。推动规范落地时建议做一件事把规则文档做成表格贴到项目 Wiki 或文档中心让大家生产资源时照表命名。下面是可以直接复用的文本模板Unity 资源命名规范 v1.0 1. 所有资源文件必须使用三段式命名前缀_模块_名称 2. 标准前缀参考表 纹理 T_ 材质 M_ 预制体 V_ 特效 FX_ 动画 A_ 动画控制器 AC_ 着色器 S_ 音频 AU_ UI图集 UI_ 场景 SC_ 3. 文件名禁止包含空格、中文括号、英文括号 4. 同名文件不允许出现在不同目录下 5. 场景文件统一 SC_Level_序号 6. 版本信息通过 _v2 后缀处理禁止“最终版”“新版”命名6.2 用命名规范倒逼目录沉淀当命名规范稳定后目录结构也会相对稳定。新资源只要按前缀和模块归类基本不会乱。我们项目里每个模块目录都会强制维护一份资源清单新成员入职直接看命名规范就能知道资源丢哪个目录。这里有一个注意点目录层数不是越多越好。超过四层的目录Unity 资源加载和工程遍历都会变慢。建议控制在Assets/模块/角色名/资源类型比如Assets/Art/Characters/Knight/Textures Assets/UI/Prefabs/MainMenu Assets/FX/Attack6.3 资源遍历性能优化现在再回到 Unity 资源加载本身。当项目变大后即使命名规范了也需要关注资源加载性能。几个实用建议图集尽量使用 Sprite Atlas而不是散图。常用资源在场景加载时使用Resources.Load或 Addressables 的异步接口。动态加载资源时避免频繁使用AssetDatabase.LoadAssetAtPath编辑器代码和生产代码要分离。如果需要在运行时动态加载资源按规范命名后可以用拼接路径的方式// 动态加载示例玩家界面按钮图标 string module UI; string buttonName BtnStart; string path $Art/{module}/Textures/T_{module}_{buttonName}.png; Sprite icon Resources.LoadSprite(path); if (icon ! null) { startButton.image.sprite icon; } else { Debug.LogWarning($图标资源未找到{path}); }这种写法的前提就是资源命名和目录结构双重规范否则路径根本拼不出来。6.4 编辑器检查工具纳入 CI 流程资源检查工具还可以更进一步让它支持命令行调用。Unity 提供了-executeMethod参数可以在 CI 脚本里自动执行# 在命令行中运行 Unity 资源命名检查示例按你的 Unity 安装路径调整 /Applications/Unity/Hub/Editor/2021.3.16f1/Unity.app/Contents/MacOS/Unity \ -projectPath /path/to/your/project \ -batchmode \ -quit \ -executeMethod ResourceNamingChecker.CheckAllAssetNames \ -logFile check_result.log在 Windows 中对应的是Unity.exe -projectPath D:\YourProject -batchmode -quit -executeMethod ResourceNamingChecker.CheckAllAssetNames -logFile check_result.log执行后可以在 CI 平台的日志中检查错误输出如果有[资源命名错误]就中断构建强制提交者修复命名。6.5 安全与版本管理注意事项最后强调几个安全底线所有批量改名、批量移动目录操作先提交一次版本或备份再执行。在团队分支上跑自动化工具前确认当前代码库干净没有未提交的改动。不要在构建服务器上使用依赖弹窗的编辑器扩展批量命令要使用-batchmode。涉及关键预制体或主线场景的重命名建议分组执行改完一批运行一次游戏流程回归。7. 总结与下一步整理 Unity 资源命名说难不难说简单也不是一两条规则能解决的。本文从 Unity 默认命名机制的局限讲起解释了Cube (1)、New Material (2)这类资源名的危害然后给出了一套可直接落地的三段式命名规则和类型前缀表并说明目录结构如何与命名规则配合最后实现了一个完整的资源命名检查工具和批量重命名示例。你现在可以动手做三件事把本文的命名规范表复制到项目文档里和团队对一遍。创建Assets/Editor/ResourceNamingChecker.cs跑一次资源扫描看看项目里有多少异常命名资源。在工具输出结果中挑一个模块做试点整理验证 Unity 重命名机制下引用是否全部保持正常。整理完一个模块后你会明显感觉到场景 Search 效率、团队协作效率、美术和程序的沟通成本都会有不小变化。资源命名这件事越早规范越省心。