UE 命名规范
资产命名表格链接:UE5项目命名规则
在开发大型项目时,我们建议你在早期阶段为各类资产建立通用的命名规范。这样方便你和团队成员寻找文件,防止出现冲突或混淆。下述命名规范介绍了Epic Games如何对示例项目中的资产命名,以ICVFX制片测试为例:
[AssetTypePrefix]_[AssetName]_[Descriptor]_[OptionalVariantLetterOrNumber]
【资产类型】_【资产名称】_【资产用法/后缀】_【多个变体版本】
-
AssetTypePrefix
将表明资产的类型,详情请参阅下表。 -
AssetName
是资产的名称。 -
Descriptor
将提供资产的更多上下文,表明其用法。例如,纹理是正常贴图还是不透明度贴图。 -
OptionalVariantLetterOrNumber
是可选的,用于区分资产的多个版本或变体。
请考虑在你的项目中使用此命名规范,以便团队成员有多种途径来搜索内容浏览器中的资产。
0.禁止字符
除非是迫不得已,否则不要使用以下字符
- 任何形式的空格
- 反斜杠 \
- 不明符号 #!@$%
- 任何Unicode字符
应尽量使用以下字符
- ABCDEFGHIJKLMNOPQRSTUVWXYZ
- abcdefghijklmnopqrstuvwxyz
- 1234567890
- _
这样做的原因是,这将确保跨所有平台的所有数据在所有工具中有最大的兼容性,并有助于防止由于代码因为潜在的错误字符而导致奔溃
1.资产命名约定
符合命名约定的项目能够轻松地管理、搜索、解析和维护其资产。
大多数事物都带有前缀,前缀通常是资产类型的首字母缩写词,后跟下划线。
[AssetTypePrefix]_[AssetName]_[Descriptor]_[OptionalVariantLetterOrNumber]
【资产类型】_【资产名称】_【资产用法/后缀】_【多个变体版本】
所有的资产都应该有一个AssetName,用来辨别这是什么资产。
AssetName应由与这组资产相关的简短且易于识别的名称来确定。例如,如果你有一个名为Bob的角色,则Bob所有的资产的AssetName都应基于Bob。
OptionalVariantLetterOrNumber应该是原资产的变体命名:如Bob邪恶的皮肤:_Evil;复古的皮肤:_Retro
如果不能准确的判断变体名称,则可以使用序号进行编号:如:_01; _02; _03等等
image.png参考表:
2.内容目录结构
内容目录结构与资产名称同样重要。项目目录风格应当准守,如果违反要求,就会导致不必要的混乱。
2.1文件夹名称
这些是命名内容结构中任何文件夹的通用规则。
2.1.1始终使用 帕斯卡命名【PascalCase 】
PascalCase 是指以大写字母开头的名称,然后不使用空格,后续每个单词都以大写开头。例如:DeserEagle、RocketPistol和AseriesOfWords
2.1.2绝不使用空格
永远不要使用空格。空格会导致各种工程工具和批处理失败。
2.1.3切勿使用Unicode字符和其他符号
如果您的游戏角色之一被命名为“Zoë”,则其文件夹名称应为Zoe
. Unicode 字符可能比空格更糟糕,因为 UE4 的某些部分也不支持路径中的 Unicode 字符。
与此相关,如果您的项目有无法解释的问题并且您的计算机的用户名具有 Unicode 字符(即您的名字是 Zoë),则位于“我的文档”文件夹中的任何项目都会遇到此问题。 通常只需将您的项目移动到 D:\Project 之类的位置即可解决这些神秘问题。
在 a-z、A-Z 和 0-9 之外使用其他字符,例如 @、-、_、、、* 和 #,也可能导致在其他平台、源代码控制和较弱的工程工具上出现意外且难以跟踪的问题。
2.2为项目特定资产使用顶级文件夹
项目的所有资产都应存在于以项目命名的文件夹中。 例如,如果您的项目名为“Generic Shooter”,则其所有内容都应存在于 Content/GenericShooter 中。
Developers 文件夹不适用于您的项目所依赖的资产,因此不是项目特定的。 有关此内容的详细信息,请参阅开发人员文件夹。
使用这种方法有以下多种原因。
2.2.1不要全局资产
通常在代码风格指南中写到你不应该污染全局命名空间,这遵循相同的原则。当资产被允许存在于项目文件夹之外时,执行严格的结构布局通常会变得更加困难,因为不在文件夹中的资产会鼓励不必组织资产的不良行为。
每个资产都应该有一个目的,否则它不属于一个项目。如果资产是实验性测试并且不应被项目使用,则应将其放在 Developer 文件夹中。
2.2.2 减少迁移冲突
在处理多个项目时,如果团队对两个项目都有用,则通常会将资产从一个项目复制到另一个项目。发生这种情况时,执行复制的最简单方法是使用内容浏览器的迁移功能,因为它不仅会复制所选资产,还会复制其所有依赖项。
这些依赖项很容易让您陷入困境。如果两个项目的资产没有顶级文件夹,并且它们碰巧有类似名称或之前已迁移的资产,则新的迁移可能会意外擦除对现有资产的任何更改。
这也是 Epic 的 Marketplace 工作人员对提交的资产执行相同政策的主要原因。
迁移后,可以使用内容浏览器中的“替换引用”工具来安全地合并资产,增加了不属于项目顶级文件夹的资产的清晰度,这些资产显然正在等待合并。资产合并并完全迁移后,您的内容树中不应再有另一个顶级文件夹。此方法 100% 保证使发生的任何迁移完全安全。
2.2.2e1 主材料示例
例如,假设您在一个项目中创建了要在另一个项目中使用的主材料,因此您迁移了该资产。如果此资产不在顶级文件夹中,它的名称可能类似于 Content/MaterialLibrary/M_Master。如果目标项目还没有主材料,这应该没有问题。
随着一个或两个项目的工作进展,他们各自的主材料可能会因正常开发过程而更改为针对其特定项目量身定制。
例如,当一个项目的艺术家创建了一组很好的通用模块化静态网格物体,而有人想在第二个项目中包含该组静态网格物体时,就会出现问题。如果创建资产的艺术家按照指示使用基于 Content/MaterialLibrary/M_Master 的材质实例,则执行迁移时,之前迁移的 Content/MaterialLibrary/M_Master 资产很有可能发生冲突。
这个问题很难预测,也很难解释。迁移静态网格物体的人可能不是熟悉这两个项目的主材质开发的人,他们甚至可能不知道有问题的静态网格物体依赖于材质实例,而材质实例又依赖于主材质。然而,迁移工具需要整个依赖链才能工作,因此当它将这些资产复制到另一个项目时,它将被迫抓取 Content/MaterialLibrary/M_Master,它会覆盖现有资产。
正是在这一点上,如果两个项目的主材质以任何方式不兼容,您可能会破坏项目的整个材质库以及可能已经迁移的任何其他依赖项,仅仅是因为资产没有存储在顶级文件夹。静态网格的简单迁移现在变成了一项非常难看的任务。
2.2.3 添加样本、模板和市场内容无风险
对 2.2.2 的扩展,如果团队成员决定添加他们从市场购买的示例内容、模板文件或资产,只要您的项目的顶级文件夹被唯一命名,就可以保证这些新资产不会干扰你的项目。
您不能相信市场内容完全符合顶级文件夹规则。存在许多资产,它们的大部分内容位于顶级文件夹中,但也可能修改了 Epic 示例内容以及污染全局 Content 文件夹的级别文件。
遵守 2.2 时,您可能遇到的最严重的市场冲突是两个市场资产都具有相同的 Epic 示例内容。如果您的所有资产都位于项目特定文件夹中,包括您可能已移入文件夹的示例内容,那么您的项目将会混乱不堪。
2.2.4 DLC、子项目、补丁易维护
如果您的项目计划发布 DLC 或有多个与之关联的子项目,这些子项目可能会被迁移出去或根本没有在构建中完成,那么与这些项目相关的资产应该有自己单独的顶级内容文件夹。这使得烘焙 DLC 与主要项目内容分开变得更加容易。子项目也可以轻松迁移进出。如果您需要更改资产的材质或在补丁中添加一些非常具体的资产覆盖行为,您可以轻松地将这些更改放在补丁文件夹中并安全地工作,而不会破坏核心项目。
2.3 使用 Developers 文件夹进行本地测试
在项目的开发过程中,团队成员拥有一种“沙盒”是很常见的,他们可以在其中自由地进行实验,而不会冒核心项目的风险。因为这项工作可能正在进行中,这些团队成员可能希望将他们的资产放在项目的源代码控制服务器上。并非所有团队都需要使用 Developer 文件夹,但确实使用它们的团队通常会遇到提交到源代码管理的资产的常见问题。
团队成员很容易意外使用尚未准备好使用的资产,一旦这些资产被移除就会导致问题。例如,艺术家可能正在对一组模块化的静态网格进行迭代,并且仍在努力使它们的大小和网格捕捉正确。如果世界构建者在主项目文件夹中看到这些资产,他们可能会在整个关卡中使用它们,而不知道它们可能会受到难以置信的更改和/或删除。这导致团队中的每个人都需要进行大量的重新工作来解决。
如果将这些模块化资产放在 Developer 文件夹中,那么世界构建者就不应该有使用它们的理由,整个问题就永远不会发生。内容浏览器具有特定的视图选项,可以隐藏开发人员文件夹(默认情况下它们是隐藏的),从而在正常使用情况下不会意外使用开发人员资产。
一旦资产准备好使用,艺术家只需将资产移动到项目特定的文件夹并修复重定向器。这实质上是将资产从实验“提升”到生产。
2.4 所有 Map 文件都属于一个名为 Maps 的文件夹*
地图文件非常特殊,每个项目都有自己的地图命名系统是很常见的,尤其是当它们使用子关卡或流式关卡时。无论具体项目采用何种地图组织系统,所有级别都应属于/Content/Project/Maps。
能够告诉某人打开特定地图而不必解释它在哪里。这是一个很好的节省时间的方式。关卡通常位于 Maps 的子文件夹中,例如 Maps/Campaign1/ 或 Maps/Arenas,但这里最重要的是它们都存在于 /Content/Project/Maps 中。
2.5 为关键蓝图和其他资产使用核心文件夹
将 /Content/Project/Core 文件夹用于对项目工作绝对重要的资产。例如,基本 GameMode、Character、PlayerController、GameState、PlayerState 和相关的蓝图应该存在于此。
让其他团队成员非常明确“不要碰这些”。非工程师应该很少有理由进入 Core 文件夹。遵循良好的代码结构风格,设计师应该在暴露功能的子类中进行游戏性调整。关卡设计师应该在指定文件夹中使用预制蓝图,而不是潜在地滥用基类。
例如,如果您的项目需要可放置在关卡中的拾取物,则 Core/Pickups 中应该存在一个基本 Pickup 类,用于定义拾取物的基本行为。特定的拾取物(例如生命值或弹药)应存在于 /Content/Project/Placeables/Pickups/ 等文件夹中。游戏设计师可以随意定义和调整此文件夹中的拾取物,但他们不应触及Core/Pickups ,因为它们可能会无意中破坏整个项目中的拾取物。
2.6 不要创建名为 Assets 或 AssetTypes 的文件夹
【这条看个人情况处理】
2.6.1 创建一个名为 Assets 的文件夹是多余的
所有资产都是资产。
2.6.2 创建名为 Meshes、Textures 或 Materials 的文件夹是多余的
所有资产名称均以资产类型命名。这些文件夹仅提供冗余信息,并且可以使用内容浏览器提供的强大且易于使用的过滤系统轻松替换这些文件夹的使用。
只想查看 Environment/Rocks/ 中的静态网格?只需打开静态网格过滤器。如果所有资产都正确命名,它们也将按字母顺序排序,而不考虑前缀。想要同时查看静态网格物体和骨架网格物体?只需打开两个过滤器。这消除了在内容浏览器的树形视图中可能必须按住 Control 单击选择两个文件夹的需要。
这也扩展了资产的完整路径名,但收益甚微。静态网格的 SM_ 前缀只有两个字符,而 Meshes/ 是七个字符。
不这样做还可以防止有人将静态网格或纹理放入 Materials 文件夹中。
2.7 超大型资产集拥有自己的文件夹布局
某些资产类型具有大量相关文件,其中每个资产都有其独特的用途。 最常见的两个是动画和音频资产。 如果您发现自己拥有 15 个以上的资产属于一起,那么它们应该是一起的。
例如,在多个角色之间共享的动画应位于 Characters/Common/Animations 中,并且可能具有诸如 Locomotion 或 Cinematic 之类的子文件夹。
这不适用于纹理和材质等资产。 如果岩石数量较多,Rocks 文件夹中通常会有大量纹理,但这些纹理通常只与少数特定岩石相关,应适当命名。 即使这些纹理是材质库的一部分。
2.8 材质库
如果您的项目使用不属于任何资产子集的主材质、分层材质或任何形式的可重用材质或纹理,则这些资产应位于 Content/Project/MaterialLibrary 中。
通过这种方式,所有“全局”材质都有一个可以存在的地方并且很容易找到。
这也使得在项目中实施“仅使用材质实例”策略变得异常容易。所有艺术家和资产都应该使用材质实例,存在的唯一常规材质资产在此文件夹中。您可以通过在任何不是 MaterialLibrary 的文件夹中搜索基础材质来轻松验证这一点。
MaterialLibrary 不必只由材质组成。共用的纹理、材质功能和其他此类性质的内容也应存储在此处以及指定其预期用途的文件夹中。例如,通用噪声纹理应位于 MaterialLibrary/Utility。
任何测试或调试材料都应该在 MaterialLibrary/Debug 中。这允许在交付之前轻松地从项目中剥离调试材料,并且在显示参考错误时,如果生产资产正在使用它们,则非常明显。
2.9 不要有空文件夹
根本不应该有任何空文件夹。 它们使内容浏览器变得混乱。
如果您发现内容浏览器有一个无法删除的空文件夹,您应该执行以下操作:
确保您使用的是源代码管理。 立即在您的项目上运行 Fix Up Redirectors。 导航到磁盘上的文件夹并删除其中的资产。 关闭编辑器。 确保您的源代码控制状态是同步的(即,如果使用 Perforce,请在您的内容目录上运行 Reconcile Offline Work) 打开编辑器。 确认一切仍按预期工作。 如果没有,请还原,找出问题所在,然后重试。 确保该文件夹现已消失。 向源代码管理提交更改。
3.静态网格体
本节将重点介绍静态网格资产及其内部结构。
3.1 静态网格体 UV
如果出现错误的 UV 并且您似乎无法追踪它,请在项目的 Saved/Logs 文件夹中打开生成的 .log 文件,以获取有关它失败原因的确切详细信息。
3.1.1 所有网格都必须有 UV
很简单。所有网格,无论它们如何使用,都不应缺少 UV。
3.1.2 所有网格都不能有光照贴图的重叠 UV
很简单。所有网格,无论它们如何使用,都应该具有有效的非重叠光照UV。
3.2 应正确设置 LOD
这是基于每个项目的主观检查,但作为一般规则,可以在不同距离看到的任何网格都应具有适当的 LOD。
3.3 模块化无插槽资产应该可无缝地组合
这是基于每个资产的主观检查,但是任何模块化无插槽资产都应可以无缝地组合在一起。
是基于 2 网格的幂还是基于 10 网格的捕捉取决于项目。但是,如果您正在为市场创作模块化无插槽资产,Epic 的要求是,当网格设置为 10 个单位或更大时,它们必须无缝。
3.4 所有网格都必须有碰撞
无论资产是否将用于关卡中的碰撞,所有网格都应定义正确的碰撞。这有助于引擎处理边界计算、遮挡和照明等问题。
3.5 所有网格都应正确缩放
这是基于每个项目的主观检查,但是所有资产都应正确缩放到其项目。关卡设计师或蓝图工作不应该让他们在编辑器中确认和调整网格的比例。引擎中的缩放网格应被视为缩放覆盖,而不是缩放校正。
4.纹理
本节将重点介绍纹理资产及其内部结构。
4.1 尺寸应是 2 的幂
除 UI 纹理外,所有纹理的尺寸都必须是 2 的幂的倍数。纹理不必是方形的。
例如,128x512、1024x1024、2048x1024、1024x2048、1x512。
4.2 纹理密度要均匀
所有纹理的大小都应适合其标准用例。适当的纹理密度因项目而异,但该项目中的所有纹理都应具有一致的密度。
例如,如果一个项目的纹理密度是每1个单位8个像素,则打算应用于100x100单位的纹理应该是 1024x1024,因为这是与项目的纹理密度匹配的最接近的 2 次幂。
4.3 纹理不应大于 8192
任何纹理的尺寸都不应超过 8192,除非您有非常明确的理由这样做。通常,使用这么大的纹理只是浪费资源。
4.4 纹理应该正确分组
每个纹理都有一个用于 LODing 的 Texture Group 属性,并且应该根据其使用情况正确设置。例如,所有 UI 纹理都应属于 UI 纹理组。
5.Niagara
本节将重点介绍 Niagara 资产及其内部结构。
5.1 永远没有空格
如开头所述,标识符中禁止使用空格和所有空白字符。 对于 Niagara 系统来说尤其如此,因为当在 Niagara 中使用 HLSL 或其他脚本编写方式并尝试引用变量时,它也会使处理事情变得更加困难。
6.关卡/地图
本节将重点介绍关卡资产及其内部结构。
6.1 没有错误或警告
所有关卡都应以零错误或警告加载。如果一个关卡加载有任何错误或警告,应立即修复它们以防止连锁问题。
您可以使用控制台命令“map check”在编辑器中的打开关卡上运行地图检查。
请注意:底层在这方面比编辑器目前更严格,并且会捕获编辑器自行解决的加载错误。
6.2 应构件光照
在开发过程中,关卡偶尔没有构建照明是正常的。但是,在进行测试/内部/运输构建或任何要分发的构建时,应始终构建照明。
6.3 没有玩家可见的 Z 战斗
关卡不应在玩家可见的所有区域中出现任何 z-fighting。
6.4 市场特定规则
如果一个项目要在 UE4 Marketplace 上出售,它必须遵循这些规则。
6.4.1 概述关卡
如果您的项目包含应可视化或演示的资产,则您的项目中必须有一个包含名称“Overview”的地图。
如果是可视化资产,则此概览图应根据 Epic 的指南进行设置。
例如,InteractionComponent_Overview。
6.4.2 演示关卡
关卡示例或附带某种教程的资产,则您的项目中必须有一个包含名称“Demo”的地图。此关卡还应包含以某种形式说明如何使用您的项目的文档。请参阅 Epic 的内容示例项目以获取有关如何执行此操作的良好示例。
如果您的项目是游戏机制或其他形式的系统而不是艺术资源包,这可以与您的“Overview”地图相同。
例如,InteractionComponent_Overview_Demo、ExplosionKit_Demo。
7.蓝图
本节将重点介绍蓝图类及其内部结构。 如果可能,样式规则应符合 Epic 的编码标准。
记住:蓝图很容易犯错误,小心!
7.1 编译
所有蓝图都应以零警告和零错误进行编译。 您应该立即修复蓝图警告和错误,因为它们会迅速演变成非常可怕的意外行为。
不要将损坏的蓝图提交给源代码控制。 如果您必须将它们存储在源代码管理中,请将它们搁置。
坏的蓝图可能会导致以其他方式表现出来的问题,例如损坏的引用、意外行为、Cook失败和频繁的不必要的重新编译。 一个坏的蓝图有能力破坏你的整个游戏。
7.2 变量
变量和属性这两个词可以互换使用。
7.2.1 命名
7.2.1.1 名词
所有非布尔变量名称必须是清晰、明确和描述性的名词。
7.2.1.2 帕斯卡命名【PascalCase 】
所有非布尔变量都应采用 PascalCase 的形式。
例如:
Score
Kills
TargetPlayer
Range
CrosshairColor
AbilityID
7.2.1.3 布尔值使用 b前缀
所有布尔值都应以 PascalCase 命名,但以小写 b 为前缀。
示例:使用 bDead 和 bEvil,而不是 Dead 和 Evil。
UE4 蓝图编辑器知道不要在变量使用时不显示b。
7.2.1.4 布尔名称
①一般和独立状态信息 如果表示一般信息,所有布尔值都应尽可能命名为描述性形容词。不要包含将变量表述为问题的单词,例如 Is。这是为函数保留的。
示例:使用 bDead 和 bHostile 而不是 bIsDead 和 bIsHostile。
尽量不要使用动词,例如 bRunning。动词往往会导致复杂的状态。
②复杂状态 不要使用布尔值来表示复杂的状态。这使得状态添加和删除变得复杂并且不再易于阅读。请改用枚举。
示例:定义武器时,如果武器不能同时装填和装备,则不要使用 bReloading 和 bEquipping。定义一个名为 EWeaponState 的枚举,并改用一个名为 WeaponState 的具有此类型的变量。这使得向武器添加新状态变得更加容易。
示例:如果您还需要 bWalking 或 bSprinting,请不要使用 bRunning。这应该定义为具有明确定义的状态名称的枚举。
7.2.1.5 考虑的上下文关系
所有变量名称不得与其上下文断开联系,因为蓝图中的所有变量引用都将始终具有上下文关系。
参考一个名为 BP_PlayerCharacter 的蓝图。
坏的命名
PlayerScore
PlayerKills
MyTargetPlayer
MyCharacterName
CharacterSkills
ChosenCharacterSkin
所有这些变量都被冗余命名。提示该变量代表它所属的 BP_PlayerCharacter,但是变量的主体已经是 BP_PlayerCharacter了。
好的命名
Score
Kills
TargetPlayer
Name
Skills
Skin
7.2.1.6 不要包含基础类型名称
基础变量是以最简单的形式表示数据的变量,例如bool、int、float和枚举。
在使用蓝图时,string和vector被认为是基础变量,但它们在技术底层中不是基础的。
虽然向量由三个浮点数组成,但向量通常可以作为一个整体进行操作,旋转器也是如此。
不要将Text变量视为基础变量,它们会隐藏本地化功能。一串字符的基础类型是String,而不是Text。
基础变量的名称中不应包含其类型名称。
示例:使用 Score、Kills 和 Description 而不是 ScoreFloat、FloatKills、DescriptionString。
此规则的唯一例外是当变量表示要计算的“数量”时,并且使用不带变量类型的名称不易阅读时。
示例:围栏生成器需要生成 X 个柱子。将 X 存储在 NumPosts 或 PostsCount 中,而不是 Posts,因为 Posts 可能会解读为名为 Post 的变量类型的数组。
7.2.1.7 包括非基础类型名称
非基础变量或复杂变量是将数据表示为基础变量集合的变量。结构体、类、接口和具有隐藏行为(如文本和名称)的类型都符合此规则。
虽然基础变量类型的数组是变量列表,但数组不会改变变量类型的“基础性”。
这些变量应该包括它们的类型名称,同时仍然考虑它们的上下文关系。
如果一个类拥有一个复杂变量的实例,即如果一个 BP_PlayerCharacter 拥有一个 BP_Hat,它应该被存储为变量类型,不要修改为其他名称。
示例:使用 Hat、Flag 和 Ability 而不是 MyHat、MyFlag 和 PlayerAbility。
如果一个类不拥有一个复杂变量所代表的值,你应该使用一个名词和变量类型。
示例:如果 BP_Turret 能够以 BP_PlayerCharacter 为目标,它应该将其目标存储为 TargetPlayer,因为在 BP_Turret 的上下文中,它应该清楚它是对它不拥有的另一个复杂变量类型的引用。
7.2.1.8 数组
数组遵循与上述相同的命名规则,但应命名为复数名词。
示例:使用 Targets、Hats 和 EnemyPlayer,而不是 TargetList、HatArray、EnemyPlayerArray。
7.2.2 可编辑变量
所有可以安全更改其值以配置蓝图行为的变量都应标记为可编辑。
相反,所有不能安全更改或不应向设计人员公开的变量不应标记为可编辑,除非出于工程原因,必须将变量标记为在生成时公开。
不要随意将变量标记为可编辑。
7.2.2.1 工具提示
所有可编辑变量,包括那些标记为可编辑的变量
7.2.3 分类
如果一个类只有少量变量,则不需要类别。
如果一个类具有中等数量的变量 (5-10),则所有可编辑变量都应分配一个非默认类别。 一个常见的类别是 Config。
如果一个类有大量的变量,那么所有的可编辑变量都应该以 Config 类为基类,划分为子类。 不可编辑的变量应分类为描述其用途的描述性类别。
您可以使用管道字符 | 来定义子类别,即 Config | Animations。
示例:一组武器类变量可能组织为:
|-- Config
| |-- Animations
| |-- Effects
| |-- Audio
| |-- Recoil
| |-- Timings
|-- Animations
|-- State
|-- Visuals
7.2.4 变量访问级别
在 C++ 中,变量具有访问级别的概念。
Public:公共意味着类外的任何代码都可以访问该变量。
Protected :受保护意味着只有类和任何子类可以在内部访问此变量。
Private :私有意味着只有这个类,子类不可以访问这个变量。
蓝图目前没有定义的受保护访问概念。
将可编辑变量视为公共变量。 将不可编辑的变量视为受保护的变量。
7.2.4.1 私有变量
除非知道一个变量只能在它定义的类中访问,而不是子类,否则不要将变量标记为私有。 在变量能够被标记为受保护之前,当您绝对知道要限制子类的使用时保留私有。
7.2.5 高级显示
如果一个变量应该是可编辑的,但通常是不变的,请将其标记为高级显示。除非单击高级显示箭头,否则这会使变量隐藏。
要查找“高级显示”选项,它在变量详细信息列表中列为高级显示变量。
7.2.6 临时变量
临时变量是不需要保存和加载其值且初始值为 0 或 null 的变量。这对于在运行时引用才知道值的其他对象和参与者很有用。这可以防止编辑器保存对其的引用,并加快蓝图类的保存和加载。
因此,所有瞬态变量都应始终初始化为零或空。否则会导致难以调试的错误。
7.2.7 配置变量
不要使用配置变量标志。这使得设计师更难控制蓝图行为。配置变量只能在 C++ 中用于很少更改的变量。将它们视为高级高级显示变量。
7.3 函数、事件和事件分发器
本节介绍如何编写函数、事件和事件分发器。除非另有说明,适用于函数的所有内容也适用于事件。
7.3.1 函数命名
函数、事件和事件分发器的命名至关重要。仅根据名称,就可以对函数做出某些假设。例如:
是纯函数吗?
它是在获取状态信息吗?
是处理程序吗?
是 RPC 吗?
它的目的是什么?
当函数命名得当时,这些问题以及更多问题都可以得到解答。
7.3.1.1 所有函数都应该是动词
所有函数和事件都执行某种形式的操作,无论是获取信息、计算数据还是引起爆炸。因此,所有功能都应该以动词开头。他们应该尽可能用现在时来表达。他们还应该有一些关于他们正在做什么的背景。
OnRep 函数、事件处理程序和事件分发器是此规则的一个例外。
好的例子:
Fire - 如果在 Character / Weapon 类中是一个很好的例子。如果在桶/草/任何模棱两可的类中,那就不好了。
Jump - 如果在 Character 类中是一个很好的例子,否则需要提示。
Explode - 爆炸
ReceiveMessage - 接收消息
SortPlayerArray - 排序播放器数组
GetArmOffset - 获得装备偏移
GetCoordinates - 获取坐标
UpdateTransforms - 更新变换
EnableBigHeadMode - 启用大头模式
IsEnemy - “是”是一个动词。
不好的例子:
Dead - 死了吗?会死机吗?
Rock - 岩石
ProcessData - 模棱两可,这些词毫无意义。
PlayerState - 名词不明确。
Color - 颜色不是动词,或模棱两可的名词。
7.3.1.2 属性 RepNotify 函数 Always OnRep_Variable
使用通知变量复制的所有函数都应具有 OnRep_Variable 的形式。这是由蓝图编辑器强制执行的。但是,如果您正在编写 C++ OnRep 函数,则在将其公开给蓝图时也应遵循此约定。
7.3.1.3 返回 Bool 的信息函数应该提问
当编写一个不改变任何对象的状态或修改任何对象并且纯粹用于获取信息、状态或计算是否值的函数时,它应该提出一个问题。这也应该遵循动词规则。
这非常重要,因为如果没有提出问题,则可以假定该函数执行了一个动作并返回该动作是否成功。
很好的例子:
IsDead - 是否死了
IsOnFire - 是否在开火
IsAlive - 是否活着
IsSpeaking - 是否正在说话
IsHavingAnExistentialCrisis - 是否有存在的危机
IsVisible - 是否可见
HasWeapon - 是否有武器,“有”是一个动词。
WasCharging - 是否在充电,“Was”是“be”的过去式。
CanReload - 是否可重新加载,“Can”是一个动词。
不好的例子:
Fire - 着火了吗?还是开火吗?
OnFire - 可能与用于触发的事件调度程序混淆。
Dead - 死了吗?设置死亡?
Visible - 获取可见吗?设置可见性?
7.3.1.4 事件处理程序和调度程序应以 On 开头
任何处理事件或分派事件的函数都应该以 On 开头并继续遵循动词规则。
On 一词的搭配不遵循动词规则。
有一些框架中用Handle来表示事件响应,但在虚幻中建议使用 On 代替 Handle
很好的例子:
OnDeath - 在死亡时;游戏中的常见搭配
OnPickup - 在捡起时
OnReceiveMessage - 在接收消息时
OnMessageRecieved - 在收到消息时
OnTargetChanged - 在目标变更时
OnClick - 在点击时
OnLeave - 在休息时候
不好的例子:
OnData - 在数据时
OnTarget - 在目标时
HandleMessage - 处理消息
HandleDeath - 处理死亡
7.3.1.5 远程过程调用应以目标为前缀
每次创建 RPC 时,它都应该以 Server、Client 或 Multicast 作为前缀。没有例外。
在前缀之后,遵循有关函数命名的所有其他规则。
很好的例子:
ServerFireWeapon - 服务器中的开火武器
ClientNotifyDeath - 客户通知死亡
MulticastSpawnTracerEffect - 多播创建跟踪特效
不好的例子:
FireWeapon - 不表示它是某种 RPC。
ServerClientBroadcast - 令人困惑。
AllNotifyDeath - 使用多播,而不是全部。
ClientWeapon - 没有动词,模棱两可。
7.3.2 所有函数都必须有返回节点
所有函数都必须有返回节点,没有例外。
返回节点明确指出函数已完成执行。在蓝图有 Sequence、ForLoopWithBreak 节点,显式执行流程对于可读性、维护和更容易调试非常重要。
如果您使用返回节点,蓝图编译器能够跟踪执行流程,并在代码分支中存在未处理的返回或错误流程时向您发出警告。
在诸如程序员可能在 for 循环完成后向 Sequence 节点添加引脚或添加逻辑但循环迭代可能提前返回的情况下,这通常会导致代码的意外错误。蓝图编译器的警告将立即提醒所有人这些问题。
7.3.3 任何函数都不应有超过 50 个节点
简单地说,任何函数都不应有超过 50 个节点。为了可读性和易于维护,任何这么大的功能都应该分解成更小的功能。
以下节点
不计算在内,因为它们被认为不会增加功能复杂性:
Comment - 注释
Route - 变更路线节点
Cast - 类型转换
Getting a Variable - 获得一个变量
Breaking a Struct - 分解一个结构体
Function Entry - 函数入口
Self - 自身
7.3.4 所有公共功能都应该有描述
此规则更适用于面向公开的蓝图函数,以便其他人可以更轻松地理解和使用您的蓝图 API。
简单地说,任何具有 Public 访问规范的函数都应该填写其描述。
7.3.5 所有自定义静态插件BlueprintCallable函数必须按插件名称分类
如果您的项目包含定义静态 BlueprintCallable 函数的插件,则它们的类别应设置为插件名称或插件名称的子类别。
例如,Zed Camera Interface 或 Zed Camera Interface | Image Capturing。