VIRTUOS_Docs/sites/styleguide.tex

2397 lines
82 KiB
TeX

% Options for packages loaded elsewhere
\PassOptionsToPackage{unicode}{hyperref}
\PassOptionsToPackage{hyphens}{url}
\PassOptionsToPackage{dvipsnames,svgnames,x11names}{xcolor}
%
\documentclass[
letterpaper,
DIV=11,
numbers=noendperiod,
oneside]{scrartcl}
\usepackage{amsmath,amssymb}
\usepackage{iftex}
\ifPDFTeX
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{textcomp} % provide euro and other symbols
\else % if luatex or xetex
\usepackage{unicode-math}
\defaultfontfeatures{Scale=MatchLowercase}
\defaultfontfeatures[\rmfamily]{Ligatures=TeX,Scale=1}
\fi
\usepackage{lmodern}
\ifPDFTeX\else
% xetex/luatex font selection
\fi
% Use upquote if available, for straight quotes in verbatim environments
\IfFileExists{upquote.sty}{\usepackage{upquote}}{}
\IfFileExists{microtype.sty}{% use microtype if available
\usepackage[]{microtype}
\UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
}{}
\makeatletter
\@ifundefined{KOMAClassName}{% if non-KOMA class
\IfFileExists{parskip.sty}{%
\usepackage{parskip}
}{% else
\setlength{\parindent}{0pt}
\setlength{\parskip}{6pt plus 2pt minus 1pt}}
}{% if KOMA class
\KOMAoptions{parskip=half}}
\makeatother
\usepackage{xcolor}
\usepackage[left=1in,marginparwidth=2.0666666666667in,textwidth=4.1333333333333in,marginparsep=0.3in]{geometry}
\setlength{\emergencystretch}{3em} % prevent overfull lines
\setcounter{secnumdepth}{-\maxdimen} % remove section numbering
% Make \paragraph and \subparagraph free-standing
\makeatletter
\ifx\paragraph\undefined\else
\let\oldparagraph\paragraph
\renewcommand{\paragraph}{
\@ifstar
\xxxParagraphStar
\xxxParagraphNoStar
}
\newcommand{\xxxParagraphStar}[1]{\oldparagraph*{#1}\mbox{}}
\newcommand{\xxxParagraphNoStar}[1]{\oldparagraph{#1}\mbox{}}
\fi
\ifx\subparagraph\undefined\else
\let\oldsubparagraph\subparagraph
\renewcommand{\subparagraph}{
\@ifstar
\xxxSubParagraphStar
\xxxSubParagraphNoStar
}
\newcommand{\xxxSubParagraphStar}[1]{\oldsubparagraph*{#1}\mbox{}}
\newcommand{\xxxSubParagraphNoStar}[1]{\oldsubparagraph{#1}\mbox{}}
\fi
\makeatother
\providecommand{\tightlist}{%
\setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}\usepackage{longtable,booktabs,array}
\usepackage{calc} % for calculating minipage widths
% Correct order of tables after \paragraph or \subparagraph
\usepackage{etoolbox}
\makeatletter
\patchcmd\longtable{\par}{\if@noskipsec\mbox{}\fi\par}{}{}
\makeatother
% Allow footnotes in longtable head/foot
\IfFileExists{footnotehyper.sty}{\usepackage{footnotehyper}}{\usepackage{footnote}}
\makesavenoteenv{longtable}
\usepackage{graphicx}
\makeatletter
\newsavebox\pandoc@box
\newcommand*\pandocbounded[1]{% scales image to fit in text height/width
\sbox\pandoc@box{#1}%
\Gscale@div\@tempa{\textheight}{\dimexpr\ht\pandoc@box+\dp\pandoc@box\relax}%
\Gscale@div\@tempb{\linewidth}{\wd\pandoc@box}%
\ifdim\@tempb\p@<\@tempa\p@\let\@tempa\@tempb\fi% select the smaller of both
\ifdim\@tempa\p@<\p@\scalebox{\@tempa}{\usebox\pandoc@box}%
\else\usebox{\pandoc@box}%
\fi%
}
% Set default figure placement to htbp
\def\fps@figure{htbp}
\makeatother
\KOMAoption{captions}{tableheading}
\makeatletter
\@ifpackageloaded{caption}{}{\usepackage{caption}}
\AtBeginDocument{%
\ifdefined\contentsname
\renewcommand*\contentsname{Table of contents}
\else
\newcommand\contentsname{Table of contents}
\fi
\ifdefined\listfigurename
\renewcommand*\listfigurename{List of Figures}
\else
\newcommand\listfigurename{List of Figures}
\fi
\ifdefined\listtablename
\renewcommand*\listtablename{List of Tables}
\else
\newcommand\listtablename{List of Tables}
\fi
\ifdefined\figurename
\renewcommand*\figurename{Figure}
\else
\newcommand\figurename{Figure}
\fi
\ifdefined\tablename
\renewcommand*\tablename{Table}
\else
\newcommand\tablename{Table}
\fi
}
\@ifpackageloaded{float}{}{\usepackage{float}}
\floatstyle{ruled}
\@ifundefined{c@chapter}{\newfloat{codelisting}{h}{lop}}{\newfloat{codelisting}{h}{lop}[chapter]}
\floatname{codelisting}{Listing}
\newcommand*\listoflistings{\listof{codelisting}{List of Listings}}
\makeatother
\makeatletter
\makeatother
\makeatletter
\@ifpackageloaded{caption}{}{\usepackage{caption}}
\@ifpackageloaded{subcaption}{}{\usepackage{subcaption}}
\makeatother
\makeatletter
\@ifpackageloaded{sidenotes}{}{\usepackage{sidenotes}}
\@ifpackageloaded{marginnote}{}{\usepackage{marginnote}}
\makeatother
\usepackage{bookmark}
\IfFileExists{xurl.sty}{\usepackage{xurl}}{} % add URL line breaks if available
\urlstyle{same} % disable monospaced font for URLs
\hypersetup{
pdftitle={Styleguide},
colorlinks=true,
linkcolor={blue},
filecolor={Maroon},
citecolor={Blue},
urlcolor={Blue},
pdfcreator={LaTeX via pandoc}}
\title{Styleguide}
\author{}
\date{}
\begin{document}
\maketitle
This Styleguiade is adapted by Gamemakin UE5 Styleguide.
\subsection{Important Terminology}\label{important-terminology}
\subparagraph{Levels/Maps}\label{levelsmaps}
The word `map' generally refers to what the average person calls a
`level' and may be used interchangeably. See this term's history
\href{https://en.wikipedia.org/wiki/Level_(video_gaming)}{here}.
\subparagraph{Identifiers}\label{identifiers}
An \texttt{Identifier} is anything that resembles or serves as a
``name''. For example, the name of an asset, or the name of a material
later, or a blueprint property, a variable, or a folder name, or for a
data table row name, etc\ldots{}
\subparagraph{Cases}\label{cases}
There are a few different ways you can \texttt{CaseWordsWhenNaming}.
Here are some common casing types:
\begin{quote}
PascalCase
Capitalize every word and remove all spaces, e.g.~\texttt{DesertEagle},
\texttt{StyleGuide}, \texttt{ASeriesOfWords}.
camelCase
The first letter is always lowercase but every following word starts
with uppercase, e.g.~\texttt{desertEagle}, \texttt{styleGuide},
\texttt{aSeriesOfWords}.
Snake\_case
Words can arbitrarily start upper or lowercase but words are separated
by an underscore, e.g.~\texttt{desert\_Eagle}, \texttt{Style\_Guide},
\texttt{a\_Series\_of\_Words}.
\end{quote}
\subparagraph{Variables / Properties}\label{variables-properties}
The words `variable' and `property' in most contexts are interchangable.
If they are both used together in the same context however:
Property
Usually refers to a variable defined in a class. For example, if
\texttt{BP\_Barrel} had a variable \texttt{bExploded},
\texttt{bExploded} may be referred to as a property of
\texttt{BP\_Barrel}.
When in the context of a class, it is often used to imply accessing
previously defined data.
Variable
Usually refers to a variable defined as a function argument or a local
variable inside a function.
When in the context of a class, it is often used to convey discussion
about its definition and what it will hold.
\subsection{0. Principles}\label{principles}
These principles have been adapted from
\href{https://github.com/rwaldron/idiomatic.js/}{idomatic.js style
guide}.
\subsubsection{0.1 If your UE4 project already has a style guide, you
should follow
it.}\label{if-your-ue4-project-already-has-a-style-guide-you-should-follow-it.}
If you are working on a project or with a team that has a pre-existing
style guide, it should be respected. Any inconsistency between an
existing style guide and this guide should defer to the existing.
Style guides should be living documents. You should propose style guide
changes to an existing style guide as well as this guide if you feel the
change benefits all usages.
\begin{quote}
\mbox{}%
\paragraph{``Arguments over style are pointless. There should be a style
guide, and you should follow
it.''}\label{arguments-over-style-are-pointless.-there-should-be-a-style-guide-and-you-should-follow-it.}
\href{https://rmurphey.com}{\emph{Rebecca Murphey}}
\end{quote}
\subsubsection{0.2 All structure, assets, and code in any Unreal Engine
4 project should look like a single person created it, no matter how
many people
contributed.}\label{all-structure-assets-and-code-in-any-unreal-engine-4-project-should-look-like-a-single-person-created-it-no-matter-how-many-people-contributed.}
Moving from one project to another should not cause a re-learning of
style and structure. Conforming to a style guide removes unneeded
guesswork and ambiguities.
It also allows for more productive creation and maintenance as one does
not need to think about style. Simply follow the instructions. This
style guide is written with best practices in mind, meaning that by
following this style guide you will also minimize hard to track issues.
\subsubsection{0.3 Friends do not let friends have bad
style.}\label{friends-do-not-let-friends-have-bad-style.}
If you see someone working either against a style guide or no style
guide, try to correct them.
When working within a team or discussing within a community such as
\href{http://join.unrealslackers.org/}{Unreal Slackers}, it is far
easier to help and to ask for help when people are consistent. Nobody
likes to help untangle someone's Blueprint spaghetti or deal with assets
that have names they can't understand.
If you are helping someone whose work conforms to a different but
consistent and sane style guide, you should be able to adapt to it. If
they do not conform to any style guide, please direct them here.
\subsubsection{0.4 A team without a style guide is no team of
mine.}\label{a-team-without-a-style-guide-is-no-team-of-mine.}
When joining an Unreal Engine 4 team, one of your first questions should
be ``Do you have a style guide?''. If the answer is no, you should be
skeptical about their ability to work as a team.
\subsubsection{0.5 Don't Break The Law}\label{dont-break-the-law}
Gamemakin LLC is not a lawyer, but please don't introduce illegal
actions and behavior to a project, including but not limited to:
\begin{itemize}
\tightlist
\item
Don't distribute content you don't have the rights to distribute
\item
Don't infringe on someone else's copyrighted or trademark material
\item
Don't steal content
\item
Follow licensing restrictions on content, e.g.~attribute when
attributions are needed
\end{itemize}
\subsection{00. Globally Enforced
Opinions}\label{globally-enforced-opinions}
@TODO\marginpar{\begin{footnotesize}{?quarto-cite:TODO}\vspace{2mm}\par\end{footnotesize}}:
Make this section 1 and update this document accordingly. Or maybe we
don't?
\subsubsection{00.1 Forbidden Characters}\label{forbidden-characters}
\paragraph{Identifiers}\label{identifiers-1}
In any \texttt{Identifier} of any kind, \textbf{never} use the following
unless absolutely forced to:
\begin{itemize}
\tightlist
\item
White space of any kind
\item
Backward slashes \texttt{\textbackslash{}}
\item
Symbols i.e.~\texttt{\#!@\$\%}
\item
Any Unicode character
\end{itemize}
Any \texttt{Identifier} should strive to only have the following
characters when possible (the \n \texttt{{[}A-Za-z0-9\_{]}+})
\begin{itemize}
\tightlist
\item
ABCDEFGHIJKLMNOPQRSTUVWXYZ
\item
abcdefghijklmnopqrstuvwxyz
\item
1234567890
\item
\_ (sparingly)
\end{itemize}
The reasoning for this is this will ensure the greatest compatibility of
all data across all platforms across all tools, and help prevent
downtime due to potentially bad character handling for identifiers in
code you don't control.
\subsection{Table of Contents}\label{table-of-contents}
\begin{quote}
\begin{enumerate}
\def\labelenumi{\arabic{enumi}.}
\tightlist
\item
\hyperref[anc]{Asset Naming Conventions}
\item
\hyperref[structure]{Directory Structure}
\item
\hyperref[bp]{Blueprints}
\item
\hyperref[s]{Static Meshes}
\item
\hyperref[ps]{Particle Systems}
\item
\hyperref[levels]{Levels / Maps}
\item
\hyperref[textures]{Textures}
\end{enumerate}
\end{quote}
\subsection{1. Asset Naming Conventions}\label{asset-naming-conventions}
Naming conventions should be treated as law. A project that conforms to
a naming convention is able to have its assets managed, searched,
parsed, and maintained with incredible ease.
Most things are prefixed with prefixes being generally an acronym of the
asset type followed by an underscore.
\subsubsection{\texorpdfstring{1.1 Base Asset Name -
\texttt{Prefix\_BaseAssetName\_Variant\_Suffix}}{1.1 Base Asset Name - Prefix\_BaseAssetName\_Variant\_Suffix}}\label{base-asset-name---prefix_baseassetname_variant_suffix}
All assets should have a \emph{Base Asset Name}. A Base Asset Name
represents a logical grouping of related assets. Any asset that is part
of this logical group should follow the standard of
\texttt{Prefix\_BaseAssetName\_Variant\_Suffix}.
Keeping the pattern \texttt{Prefix\_BaseAssetName\_Variant\_Suffix} and
in mind and using common sense is generally enough to warrant good asset
names. Here are some detailed rules regarding each element.
\texttt{Prefix} and \texttt{Suffix} are to be determined by the asset
type through the following \hyperref[asset-name-modifiers]{Asset Name
Modifier} tables.
\texttt{BaseAssetName} should be determined by a short and easily
recognizable name related to the context of this group of assets. For
example, if you had a character named Bob, all of Bob's assets would
have the \texttt{BaseAssetName} of \texttt{Bob}.
For unique and specific variations of assets, \texttt{Variant} is either
a short and easily recognizable name that represents logical grouping of
assets that are a subset of an asset's base name. For example, if Bob
had multiple skins these skins should still use \texttt{Bob} as the
\texttt{BaseAssetName} but include a recognizable \texttt{Variant}. An
`Evil' skin would be referred to as \texttt{Bob\_Evil} and a `Retro'
skin would be referred to as \texttt{Bob\_Retro}.
For unique but generic variations of assets, \texttt{Variant} is a two
digit number starting at \texttt{01}. For example, if you have an
environment artist generating nondescript rocks, they would be named
\texttt{Rock\_01}, \texttt{Rock\_02}, \texttt{Rock\_03}, etc. Except for
rare exceptions, you should never require a three digit variant number.
If you have more than 100 assets, you should consider organizing them
with different base names or using multiple variant names.
Depending on how your asset variants are made, you can chain together
variant names. For example, if you are creating flooring assets for an
Arch Viz project you should use the base name \texttt{Flooring} with
chained variants such as \texttt{Flooring\_Marble\_01},
\texttt{Flooring\_Maple\_01}, \texttt{Flooring\_Tile\_Squares\_01}.
\paragraph{1.1 Examples}\label{examples}
\subparagraph{1.1e1 Bob}\label{e1-bob}
\begin{longtable}[]{@{}
>{\raggedright\arraybackslash}p{(\linewidth - 2\tabcolsep) * \real{0.2840}}
>{\raggedright\arraybackslash}p{(\linewidth - 2\tabcolsep) * \real{0.7160}}@{}}
\toprule\noalign{}
\begin{minipage}[b]{\linewidth}\raggedright
Asset Type
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Asset Name
\end{minipage} \\
\midrule\noalign{}
\endhead
\bottomrule\noalign{}
\endlastfoot
Skeletal Mesh & SK\_Bob \\
Material & M\_Bob \\
Texture (Diffuse/Albedo) & T\_Bob\_D \\
Texture (Normal) & T\_Bob\_N \\
Texture (Evil Diffuse) & T\_Bob\_Evil\_D \\
\end{longtable}
\subparagraph{1.1e2 Rocks}\label{e2-rocks}
\begin{longtable}[]{@{}
>{\raggedright\arraybackslash}p{(\linewidth - 2\tabcolsep) * \real{0.2840}}
>{\raggedright\arraybackslash}p{(\linewidth - 2\tabcolsep) * \real{0.7160}}@{}}
\toprule\noalign{}
\begin{minipage}[b]{\linewidth}\raggedright
Asset Type
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Asset Name
\end{minipage} \\
\midrule\noalign{}
\endhead
\bottomrule\noalign{}
\endlastfoot
Static Mesh (01) & S\_Rock\_01 \\
Static Mesh (02) & S\_Rock\_02 \\
Static Mesh (03) & S\_Rock\_03 \\
Material & M\_Rock \\
Material Instance (Snow) & MI\_Rock\_Snow \\
\end{longtable}
\subsubsection{1.2 Asset Name Modifiers}\label{asset-name-modifiers}
When naming an asset, use these tables to determine the prefix and
suffix to use with an asset's \hyperref[base-asset-name]{Base Asset
Name}.
\paragraph{Sections}\label{sections}
\begin{quote}
1.2.1 \hyperref[anc-common]{Most Common}
\end{quote}
\begin{quote}
1.2.2 \hyperref[anc-animations]{Animations}
\end{quote}
\begin{quote}
1.2.3 \hyperref[anc-ai]{Artificial Intelligence}
\end{quote}
\begin{quote}
1.2.4 \hyperref[anc-bp]{Blueprints}
\end{quote}
\begin{quote}
1.2.5 \hyperref[anc-materials]{Materials}
\end{quote}
\begin{quote}
1.2.6 \hyperref[anc-textures]{Textures}
\end{quote}
\begin{quote}
1.2.7 \hyperref[anc-misc]{Miscellaneous}
\end{quote}
\begin{quote}
1.2.8 \hyperref[anc-paper2d]{Paper 2D}
\end{quote}
\begin{quote}
1.2.9 \hyperref[anc-physics]{Physics}
\end{quote}
\begin{quote}
1.2.10 \hyperref[anc-sounds]{Sound}
\end{quote}
\begin{quote}
1.2.11 \hyperref[anc-ui]{User Interface}
\end{quote}
\begin{quote}
1.2.12 \hyperref[anc-effects]{Effects}
\end{quote}
\paragraph{1.2.1 Most Common}\label{most-common}
\begin{longtable}[]{@{}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.3067}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.1333}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.1333}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.4267}}@{}}
\toprule\noalign{}
\begin{minipage}[b]{\linewidth}\raggedright
Asset Type
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Prefix
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Suffix
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Notes
\end{minipage} \\
\midrule\noalign{}
\endhead
\bottomrule\noalign{}
\endlastfoot
Level / Map & & & \hyperref[2.4]{Should be in a folder called Maps.} \\
Level (Persistent) & & \_P & \\
Level (Audio) & & \_Audio & \\
Level (Lighting) & & \_Lighting & \\
Level (Geometry) & & \_Geo & \\
Level (Gameplay) & & \_Gameplay & \\
Blueprint & BP\_ & & \\
Material & M\_ & & \\
Static Mesh & S\_ & & Many use SM\_. We use S\_. \\
Skeletal Mesh & SK\_ & & \\
Texture & T\_ & \_? & See \hyperref[anc-textures]{Textures} \\
Particle System & PS\_ & & \\
Widget Blueprint & WBP\_ & & \\
\end{longtable}
\paragraph{1.2.2 Animations}\label{animations}
\begin{longtable}[]{@{}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.3067}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.1333}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.1333}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.4267}}@{}}
\toprule\noalign{}
\begin{minipage}[b]{\linewidth}\raggedright
Asset Type
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Prefix
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Suffix
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Notes
\end{minipage} \\
\midrule\noalign{}
\endhead
\bottomrule\noalign{}
\endlastfoot
Aim Offset & AO\_ & & \\
Aim Offset 1D & AO\_ & & \\
Animation Blueprint & ABP\_ & & \\
Animation Composite & AC\_ & & \\
Animation Montage & AM\_ & & \\
Animation Sequence & A\_ & & \\
Blend Space & BS\_ & & \\
Blend Space 1D & BS\_ & & \\
Level Sequence & LS\_ & & \\
Morph Target & MT\_ & & \\
Paper Flipbook & PFB\_ & & \\
Rig & Rig\_ & & \\
Control Rig & CR\_ & & \\
Skeletal Mesh & SK\_ & & \\
Skeleton & SKEL\_ & & \\
\end{longtable}
\subsubsection{1.2.3 Artificial
Intelligence}\label{artificial-intelligence}
\begin{longtable}[]{@{}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.3067}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.1333}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.1333}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.4267}}@{}}
\toprule\noalign{}
\begin{minipage}[b]{\linewidth}\raggedright
Asset Type
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Prefix
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Suffix
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Notes
\end{minipage} \\
\midrule\noalign{}
\endhead
\bottomrule\noalign{}
\endlastfoot
AI Controller & AIC\_ & & \\
Behavior Tree & BT\_ & & \\
Blackboard & BB\_ & & \\
Decorator & BTDecorator\_ & & \\
Service & BTService\_ & & \\
Task & BTTask\_ & & \\
Environment Query & EQS\_ & & \\
EnvQueryContext & EQS\_ & Context & \\
\end{longtable}
\subsubsection{1.2.4 Blueprints}\label{blueprints}
\begin{longtable}[]{@{}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.3067}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.1333}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.1333}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.4267}}@{}}
\toprule\noalign{}
\begin{minipage}[b]{\linewidth}\raggedright
Asset Type
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Prefix
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Suffix
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Notes
\end{minipage} \\
\midrule\noalign{}
\endhead
\bottomrule\noalign{}
\endlastfoot
Blueprint & BP\_ & & \\
Blueprint Component & BP\_ & Component & I.e. BP\_InventoryComponent \\
Blueprint Function Library & BPFL\_ & & \\
Blueprint Interface & BPI\_ & & \\
Blueprint Macro Library & BPML\_ & & Do not use macro libraries if
possible. \\
Enumeration & E & & No underscore. \\
Structure & F or S & & No underscore. \\
Tutorial Blueprint & TBP\_ & & \\
Widget Blueprint & WBP\_ & & \\
\end{longtable}
\subsubsection{1.2.5 Materials}\label{materials}
\begin{longtable}[]{@{}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.3580}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.1235}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.1235}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.3951}}@{}}
\toprule\noalign{}
\begin{minipage}[b]{\linewidth}\raggedright
Asset Type
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Prefix
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Suffix
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Notes
\end{minipage} \\
\midrule\noalign{}
\endhead
\bottomrule\noalign{}
\endlastfoot
Material & M\_ & & \\
Material (Post Process) & PP\_ & & \\
Material Function & MF\_ & & \\
Material Instance & MI\_ & & \\
Material Parameter Collection & MPC\_ & & \\
Subsurface Profile & SP\_ & & \\
Physical Materials & PM\_ & & \\
Decal & M\_, MI\_ & \_Decal & \\
\end{longtable}
\subsubsection{1.2.6 Textures}\label{textures}
\begin{longtable}[]{@{}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.3067}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.1333}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.1333}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.4267}}@{}}
\toprule\noalign{}
\begin{minipage}[b]{\linewidth}\raggedright
Asset Type
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Prefix
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Suffix
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Notes
\end{minipage} \\
\midrule\noalign{}
\endhead
\bottomrule\noalign{}
\endlastfoot
Texture & T\_ & & \\
Texture (Diffuse/Albedo/Base Color) & T\_ & \_D & \\
Texture (Normal) & T\_ & \_N & \\
Texture (Roughness) & T\_ & \_R & \\
Texture (Alpha/Opacity) & T\_ & \_A & \\
Texture (Ambient Occlusion) & T\_ & \_O & \\
Texture (Bump) & T\_ & \_B & \\
Texture (Emissive) & T\_ & \_E & \\
Texture (Mask) & T\_ & \_M & \\
Texture (Specular) & T\_ & \_S & \\
Texture (Metallic) & T\_ & \_M & \\
Texture (Packed) & T\_ & \_* & See notes below about
\hyperref[anc-textures-packing]{packing}. \\
Texture Cube & TC\_ & & \\
Media Texture & MT\_ & & \\
Render Target & RT\_ & & \\
Cube Render Target & RTC\_ & & \\
Texture Light Profile & TLP & & \\
\end{longtable}
\paragraph{1.2.6.1 Texture Packing}\label{texture-packing}
It is common practice to pack multiple layers of texture data into one
texture. An example of this is packing Emissive, Roughness, Ambient
Occlusion together as the Red, Green, and Blue channels of a texture
respectively. To determine the suffix, simply stack the given suffix
letters from above together, e.g.~\texttt{\_ERO}.
\begin{quote}
It is generally acceptable to include an Alpha/Opacity layer in your
Diffuse/Albedo's alpha channel and as this is common practice, adding
\texttt{A} to the \texttt{\_D} suffix is optional.
\end{quote}
Packing 4 channels of data into a texture (RGBA) is not recommended
except for an Alpha/Opacity mask in the Diffuse/Albedo's alpha channel
as a texture with an alpha channel incurs more overhead than one
without.
\subsubsection{1.2.7 Miscellaneous}\label{miscellaneous}
\begin{longtable}[]{@{}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.3333}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.1282}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.1282}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.4103}}@{}}
\toprule\noalign{}
\begin{minipage}[b]{\linewidth}\raggedright
Asset Type
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Prefix
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Suffix
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Notes
\end{minipage} \\
\midrule\noalign{}
\endhead
\bottomrule\noalign{}
\endlastfoot
Animated Vector Field & VFA\_ & & \\
Camera Anim & CA\_ & & \\
Color Curve & Curve\_ & \_Color & \\
Curve Table & Curve\_ & \_Table & \\
Data Asset & *\_ & & Prefix should be based on class. \\
Data Table & DT\_ & & \\
Float Curve & Curve\_ & \_Float & \\
Foliage Type & FT\_ & & \\
Force Feedback Effect & FFE\_ & & \\
Landscape Grass Type & LG\_ & & \\
Landscape Layer & LL\_ & & \\
Matinee Data & Matinee\_ & & \\
Media Player & MP\_ & & \\
Object Library & OL\_ & & \\
Redirector & & & These should be fixed up ASAP. \\
Sprite Sheet & SS\_ & & \\
Static Vector Field & VF\_ & & \\
Substance Graph Instance & SGI\_ & & \\
Substance Instance Factory & SIF\_ & & \\
Touch Interface Setup & TI\_ & & \\
Vector Curve & Curve\_ & \_Vector & \\
\end{longtable}
\subsubsection{1.2.8 Paper 2D}\label{paper-2d}
\begin{longtable}[]{@{}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.3067}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.1333}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.1333}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.4267}}@{}}
\toprule\noalign{}
\begin{minipage}[b]{\linewidth}\raggedright
Asset Type
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Prefix
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Suffix
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Notes
\end{minipage} \\
\midrule\noalign{}
\endhead
\bottomrule\noalign{}
\endlastfoot
Paper Flipbook & PFB\_ & & \\
Sprite & SPR\_ & & \\
Sprite Atlas Group & SPRG\_ & & \\
Tile Map & TM\_ & & \\
Tile Set & TS\_ & & \\
\end{longtable}
\subsubsection{1.2.9 Physics}\label{physics}
\begin{longtable}[]{@{}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.3067}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.1333}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.1333}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.4267}}@{}}
\toprule\noalign{}
\begin{minipage}[b]{\linewidth}\raggedright
Asset Type
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Prefix
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Suffix
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Notes
\end{minipage} \\
\midrule\noalign{}
\endhead
\bottomrule\noalign{}
\endlastfoot
Physical Material & PM\_ & & \\
Physics Asset & PHYS\_ & & \\
Destructible Mesh & DM\_ & & \\
\end{longtable}
\subsubsection{1.2.10 Sounds}\label{sounds}
\begin{longtable}[]{@{}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.3067}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.1333}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.1333}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.4267}}@{}}
\toprule\noalign{}
\begin{minipage}[b]{\linewidth}\raggedright
Asset Type
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Prefix
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Suffix
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Notes
\end{minipage} \\
\midrule\noalign{}
\endhead
\bottomrule\noalign{}
\endlastfoot
Dialogue Voice & DV\_ & & \\
Dialogue Wave & DW\_ & & \\
Media Sound Wave & MSW\_ & & \\
Reverb Effect & Reverb\_ & & \\
Sound Attenuation & ATT\_ & & \\
Sound Class & & & No prefix/suffix. Should be put in a folder called
SoundClasses \\
Sound Concurrency & & \_SC & Should be named after a SoundClass \\
Sound Cue & A\_ & \_Cue & \\
Sound Mix & Mix\_ & & \\
Sound Wave & A\_ & & \\
\end{longtable}
\subsubsection{1.2.11 User Interface}\label{user-interface}
\begin{longtable}[]{@{}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.3067}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.1333}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.1333}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.4267}}@{}}
\toprule\noalign{}
\begin{minipage}[b]{\linewidth}\raggedright
Asset Type
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Prefix
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Suffix
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Notes
\end{minipage} \\
\midrule\noalign{}
\endhead
\bottomrule\noalign{}
\endlastfoot
Font & Font\_ & & \\
Slate Brush & Brush\_ & & \\
Slate Widget Style & Style\_ & & \\
Widget Blueprint & WBP\_ & & \\
\end{longtable}
\subsubsection{1.2.12 Effects}\label{effects}
\begin{longtable}[]{@{}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.3067}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.1333}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.1333}}
>{\raggedright\arraybackslash}p{(\linewidth - 6\tabcolsep) * \real{0.4267}}@{}}
\toprule\noalign{}
\begin{minipage}[b]{\linewidth}\raggedright
Asset Type
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Prefix
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Suffix
\end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
Notes
\end{minipage} \\
\midrule\noalign{}
\endhead
\bottomrule\noalign{}
\endlastfoot
Particle System & PS\_ & & \\
Material (Post Process) & PP\_ & & \\
\end{longtable}
\textbf{\hyperref[table-of-contents]{⬆ Back to Top}}
\subsection{2. Content Directory
Structure}\label{content-directory-structure}
Equally important as asset names, the directory structure style of a
project should be considered law. Asset naming conventions and content
directory structure go hand in hand, and a violation of either causes
unneeded chaos.
There are multiple ways to lay out the content of a UE4 project. In this
style, we will be using a structure that relies more on filtering and
search abilities of the Content Browser for those working with assets to
find assets of a specific type instead of another common structure that
groups asset types with folders.
\begin{quote}
If you are using the prefix \hyperref[1.2]{naming convention} above,
using folders to contain assets of similar types such as
\texttt{Meshes}, \texttt{Textures}, and \texttt{Materials} is a
redundant practice as asset types are already both sorted by prefix as
well as able to be filtered in the content browser.
\end{quote}
\#\#\# 2e1 Example Project Content Structure
The reasons for this structure are listed in the following sub-sections.
\subsubsection{Sections}\label{sections-1}
\begin{quote}
2.1 \hyperref[structure-folder-names]{Folder Names}
\end{quote}
\begin{quote}
2.2 \hyperref[structure-top-level]{Top-Level Folders}
\end{quote}
\begin{quote}
2.3 \hyperref[structure-developers]{Developer Folders}
\end{quote}
\begin{quote}
2.4 \hyperref[structure-maps]{Maps}
\end{quote}
\begin{quote}
2.5 \hyperref[structure-core]{Core}
\end{quote}
\begin{quote}
2.6 \hyperref[structure-assettypes]{\texttt{Assets} and
\texttt{AssetTypes}}
\end{quote}
\begin{quote}
2.7 \hyperref[structure-large-sets]{Large Sets}
\end{quote}
\begin{quote}
2.8 \hyperref[structure-material-library]{Material Library}
\end{quote}
\#\#\# 2.1 Folder Names
These are common rules for naming any folder in the content structure.
\paragraph{\texorpdfstring{2.1.1 Always Use
PascalCase\hyperref[terms-cases]{*}}{2.1.1 Always Use PascalCase*}}\label{always-use-pascalcase}
PascalCase refers to starting a name with a capital letter and then
instead of using spaces, every following word also starts with a capital
letter. For example, \texttt{DesertEagle}, \texttt{RocketPistol}, and
\texttt{ASeriesOfWords}.
See \hyperref[terms-cases]{Cases}.
\paragraph{2.1.2 Never Use Spaces}\label{never-use-spaces}
Re-enforcing \hyperref[2.1.1]{2.1.1}, never use spaces. Spaces can cause
various engineering tools and batch processes to fail. Ideally, your
project's root also contains no spaces and is located somewhere such as
\texttt{D:\textbackslash{}Project} instead of
\texttt{C:\textbackslash{}Users\textbackslash{}My\ Name\textbackslash{}My\ Documents\textbackslash{}Unreal\ Projects}.
\paragraph{2.1.3 Never Use Unicode Characters And Other
Symbols}\label{never-use-unicode-characters-and-other-symbols}
If one of your game characters is named `Zoë', its folder name should be
\texttt{Zoe}. Unicode characters can be worse than
\hyperref[2.1.2]{Spaces} for engineering tool and some parts of UE4
don't support Unicode characters in paths either.
Related to this, if your project has
\href{https://answers.unrealengine.com/questions/101207/undefined.html}{unexplained
issues} and your computer's user name has a Unicode character (i.e.~your
name is \texttt{Zoë}), any project located in your
\texttt{My\ Documents} folder will suffer from this issue. Often simply
moving your project to something like \texttt{D:\textbackslash{}Project}
will fix these mysterious issues.
Using other characters outside \texttt{a-z}, \texttt{A-Z}, and
\texttt{0-9} such as \texttt{@}, \texttt{-}, \texttt{\_}, \texttt{,},
\texttt{*}, and \texttt{\#} can also lead to unexpected and hard to
track issues on other platforms, source control, and weaker engineering
tools.
\#\#\# 2.2 Use A Top Level Folder For Project Specific Assets
All of a project's assets should exist in a folder named after the
project. For example, if your project is named `Generic Shooter',
\emph{all} of it's content should exist in
\texttt{Content/GenericShooter}.
\begin{quote}
The \texttt{Developers} folder is not for assets that your project
relies on and therefore is not project specific. See
\hyperref[2.3]{Developer Folders} for details about this.
\end{quote}
There are multiple reasons for this approach.
\paragraph{2.2.1 No Global Assets}\label{no-global-assets}
Often in code style guides it is written that you should not pollute the
global namespace and this follows the same principle. When assets are
allowed to exist outside of a project folder, it often becomes much
harder to enforce a strict structure layout as assets not in a folder
encourages the bad behavior of not having to organize assets.
Every asset should have a purpose, otherwise it does not belong in a
project. If an asset is an experimental test and shouldn't be used by
the project it should be put in a \hyperref[2.3]{\texttt{Developer}}
folder.
\paragraph{2.2.2 Reduce Migration
Conflicts}\label{reduce-migration-conflicts}
When working on multiple projects it is common for a team to copy assets
from one project to another if they have made something useful for both.
When this occurs, the easiest way to perform the copy is to use the
Content Browser's Migrate functionality as it will copy over not just
the selected asset but all of its dependencies.
These dependencies are what can easily get you into trouble. If two
project's assets do not have a top level folder and they happen to have
similarly named or already previously migrated assets, a new migration
can accidentally wipe any changes to the existing assets.
This is also the primary reason why Epic's Marketplace staff enforces
the same policy for submitted assets.
After a migration, safe merging of assets can be done using the `Replace
References' tool in the content browser with the added clarity of assets
not belonging to a project's top level folder are clearly pending a
merge. Once assets are merged and fully migrated, there shouldn't be
another top level folder in your Content tree. This method is
\emph{100\%} guaranteed to make any migrations that occur completely
safe.
\subparagraph{2.2.2e1 Master Material
Example}\label{e1-master-material-example}
For example, say you created a master material in one project that you
would like to use in another project so you migrated that asset over. If
this asset is not in a top level folder, it may have a name like
\texttt{Content/MaterialLibrary/M\_Master}. If the target project
doesn't have a master material already, this should work without issue.
As work on one or both projects progress, their respective master
materials may change to be tailored for their specific projects due to
the course of normal development.
The issue comes when, for example, an artist for one project created a
nice generic modular set of static meshes and someone wants to include
that set of static meshes in the second project. If the artist who
created the assets used material instances based on
\texttt{Content/MaterialLibrary/M\_Master} as they're instructed to,
when a migration is performed there is a great chance of conflict for
the previously migrated \texttt{Content/MaterialLibrary/M\_Master}
asset.
This issue can be hard to predict and hard to account for. The person
migrating the static meshes may not be the same person who is familiar
with the development of both project's master material, and they may not
be even aware that the static meshes in question rely on material
instances which then rely on the master material. The Migrate tool
requires the entire chain of dependencies to work however, and so it
will be forced to grab \texttt{Content/MaterialLibrary/M\_Master} when
it copies these assets to the other project and it will overwrite the
existing asset.
It is at this point where if the master materials for both projects are
incompatible in \emph{any way}, you risk breaking possibly the entire
material library for a project as well as any other dependencies that
may have already been migrated, simply because assets were not stored in
a top level folder. The simple migration of static meshes now becomes a
very ugly task.
\paragraph{2.2.3 Samples, Templates, and Marketplace Content Are
Risk-Free}\label{samples-templates-and-marketplace-content-are-risk-free}
An extension to \hyperref[2.2.2]{2.2.2}, if a team member decides to add
sample content, template files, or assets they bought from the
marketplace, it is guaranteed, as long your project's top-level folder
is uniquely named,that these new assets will not interfere with your
project.
You can not trust marketplace content to fully conform to the
\hyperref[2.2]{top level folder rule}. There exists many assets that
have the majority of their content in a top level folder but also have
possibly modified Epic sample content as well as level files polluting
the global \texttt{Content} folder.
When adhering to \hyperref[2.2]{2.2}, the worst marketplace conflict you
can have is if two marketplace assets both have the same Epic sample
content. If all your assets are in a project specific folder, including
sample content you may have moved into your folder, your project will
never break.
\paragraph{2.2.4 DLC, Sub-Projects, and Patches Are Easily
Maintained}\label{dlc-sub-projects-and-patches-are-easily-maintained}
If your project plans to release DLC or has multiple sub-projects
associated with it that may either be migrated out or simply not cooked
in a build, assets relating to these projects should have their own
separate top level content folder. This make cooking DLC separate from
main project content far easier. Sub-projects can also be migrated in
and out with minimal effort. If you need to change a material of an
asset or add some very specific asset override behavior in a patch, you
can easily put these changes in a patch folder and work safely without
the chance of breaking the core project.
\subsubsection{2.3 Use Developers Folder For Local
Testing}\label{use-developers-folder-for-local-testing}
During a project's development, it is very common for team members to
have a sort of `sandbox' where they can experiment freely without
risking the core project. Because this work may be ongoing, these team
members may wish to put their assets on a project's source control
server. Not all teams require use of Developer folders, but ones that do
use them often run into a common problem with assets submitted to source
control.
It is very easy for a team member to accidentally use assets that are
not ready for use, which will cause issues once those assets are
removed. For example, an artist may be iterating on a modular set of
static meshes and still working on getting their sizing and grid
snapping correct. If a world builder sees these assets in the main
project folder, they might use them all over a level not knowing they
could be subject to incredible change and/or removal. This causes
massive amounts of re-working for everyone on the team to resolve.
If these modular assets were placed in a Developer folder, the world
builder should never have had a reason to use them and the whole issue
would never happen. The Content Browser has specific View Options that
will hide Developer folders (they are hidden by default) making it
impossible to accidentally use Developer assets under normal use.
Once the assets are ready for use, an artist simply has to move the
assets into the project specific folder and fix up redirectors. This is
essentially `promoting' the assets from experimental to production.
\subsubsection{\texorpdfstring{2.4 All Map\hyperref[terms-level-map]{*}
Files Belong In A Folder Called
Maps}{2.4 All Map* Files Belong In A Folder Called Maps}}\label{all-map-files-belong-in-a-folder-called-maps}
Map files are incredibly special and it is common for every project to
have its own map naming system, especially if they work with sub-levels
or streaming levels. No matter what system of map organization is in
place for the specific project, all levels should belong in
\texttt{/Content/Project/Maps}.
Being able to tell someone to open a specific map without having to
explain where it is is a great time saver and general `quality of life'
improvement. It is common for levels to be within sub-folders of
\texttt{Maps}, such as \texttt{Maps/Campaign1/} or \texttt{Maps/Arenas},
but the most important thing here is that they all exist within
\texttt{/Content/Project/Maps}.
This also simplifies the job of cooking for engineers. Wrangling levels
for a build process can be extremely frustrating if they have to dig
through arbitrary folders for them. If a team's maps are all in one
place, it is much harder to accidentally not cook a map in a build. It
also simplifies lighting build scripts as well as QA processes.
\subsubsection{\texorpdfstring{2.5 Use A \texttt{Core} Folder For
Critical Blueprints And Other
Assets}{2.5 Use A Core Folder For Critical Blueprints And Other Assets}}\label{use-a-core-folder-for-critical-blueprints-and-other-assets}
Use \texttt{/Content/Project/Core} folder for assets that are absolutely
fundamental to a project's workings. For example, base
\texttt{GameMode}, \texttt{Character}, \texttt{PlayerController},
\texttt{GameState}, \texttt{PlayerState}, and related Blueprints should
live here.
This creates a very clear ``don't touch these'' message for other team
members. Non-engineers should have very little reason to enter the
\texttt{Core} folder. Following good code structure style, designers
should be making their gameplay tweaks in child classes that expose
functionality. World builders should be using prefab Blueprints in
designated folders instead of potentially abusing base classes.
For example, if your project requires pickups that can be placed in a
level, there should exist a base Pickup class in \texttt{Core/Pickups}
that defines base behavior for a pickup. Specific pickups such as a
Health or Ammo should exist in a folder such as
\texttt{/Content/Project/Placeables/Pickups/}. Game designers can define
and tweak pickups in this folder however they please, but they should
not touch \texttt{Core/Pickups} as they may unintentionally break
pickups project-wide.
\subsubsection{\texorpdfstring{2.6 Do Not Create Folders Called
\texttt{Assets} or
\texttt{AssetTypes}}{2.6 Do Not Create Folders Called Assets or AssetTypes}}\label{do-not-create-folders-called-assets-or-assettypes}
\paragraph{\texorpdfstring{2.6.1 Creating a folder named \texttt{Assets}
is
redundant.}{2.6.1 Creating a folder named Assets is redundant.}}\label{creating-a-folder-named-assets-is-redundant.}
All assets are assets.
\paragraph{\texorpdfstring{2.6.2 Creating a folder named
\texttt{Meshes}, \texttt{Textures}, or \texttt{Materials} is
redundant.}{2.6.2 Creating a folder named Meshes, Textures, or Materials is redundant.}}\label{creating-a-folder-named-meshes-textures-or-materials-is-redundant.}
All asset names are named with their asset type in mind. These folders
offer only redundant information and the use of these folders can easily
be replaced with the robust and easy to use filtering system the Content
Browser provides.
Want to view only static mesh in \texttt{Environment/Rocks/}? Simply
turn on the Static Mesh filter. If all assets are named correctly, they
will also be sorted in alphabetical order regardless of prefixes. Want
to view both static meshes and skeletal meshes? Simply turn on both
filters. This eliminates the need to potentially have to
\texttt{Control-Click} select two folders in the Content Browser's tree
view.
\begin{quote}
This also extends the full path name of an asset for very little
benefit. The \texttt{S\_} prefix for a static mesh is only two
characters, whereas \texttt{Meshes/} is seven characters.
\end{quote}
Not doing this also prevents the inevitability of someone putting a
static mesh or a texture in a \texttt{Materials} folder.
\subsubsection{2.7 Very Large Asset Sets Get Their Own Folder
Layout}\label{very-large-asset-sets-get-their-own-folder-layout}
This can be seen as a pseudo-exception to \hyperref[2.6]{2.6}.
There are certain asset types that have a huge volume of related files
where each asset has a unique purpose. The two most common are Animation
and Audio assets. If you find yourself having 15+ of these assets that
belong together, they should be together.
For example, animations that are shared across multiple characters
should lay in \texttt{Characters/Common/Animations} and may have
sub-folders such as \texttt{Locomotion} or \texttt{Cinematic}.
\begin{quote}
This does not apply to assets like textures and materials. It is common
for a \texttt{Rocks} folder to have a large amount of textures if there
are a large amount of rocks, however these textures are generally only
related to a few specific rocks and should be named appropriately. Even
if these textures are part of a \hyperref[2.8]{Material Library}.
\end{quote}
\subsubsection{\texorpdfstring{2.8
\texttt{MaterialLibrary}}{2.8 MaterialLibrary}}\label{materiallibrary}
If your project makes use of master materials, layered materials, or any
form of reusable materials or textures that do not belong to any subset
of assets, these assets should be located in
\texttt{Content/Project/MaterialLibrary}.
This way all `global' materials have a place to live and are easily
located.
\begin{quote}
This also makes it incredibly easy to enforce a `use material instances
only' policy within a project. If all artists and assets should be using
material instances, then the only regular material assets that should
exist are within this folder. You can easily verify this by searching
for base materials in any folder that isn't the
\texttt{MaterialLibrary}.
\end{quote}
The \texttt{MaterialLibrary} doesn't have to consist of purely
materials. Shared utility textures, material functions, and other things
of this nature should be stored here as well within folders that
designate their intended purpose. For example, generic noise textures
should be located in \texttt{MaterialLibrary/Utility}.
Any testing or debug materials should be within
\texttt{MaterialLibrary/Debug}. This allows debug materials to be easily
stripped from a project before shipping and makes it incredibly apparent
if production assets are using them if reference errors are shown.
\subsubsection{2.9 No Empty Folders}\label{no-empty-folders}
There simply shouldn't be any empty folders. They clutter the content
browser.
If you find that the content browser has an empty folder you can't
delete, you should perform the following: 1. Be sure you're using source
control. 1. Immediately run Fix Up Redirectors on your project. 1.
Navigate to the folder on-disk and delete the assets inside. 1. Close
the editor. 1. Make sure your source control state is in sync (i.e.~if
using Perforce, run a Reconcile Offline Work on your content directory)
1. Open the editor. Confirm everything still works as expected. If it
doesn't, revert, figure out what went wrong, and try again. 1. Ensure
the folder is now gone. 1. Submit changes to source control.
\textbf{\hyperref[table-of-contents]{⬆ Back to Top}}
\subsection{3. Blueprints}\label{blueprints-1}
This section will focus on Blueprint classes and their internals. When
possible, style rules conform to
\href{https://docs.unrealengine.com/latest/INT/Programming/Development/CodingStandard}{Epic's
Coding Standard}.
Remember: Blueprinting badly bears blunders, beware! (Phrase by
\href{http://github.com/KorkuVeren}{KorkuVeren})
\subsubsection{Sections}\label{sections-2}
\begin{quote}
3.1 \hyperref[bp-compiling]{Compiling}
\end{quote}
\begin{quote}
3.2 \hyperref[bp-vars]{Variables}
\end{quote}
\begin{quote}
3.3 \hyperref[bp-functions]{Functions}
\end{quote}
\begin{quote}
3.4 \hyperref[bp-graphs]{Graphs}
\end{quote}
\subsubsection{3.1 Compiling}\label{compiling}
All blueprints should compile with zero warnings and zero errors. You
should fix blueprint warnings and errors immediately as they can quickly
cascade into very scary unexpected behavior.
Do \emph{not} submit broken blueprints to source control. If you must
store them on source control, shelve them instead.
Broken blueprints can cause problems that manifest in other ways, such
as broken references, unexpected behavior, cooking failures, and
frequent unneeded recompilation. A broken blueprint has the power to
break your entire game.
\subsubsection{3.2 Variables}\label{variables}
The words \texttt{variable} and \texttt{property} may be used
interchangeably.
\paragraph{Sections}\label{sections-3}
\begin{quote}
3.2.1 \hyperref[bp-vars]{Naming}
\end{quote}
\begin{quote}
3.2.2 \hyperref[bp-vars-editable]{Editable}
\end{quote}
\begin{quote}
3.2.3 \hyperref[bp-vars-categories]{Categories}
\end{quote}
\begin{quote}
3.2.4 \hyperref[bp-vars-access]{Access}
\end{quote}
\begin{quote}
3.2.5 \hyperref[bp-vars-advanced]{Advanced}
\end{quote}
\begin{quote}
3.2.6 \hyperref[bp-vars-transient]{Transient}
\end{quote}
\begin{quote}
3.2.7 \hyperref[bp-vars-config]{Config}
\end{quote}
\paragraph{3.2.1 Naming}\label{naming}
\subparagraph{3.2.1.1 Nouns}\label{nouns}
All non-boolean variable names must be clear, unambiguous, and
descriptive nouns.
\subparagraph{3.2.1.2 PascalCase}\label{pascalcase-1}
All non-boolean variables should be in the form of
\hyperref[terms-cases]{PascalCase}.
3.2.1.2e Examples:
\begin{itemize}
\tightlist
\item
\texttt{Score}
\item
\texttt{Kills}
\item
\texttt{TargetPlayer}
\item
\texttt{Range}
\item
\texttt{CrosshairColor}
\item
\texttt{AbilityID}
\end{itemize}
\subparagraph{\texorpdfstring{3.2.1.3 Boolean \texttt{b}
Prefix}{3.2.1.3 Boolean b Prefix}}\label{boolean-b-prefix}
All booleans should be named in PascalCase but prefixed with a lowercase
\texttt{b}.
Example: Use \texttt{bDead} and \texttt{bEvil}, \textbf{not}
\texttt{Dead} and \texttt{Evil}.
UE4 Blueprint editors know not to include the \texttt{b} in
user-friendly displays of the variable.
\subparagraph{3.2.1.4 Boolean Names}\label{boolean-names}
3.2.1.4.1 General And Independent State Information
All booleans should be named as descriptive adjectives when possible if
representing general information. Do not include words that phrase the
variable as a question, such as \texttt{Is}. This is reserved for
functions.
Example: Use \texttt{bDead} and \texttt{bHostile} \textbf{not}
\texttt{bIsDead} and \texttt{bIsHostile}.
Try to not use verbs such as \texttt{bRunning}. Verbs tend to lead to
complex states.
3.2.1.4.2 Complex States
Do not to use booleans to represent complex and/or dependent states.
This makes state adding and removing complex and no longer easily
readable. Use an enumeration instead.
Example: When defining a weapon, do \textbf{not} use \texttt{bReloading}
and \texttt{bEquipping} if a weapon can't be both reloading and
equipping. Define an enumeration named \texttt{EWeaponState} and use a
variable with this type named \texttt{WeaponState} instead. This makes
it far easier to add new states to weapons.
Example: Do \textbf{not} use \texttt{bRunning} if you also need
\texttt{bWalking} or \texttt{bSprinting}. This should be defined as an
enumeration with clearly defined state names.
\subparagraph{3.2.1.5 Considered Context}\label{considered-context}
All variable names must not be redundant with their context as all
variable references in Blueprint will always have context.
3.2.1.5e Examples:
Consider a Blueprint called \texttt{BP\_PlayerCharacter}.
\textbf{Bad}
\begin{itemize}
\tightlist
\item
\texttt{PlayerScore}
\item
\texttt{PlayerKills}
\item
\texttt{MyTargetPlayer}
\item
\texttt{MyCharacterName}
\item
\texttt{CharacterSkills}
\item
\texttt{ChosenCharacterSkin}
\end{itemize}
All of these variables are named redundantly. It is implied that the
variable is representative of the \texttt{BP\_PlayerCharacter} it
belongs to because it is \texttt{BP\_PlayerCharacter} that is defining
these variables.
\textbf{Good}
\begin{itemize}
\tightlist
\item
\texttt{Score}
\item
\texttt{Kills}
\item
\texttt{TargetPlayer}
\item
\texttt{Name}
\item
\texttt{Skills}
\item
\texttt{Skin}
\end{itemize}
\subparagraph{\texorpdfstring{3.2.1.6 Do \emph{Not} Include Atomic Type
Names}{3.2.1.6 Do Not Include Atomic Type Names}}\label{do-not-include-atomic-type-names}
Atomic or primitive variables are variables that represent data in their
simplest form, such as booleans, integers, floats, and enumerations.
Strings and vectors are considered atomic in terms of style when working
with Blueprints, however they are technically not atomic.
\begin{quote}
While vectors consist of three floats, vectors are often able to be
manipulated as a whole, same with rotators.
\end{quote}
\begin{quote}
Do \emph{not} consider Text variables as atomic, they are secretly
hiding localization functionality. The atomic type of a string of
characters is \texttt{String}, not \texttt{Text}.
\end{quote}
Atomic variables should not have their type name in their name.
Example: Use \texttt{Score}, \texttt{Kills}, and \texttt{Description}
\textbf{not} \texttt{ScoreFloat}, \texttt{FloatKills},
\texttt{DescriptionString}.
The only exception to this rule is when a variable represents `a number
of' something to be counted \emph{and} when using a name without a
variable type is not easy to read.
Example: A fence generator needs to generate X number of posts. Store X
in \texttt{NumPosts} or \texttt{PostsCount} instead of \texttt{Posts} as
\texttt{Posts} may potentially read as an Array of a variable type named
\texttt{Post}.
\subparagraph{3.2.1.7 Do Include Non-Atomic Type
Names}\label{do-include-non-atomic-type-names}
Non-atomic or complex variables are variables that represent data as a
collection of atomic variables. Structs, Classes, Interfaces, and
primitives with hidden behavior such as \texttt{Text} and \texttt{Name}
all qualify under this rule.
\begin{quote}
While an Array of an atomic variable type is a list of variables, Arrays
do not change the `atomicness' of a variable type.
\end{quote}
These variables should include their type name while still considering
their context.
If a class owns an instance of a complex variable, i.e.~if a
\texttt{BP\_PlayerCharacter} owns a \texttt{BP\_Hat}, it should be
stored as the variable type as without any name modifications.
Example: Use \texttt{Hat}, \texttt{Flag}, and \texttt{Ability}
\textbf{not} \texttt{MyHat}, \texttt{MyFlag}, and
\texttt{PlayerAbility}.
If a class does not own the value a complex variable represents, you
should use a noun along with the variable type.
Example: If a \texttt{BP\_Turret} has the ability to target a
\texttt{BP\_PlayerCharacter}, it should store its target as
\texttt{TargetPlayer} as when in the context of \texttt{BP\_Turret} it
should be clear that it is a reference to another complex variable type
that it does not own.
\subparagraph{3.2.1.8 Arrays}\label{arrays}
Arrays follow the same naming rules as above, but should be named as a
plural noun.
Example: Use \texttt{Targets}, \texttt{Hats}, and \texttt{EnemyPlayers},
\textbf{not} \texttt{TargetList}, \texttt{HatArray},
\texttt{EnemyPlayerArray}.
\paragraph{3.2.2 Editable Variables}\label{editable-variables}
All variables that are safe to change the value of in order to configure
behavior of a blueprint should be marked as \texttt{Editable}.
Conversely, all variables that are not safe to change or should not be
exposed to designers should \emph{not} be marked as editable, unless for
engineering reasons the variable must be marked as
\texttt{Expose\ On\ Spawn}.
Do not arbitrarily mark variables as \texttt{Editable}.
\subparagraph{3.2.2.1 Tooltips}\label{tooltips}
All \texttt{Editable} variables, including those marked editable just so
they can be marked as \texttt{Expose\ On\ Spawn}, should have a
description in their \texttt{Tooltip} fields that explains how changing
this value affects the behavior of the blueprint.
\subparagraph{3.2.2.2 Slider And Value
Ranges}\label{slider-and-value-ranges}
All \texttt{Editable} variables should make use of slider and value
ranges if there is ever a value that a variable should \emph{not} be set
to.
Example: A blueprint that generates fence posts might have an editable
variable named \texttt{PostsCount} and a value of -1 would not make any
sense. Use the range fields to mark 0 as a minimum.
If an editable variable is used in a Construction Script, it should have
a reasonable Slider Range defined so that someone can not accidentally
assign it a large value that could crash the editor.
A Value Range only needs to be defined if the bounds of a value are
known. While a Slider Range prevents accidental large number inputs, an
undefined Value Range allows a user to specify a value outside the
Slider Range that may be considered `dangerous' but still valid.
\paragraph{3.2.3 Categories}\label{categories}
If a class has only a small number of variables, categories are not
required.
If a class has a moderate amount of variables (5-10), all
\texttt{Editable} variables should have a non-default category assigned.
A common category is \texttt{Config}.
If a class has a large amount of variables, all \texttt{Editable}
variables should be categorized into sub-categories using the category
\texttt{Config} as the base category. Non-editable variables should be
categorized into descriptive categories describing their usage.
\begin{quote}
You can define sub-categories by using the pipe character
\texttt{\textbar{}}, i.e.~\texttt{Config\ \textbar{}\ Animations}.
\end{quote}
Example: A weapon class set of variables might be organized as:
\begin{verbatim}
|-- Config
| |-- Animations
| |-- Effects
| |-- Audio
| |-- Recoil
| |-- Timings
|-- Animations
|-- State
|-- Visuals
\end{verbatim}
\paragraph{3.2.4 Variable Access Level}\label{variable-access-level}
In C++, variables have a concept of access level. Public means any code
outside the class can access the variable. Protected means only the
class and any child classes can access this variable internally. Private
means only this class and no child classes can access this variable.
Blueprints do not have a defined concept of protected access currently.
Treat \texttt{Editable} variables as public variables. Treat
non-editable variables as protected variables.
\subparagraph{3.2.4.1 Private Variables}\label{private-variables}
Unless it is known that a variable should only be accessed within the
class it is defined and never a child class, do not mark variables as
private. Until variables are able to be marked \texttt{protected},
reserve private for when you absolutely know you want to restrict child
class usage.
\paragraph{3.2.5 Advanced Display}\label{advanced-display}
If a variable should be editable but often untouched, mark it as
\texttt{Advanced\ Display}. This makes the variable hidden unless the
advanced display arrow is clicked.
To find the \texttt{Advanced\ Display} option, it is listed as an
advanced displayed variable in the variable details list.
\paragraph{3.2.6 Transient Variables}\label{transient-variables}
Transient variables are variables that do not need to have their value
saved and loaded and have an initial value of zero or null. This is
useful for references to other objects and actors who's value isn't
known until run-time. This prevents the editor from ever saving a
reference to it, and speeds up saving and loading of the blueprint
class.
Because of this, all transient variables should always be initialized as
zero or null. To do otherwise would result in hard to debug errors.
\paragraph{3.2.8 Config Variables}\label{config-variables}
Do not use the \texttt{Config\ Variable} flag. This makes it harder for
designers to control blueprint behavior. Config variables should only be
used in C++ for rarely changed variables. Think of them as
\texttt{Advanced\ Advanced\ Display} variables.
\subsubsection{3.3 Functions, Events, and Event
Dispatchers}\label{functions-events-and-event-dispatchers}
This section describes how you should author functions, events, and
event dispatchers. Everything that applies to functions also applies to
events, unless otherwise noted.
\paragraph{3.3.1 Function Naming}\label{function-naming}
The naming of functions, events, and event dispatchers is critically
important. Based on the name alone, certain assumptions can be made
about functions. For example:
\begin{itemize}
\tightlist
\item
Is it a pure function?
\item
Is it fetching state information?
\item
Is it a handler?
\item
Is it an RPC?
\item
What is its purpose?
\end{itemize}
These questions and more can all be answered when functions are named
appropriately.
\paragraph{3.3.1.1 All Functions Should Be
Verbs}\label{all-functions-should-be-verbs}
All functions and events perform some form of action, whether its
getting info, calculating data, or causing something to explode.
Therefore, all functions should all start with verbs. They should be
worded in the present tense whenever possible. They should also have
some context as to what they are doing.
\texttt{OnRep} functions, event handlers, and event dispatchers are an
exception to this rule.
Good examples:
\begin{itemize}
\tightlist
\item
\texttt{Fire} - Good example if in a Character / Weapon class, as it
has context. Bad if in a Barrel / Grass / any ambiguous class.
\item
\texttt{Jump} - Good example if in a Character class, otherwise, needs
context.
\item
\texttt{Explode}
\item
\texttt{ReceiveMessage}
\item
\texttt{SortPlayerArray}
\item
\texttt{GetArmOffset}
\item
\texttt{GetCoordinates}
\item
\texttt{UpdateTransforms}
\item
\texttt{EnableBigHeadMode}
\item
\texttt{IsEnemy} -
\href{http://writingexplained.org/is-is-a-verb}{``Is'' is a verb.}
\end{itemize}
Bad examples:
\begin{itemize}
\tightlist
\item
\texttt{Dead} - Is Dead? Will deaden?
\item
\texttt{Rock}
\item
\texttt{ProcessData} - Ambiguous, these words mean nothing.
\item
\texttt{PlayerState} - Nouns are ambiguous.
\item
\texttt{Color} - Verb with no context, or ambiguous noun.
\end{itemize}
\paragraph{\texorpdfstring{3.3.1.2 Property RepNotify Functions Always
\texttt{OnRep\_Variable}}{3.3.1.2 Property RepNotify Functions Always OnRep\_Variable}}\label{property-repnotify-functions-always-onrep_variable}
All functions for replicated with notification variables should have the
form \texttt{OnRep\_Variable}. This is forced by the Blueprint editor.
If you are writing a C++ \texttt{OnRep} function however, it should also
follow this convention when exposing it to Blueprints.
\paragraph{3.3.1.3 Info Functions Returning Bool Should Ask
Questions}\label{info-functions-returning-bool-should-ask-questions}
When writing a function that does not change the state of or modify any
object and is purely for getting information, state, or computing a
yes/no value, it should ask a question. This should also follow
\hyperref[bp-funcs-naming-verbs]{the verb rule}.
This is extremely important as if a question is not asked, it may be
assumed that the function performs an action and is returning whether
that action succeeded.
Good examples:
\begin{itemize}
\tightlist
\item
\texttt{IsDead}
\item
\texttt{IsOnFire}
\item
\texttt{IsAlive}
\item
\texttt{IsSpeaking}
\item
\texttt{IsHavingAnExistentialCrisis}
\item
\texttt{IsVisible}
\item
\texttt{HasWeapon} -
\href{http://grammar.yourdictionary.com/parts-of-speech/verbs/Helping-Verbs.html}{``Has''
is a verb.}
\item
\texttt{WasCharging} -
\href{http://grammar.yourdictionary.com/parts-of-speech/verbs/Helping-Verbs.html}{``Was''
is past-tense of ``be''.} Use ``was'' when referring to `previous
frame' or `previous state'.
\item
\texttt{CanReload} -
\href{http://grammar.yourdictionary.com/parts-of-speech/verbs/Helping-Verbs.html}{``Can''
is a verb.}
\end{itemize}
Bad examples:
\begin{itemize}
\tightlist
\item
\texttt{Fire} - Is on fire? Will fire? Do fire?
\item
\texttt{OnFire} - Can be confused with event dispatcher for firing.
\item
\texttt{Dead} - Is dead? Will deaden?
\item
\texttt{Visibility} - Is visible? Set visibility? A description of
flying conditions?
\end{itemize}
\paragraph{\texorpdfstring{3.3.1.4 Event Handlers and Dispatchers Should
Start With
\texttt{On}}{3.3.1.4 Event Handlers and Dispatchers Should Start With On}}\label{event-handlers-and-dispatchers-should-start-with-on}
Any function that handles an event or dispatches an event should start
with \texttt{On} and continue to follow
\hyperref[bp-funcs-naming-verbs]{the verb rule}. The verb may move to
the end however if past-tense reads better.
\href{http://dictionary.cambridge.org/us/grammar/british-grammar/about-words-clauses-and-sentences/collocation}{Collocations}
of the word \texttt{On} are exempt from following the verb rule.
\texttt{Handle} is not allowed. It is `Unreal' to use \texttt{On}
instead of \texttt{Handle}, while other frameworks may prefer to use
\texttt{Handle} instead of \texttt{On}.
Good examples:
\begin{itemize}
\tightlist
\item
\texttt{OnDeath} - Common collocation in games
\item
\texttt{OnPickup}
\item
\texttt{OnReceiveMessage}
\item
\texttt{OnMessageRecieved}
\item
\texttt{OnTargetChanged}
\item
\texttt{OnClick}
\item
\texttt{OnLeave}
\end{itemize}
Bad examples:
\begin{itemize}
\tightlist
\item
\texttt{OnData}
\item
\texttt{OnTarget}
\item
\texttt{HandleMessage}
\item
\texttt{HandleDeath}
\end{itemize}
\paragraph{3.3.1.5 Remote Procedure Calls Should Be Prefixed With
Target}\label{remote-procedure-calls-should-be-prefixed-with-target}
Any time an RPC is created, it should be prefixed with either
\texttt{Server}, \texttt{Client}, or \texttt{Multicast}. No exceptions.
After the prefix, follow all other rules regarding function naming.
Good examples:
\begin{itemize}
\tightlist
\item
\texttt{ServerFireWeapon}
\item
\texttt{ClientNotifyDeath}
\item
\texttt{MulticastSpawnTracerEffect}
\end{itemize}
Bad examples:
\begin{itemize}
\tightlist
\item
\texttt{FireWeapon} - Does not indicate its an RPC of some kind.
\item
\texttt{ServerClientBroadcast} - Confusing.
\item
\texttt{AllNotifyDeath} - Use \texttt{Multicast}, never \texttt{All}.
\item
\texttt{ClientWeapon} - No verb, ambiguous.
\end{itemize}
\paragraph{3.3.2 All Functions Must Have Return
Nodes}\label{all-functions-must-have-return-nodes}
All functions must have return nodes, no exceptions.
Return nodes explicitly note that a function has finished its execution.
In a world where blueprints can be filled with \texttt{Sequence},
\texttt{ForLoopWithBreak}, and backwards reroute nodes, explicit
execution flow is important for readability, maintenance, and easier
debugging.
The Blueprint compiler is able to follow the flow of execution and will
warn you if there is a branch of your code with an unhandled return or
bad flow if you use return nodes.
In situations like where a programmer may add a pin to a Sequence node
or add logic after a for loop completes but the loop iteration might
return early, this can often result in an accidental error in code flow.
The warnings the Blueprint compiler will alert everyone of these issues
immediately.
\paragraph{3.3.3 No Function Should Have More Than 50
Nodes}\label{no-function-should-have-more-than-50-nodes}
Simply, no function should have more than 50 nodes. Any function this
big should be broken down into smaller functions for readability and
ease of maintenance.
The following nodes are not counted as they are deemed to not increase
function complexity:
\begin{itemize}
\tightlist
\item
Comment
\item
Route
\item
Cast
\item
Getting a Variable
\item
Breaking a Struct
\item
Function Entry
\item
Self
\end{itemize}
\paragraph{3.3.4 All Public Functions Should Have A
Description}\label{all-public-functions-should-have-a-description}
This rule applies more to public facing or marketplace blueprints, so
that others can more easily navigate and consume your blueprint API.
Simply, any function that has an access specificer of Public should have
its description filled out.
\paragraph{\texorpdfstring{3.3.5 All Custom Static Plugin
\texttt{BlueprintCallable} Functions Must Be Categorized By Plugin
Name}{3.3.5 All Custom Static Plugin BlueprintCallable Functions Must Be Categorized By Plugin Name}}\label{all-custom-static-plugin-blueprintcallable-functions-must-be-categorized-by-plugin-name}
If your project includes a plugin that defines \texttt{static}
\texttt{BlueprintCallable} functions, they should have their category
set to the plugin's name or a subset category of the plugin's name.
For example, \texttt{Zed\ Camera\ Interface} or
\texttt{Zed\ Camera\ Interface\ \textbar{}\ Image\ Capturing}.
\subsubsection{3.4 Blueprint Graphs}\label{blueprint-graphs}
This section covers things that apply to all Blueprint graphs.
\paragraph{3.4.1 No Spaghetti}\label{no-spaghetti}
Wires should have clear beginnings and ends. You should never have to
mentally untangle wires to make sense of a graph. Many of the following
sections are dedicated to reducing spaghetti.
\paragraph{3.4.2 Align Wires Not Nodes}\label{align-wires-not-nodes}
Always align wires, not nodes. You can't always control the size and pin
location on a node, but you can always control the location of a node
and thus control the wires. Straight wires provide clear linear flow.
Wiggly wires wear wits wickedly. You can straighten wires by using the
Straighten Connections command with BP nodes selected. Hotkey: Q
Good example: The tops of the nodes are staggered to keep a perfectly
straight white exec line.
\pandocbounded{\includegraphics[keepaspectratio]{styleguide_files/mediabag/bp-graphs-align-wire.png}}
Bad Example: The tops of the nodes are aligned creating a wiggly white
exec line.
\pandocbounded{\includegraphics[keepaspectratio]{styleguide_files/mediabag/bp-graphs-align-wire1.png}}
Acceptable Example: Certain nodes might not cooperate no matter how you
use the alignment tools. In this situation, try to minimize the wiggle
by bringing the node in closer.
\pandocbounded{\includegraphics[keepaspectratio]{styleguide_files/mediabag/bp-graphs-align-wire12.png}}
\paragraph{3.4.3 White Exec Lines Are Top
Priority}\label{white-exec-lines-are-top-priority}
If you ever have to decide between straightening a linear white exec
line or straightening data lines of some kind, always straighten the
white exec line.
\paragraph{3.4.4 Graphs Should Be Reasonably
Commented}\label{graphs-should-be-reasonably-commented}
Blocks of nodes should be wrapped in comments that describe their
higher-level behavior. While every function should be well named so that
each individual node is easily readable and understandable, groups of
nodes contributing to a purpose should have their purpose described in a
comment block. If a function does not have many blocks of nodes and its
clear that the nodes are serving a direct purpose in the function's
goal, then they do not need to be commented as the function name and
description should suffice.
\paragraph{3.4.5 Graphs Should Handle Casting Errors Where
Appropriate}\label{graphs-should-handle-casting-errors-where-appropriate}
If a function or event assumes that a cast always succeeds, it should
appropriately report a failure in logic if the cast fails. This lets
others know why something that is `supposed to work' doesn't. A function
should also attempt a graceful recover after a failed cast if it's known
that the reference being casted could ever fail to be casted.
This does not mean every cast node should have its failure handled. In
many cases, especially events regarding things like collisions, it is
expected that execution flow terminates on a failed cast quietly.
\paragraph{3.4.6 Graphs Should Not Have Any Dangling / Loose / Dead
Nodes}\label{graphs-should-not-have-any-dangling-loose-dead-nodes}
All nodes in all blueprint graphs must have a purpose. You should not
leave dangling blueprint nodes around that have no purpose or are not
executed.
\textbf{\hyperref[table-of-contents]{⬆ Back to Top}}
\subsection{4. Static Meshes}\label{static-meshes}
This section will focus on Static Mesh assets and their internals.
\subsubsection{Sections}\label{sections-4}
\begin{quote}
4.1 \hyperref[s-uvs]{UVs}
\end{quote}
\begin{quote}
4.2 \hyperref[s-lods]{LODs}
\end{quote}
\begin{quote}
4.3 \hyperref[s-modular-snapping]{Modular Socketless Snapping}
\end{quote}
\begin{quote}
4.4 \hyperref[s-collision]{Must Have Collision}
\end{quote}
\begin{quote}
4.5 \hyperref[s-scaled]{Correct Scale}
\end{quote}
\subsubsection{4.1 Static Mesh UVs}\label{static-mesh-uvs}
If Linter is reporting bad UVs and you can't seem to track it down, open
the resulting \texttt{.log} file in your project's \texttt{Saved/Logs}
folder for exact details as to why it's failing. I am hoping to include
these messages in the Lint report in the future.
\paragraph{4.1.1 All Meshes Must Have
UVs}\label{all-meshes-must-have-uvs}
Pretty simple. All meshes, regardless how they are to be used, should
not be missing UVs.
\paragraph{4.1.2 All Meshes Must Not Have Overlapping UVs for
Lightmaps}\label{all-meshes-must-not-have-overlapping-uvs-for-lightmaps}
Pretty simple. All meshes, regardless how they are to be used, should
have valid non-overlapping UVs.
\subsubsection{4.2 LODs Should Be Set Up
Correctly}\label{lods-should-be-set-up-correctly}
This is a subjective check on a per-project basis, but as a general rule
any mesh that can be seen at varying distances should have proper LODs.
\subsubsection{4.3 Modular Socketless Assets Should Snap To The Grid
Cleanly}\label{modular-socketless-assets-should-snap-to-the-grid-cleanly}
This is a subjective check on a per-asset basis, however any modular
socketless assets should snap together cleanly based on the project's
grid settings.
It is up to the project whether to snap based on a power of 2 grid or on
a base 10 grid. However if you are authoring modular socketless assets
for the marketplace, Epic's requirement is that they snap cleanly when
the grid is set to 10 units or bigger.
\subsubsection{4.4 All Meshes Must Have
Collision}\label{all-meshes-must-have-collision}
Regardless of whether an asset is going to be used for collision in a
level, all meshes should have proper collision defined. This helps the
engine with things such as bounds calculations, occlusion, and lighting.
Collision should also be well-formed to the asset.
\subsubsection{4.5 All Meshes Should Be Scaled
Correctly}\label{all-meshes-should-be-scaled-correctly}
This is a subjective check on a per-project basis, however all assets
should be scaled correctly to their project. Level designers or
blueprint authors should not have to tweak the scale of meshes to get
them to confirm in the editor. Scaling meshes in the engine should be
treated as a scale override, not a scale correction.
\textbf{\hyperref[table-of-contents]{⬆ Back to Top}}
\subsection{5. Niagara}\label{niagara}
This section will focus on Niagara assets and their internals.
\subsubsection{Sections}\label{sections-5}
\begin{quote}
5.1 \hyperref[ng-rules]{Naming Rules}
\end{quote}
\subsubsection{5.1 No Spaces, Ever}\label{no-spaces-ever}
As mentioned in \hyperref[00]{00.1 Forbidden Identifiers}, spaces and
all white space characters are forbidden in identifiers. This is
especially true for Niagara systems as it makes working with things
significantly harder if not impossible when working with HLSL or other
means of scripting within Niagara and trying to reference an identifier.
(Original Contribution by
\href{https://github.com/Allar/ue5-style-guide/issues/58}{@dunenkoff\marginpar{\begin{footnotesize}{?quarto-cite:dunenkoff}\vspace{2mm}\par\end{footnotesize}}})
\textbf{\hyperref[table-of-contents]{⬆ Back to Top}}
\subsection{6. Levels / Maps}\label{levels-maps}
\hyperref[terms-level-map]{See Terminology Note} regarding ``levels'' vs
``maps''.
This section will focus on Level assets and their internals.
\subsubsection{Sections}\label{sections-6}
\begin{quote}
6.1 \hyperref[levels-no-errors-or-warnings]{No Errors Or Warnings}
\end{quote}
\begin{quote}
6.2 \hyperref[levels-lighting-should-be-built]{Lighting Should Be Built}
\end{quote}
\begin{quote}
6.3 \hyperref[evels-no-visible-z-fighting]{No Player Visible Z Fighting}
\end{quote}
\begin{quote}
6.4 \hyperref[evels-levels-mp-rules]{Marketplace Specific Rules}
\end{quote}
\subsubsection{6.1 No Errors Or Warnings}\label{no-errors-or-warnings}
All levels should load with zero errors or warnings. If a level loads
with any errors or warnings, they should be fixed immediately to prevent
cascading issues.
You can run a map check on an open level in the editor by using the
console command ``map check''.
Please note: Linter is even more strict on this than the editor is
currently, and will catch load errors that the editor will resolve on
its own.
\subsubsection{6.2 Lighting Should Be
Built}\label{lighting-should-be-built}
It is normal during development for levels to occasionally not have
lighting built. When doing a test/internal/shipping build or any build
that is to be distributed however, lighting should always be built.
\subsubsection{6.3 No Player Visible Z
Fighting}\label{no-player-visible-z-fighting}
Levels should not have any
\href{https://en.wikipedia.org/wiki/Z-fighting}{z-fighting} in all areas
visible to the player.
\subsubsection{6.4 Marketplace Specific
Rules}\label{marketplace-specific-rules}
If a project is to be sold on the UE4 Marketplace, it must follow these
rules.
\subsubsection{6.4.1 Overview Level}\label{overview-level}
If your project contains assets that should be visualized or demoed, you
must have a map within your project that contains the name ``Overview''.
This overview map, if it is visualizing assets, should be set up
according to
\href{http://help.epicgames.com/customer/en/portal/articles/2592186-marketplace-submission-guidelines-preparing-your-assets\#Required\%20Levels\%20and\%20Maps}{Epic's
guidelines}.
For example, \texttt{InteractionComponent\_Overview}.
\subsubsection{6.4.2 Demo Level}\label{demo-level}
If your project contains assets that should be demoed or come with some
sort of tutorial, you must have a map within your project that contains
the name ``Demo''. This level should also contain documentation within
it in some form that illustrates how to use your project. See Epic's
Content Examples project for good examples on how to do this.
If your project is a gameplay mechanic or other form of system as
opposed to an art pack, this can be the same as your ``Overview'' map.
For example, \texttt{InteractionComponent\_Overview\_Demo},
\texttt{ExplosionKit\_Demo}.
\textbf{\hyperref[table-of-contents]{⬆ Back to Top}}
\subsection{7. Textures}\label{textures-1}
This section will focus on Texture assets and their internals.
\subsubsection{Sections}\label{sections-7}
\begin{quote}
7.1 \hyperref[textures-dimension]{Dimensions Are Powers of 2}
\end{quote}
\begin{quote}
7.2 \hyperref[textures-dimension]{Texture Density Should Be Uniform}
\end{quote}
\begin{quote}
7.3 \hyperref[textures-max-size]{Textures Should Be No Bigger than 8192}
\end{quote}
\begin{quote}
7.4 \hyperref[textures-textures-group]{Correct Texture Groups}
\end{quote}
\subsubsection{7.1 Dimensions Are Powers of
2}\label{dimensions-are-powers-of-2}
All textures, except for UI textures, must have its dimensions in
multiples of powers of 2. Textures do not have to be square.
For example, \texttt{128x512}, \texttt{1024x1024}, \texttt{2048x1024},
\texttt{1024x2048}, \texttt{1x512}.
\subsubsection{7.2 Texture Density Should Be
Uniform}\label{texture-density-should-be-uniform}
All textures should be of a size appropriate for their standard use
case. Appropriate texture density varies from project to project, but
all textures within that project should have a consistent density.
For example, if a project's texture density is 8 pixel per 1 unit, a
texture that is meant to be applied to a 100x100 unit cube should be
1024x1024, as that is the closest power of 2 that matches the project's
texture density.
\subsubsection{7.3 Textures Should Be No Bigger than
8192}\label{textures-should-be-no-bigger-than-8192}
No texture should have a dimension that exceeds 8192 in size, unless you
have a very explicit reason to do so. Often, using a texture this big is
simply just a waste of resources.
\subsubsection{7.4 Textures Should Be Grouped
Correctly}\label{textures-should-be-grouped-correctly}
Every texture has a Texture Group property used for LODing, and this
should be set correctly based on its use. For example, all UI textures
should belong in the UI texture group.
\textbf{\hyperref[table-of-contents]{⬆ Back to Top}}
\end{document}