└── README.md /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | # Unity Style Guide 6 | 7 | This article contains ideas for setting up a projects structure and a naming convention for scripts and assets in Unity. It is derived from [justinwasilenko's](https://github.com/justinwasilenko/Unity-Style-Guide) Unity Style Guide. This version of the guide removes Unreal-related terminology, as well as specific rules which I believe to be overzealous. 8 | 9 | 10 | ## Table of Contents 11 | 12 | > 1. [Introduction](#introduction) 13 | > 1. [Project Structure](#structure) 14 | > 1. [Scripts](#scripts) 15 | > 1. [Asset Naming Conventions](#anc) 16 | > 1. [Asset Workflows](#asset-workflows) 17 | 18 | 19 | ## 1. Introduction 20 | 21 | ### Sections 22 | 23 | > 1.1 [Style](#style) 24 | 25 | > 1.2 [Important Terminology](#importantterminology) 26 | 27 | 28 | ### 1.1 Style 29 | 30 | #### If your project already has a style guide, you should follow it. 31 | 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. 32 | 33 | Style guides should be living documents however and you should propose style guide changes to an existing style guide as well as this guide if you feel the change benefits all usages. 34 | 35 | > ##### *Arguments over style are pointless. There should be a style guide, and you should follow it.* 36 | > [_Rebecca Murphey_](https://rmurphey.com) 37 | 38 | #### All structure, assets, and code in any project should look like a single person created it, no matter how many people contributed. 39 | 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. 40 | 41 | It also allows for more productive creation and maintenance as one does not need to think about style, simply follow 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. 42 | 43 | #### Friends do not let friends have bad style. 44 | If you see someone working either against a style guide or no style guide, try to correct them. 45 | 46 | When working within a team or discussing within a community, it is far easier to help and to ask for help when people are consistent. Nobody likes to help untangle someone's spaghetti code or deal with assets with names they can't understand. 47 | 48 | If you are helping someone who's 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. 49 | 50 | 51 | ### 1.2 Important Terminology 52 | 53 | 54 | #### Prefabs 55 | Unity uses the term Prefab for a system that allows you to create, configure, and store a GameObject complete with all its components, property values, and child GameObjects as a reusable Asset. 56 | 57 | 58 | #### Levels/Maps/Scene 59 | Levels refer to what some people call maps or what Unity calls Scenes. A level contains a collection of objects. 60 | 61 | 62 | #### Serializable 63 | Variables that are Serializable are shown in the Inspector window in Unity. For more information see Unity's documentation on [Serializable](https://docs.unity3d.com/Manual/script-Serialization.html). 64 | 65 | 66 | #### Cases 67 | There are a few different ways you can name things. Here are some common casing types: 68 | 69 | > ##### PascalCase 70 | > Capitalize every word and remove all spaces, e.g. `DesertEagle`, `StyleGuide`, `ASeriesOfWords`. 71 | > 72 | > ##### camelCase 73 | > The first letter is always lowercase but every following word starts with uppercase, e.g. `desertEagle`, `styleGuide`, `aSeriesOfWords`. 74 | > ##### lowercase 75 | > All letters are lowercase, e.g. `deserteagle`, 76 | > ##### _underScore 77 | > The name is prepended by an underscore. The first letter is always lowercase but every following word starts with uppercase, e.g. `_desertEagle`, `_styleGuide`, `_aSeriesOfWords`. 78 | > ##### Snake_case 79 | > Words can arbitrarily start upper or lowercase but words are separated by an underscore, e.g. `desert_Eagle`, `Style_Guide`, `a_Series_of_Words`. 80 | 81 | **[⬆ Back to Top](#table-of-contents)** 82 | 83 | 84 | ## 2. Project Structure 85 | 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. 86 | 87 | In this style, we will be using a structure that relies more on filtering and search abilities of the Project Window for those working with assets to find assets of a specific type instead of another common structure that groups asset types with folders. 88 | 89 | > Using a prefix [naming convention](#asset-name-modifiers), using folders to contain assets of similar types such as `Meshes`, `Textures`, and `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. 90 |
  91 | Assets
  92 |     _Developers(Use a `_`to keep this folder at the top)
  93 |         DeveloperName
  94 |             (Work in progress assets)
  95 |     ProjectName
  96 |             Characters
  97 |             	Anakin
  98 |             FX
  99 |                 Vehicles
 100 |                     Abilities
 101 |                         IonCannon
 102 |                             (Particle Systems, Textures)
 103 |                 Weapons
 104 |             Gameplay
 105 |                 Characters
 106 |                 Equipment
 107 |                 Input
 108 |                 Vehicles
 109 |                     Abilities
 110 |                     Air
 111 |                         TieFighter
 112 |                             (Models, Textures, Materials, Prefabs)
 113 |             _Levels
 114 |                 Frontend
 115 |                 Act1
 116 |                     Level1
 117 |             Lighting
 118 |                 HDRI
 119 |                 Lut
 120 |                 Textures
 121 |             MaterialLibrary
 122 |             	Debug
 123 |             	Shaders
 124 |             Objects
 125 |                 Architecture (Single use big objects)
 126 |                     DeathStar
 127 |                 Props (Repeating objects to fill a level)
 128 |                     ObjectSets
 129 |                         DeathStar
 130 |             Scripts
 131 |                 AI
 132 |                 Gameplay
 133 |                     Input
 134 |                 Tools
 135 |             Sound
 136 |                 Characters
 137 |                 Vehicles
 138 |                     TieFighter
 139 |                         Abilities
 140 |                             Afterburners
 141 |                 Weapons
 142 |             UI
 143 |                 Art
 144 |                     Buttons
 145 |                 Resources
 146 |                     Fonts
 147 |     ExpansionPack (DLC)
 148 |     Plugins
 149 |     ThirdPartySDK  
 150 | 
151 | 152 | 153 | 154 | 155 | The reasons for this structure are listed in the following sub-sections. 156 | 157 | ### Sections 158 | 159 | > 2.1 [Folder Names](#structure-folder-names) 160 | 161 | > 2.2 [Top-Level Folders](#structure-top-level) 162 | 163 | > 2.3 [Developer Folders](#structure-developers) 164 | 165 | > 2.4 [Levels](#levels) 166 | 167 | > 2.5 [Define Ownership](#structure-ownership) 168 | 169 | > 2.6 [`Assets` and `AssetTypes`](#structure-assettypes) 170 | 171 | > 2.7 [Large Sets](#structure-large-sets) 172 | 173 | > 2.8 [Material Library](#structure-material-library) 174 | 175 | > 2.9 [Scene Structure](#scene-structure) 176 | 177 | 178 | 179 | 180 | ### 2.1 Folder Names 181 | These are common rules for naming any folder in the content structure. 182 | 183 | 184 | #### Always Use [PascalCase](#terms-cases) 185 | 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, `DesertEagle`, `RocketPistol`, and `ASeriesOfWords`. 186 | 187 | 188 | #### Never Use Spaces 189 | Re-enforcing [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 `D:\Project` instead of `C:\Users\My Name\My Documents\Unity Projects`. 190 | 191 | 192 | #### Never Use Unicode Characters And Other Symbols 193 | If one of your game characters is named 'Zoë', its folder name should be `Zoe`. Unicode characters can be worse than [Spaces](#2.1.2) for engineering tools and some parts applications don't support Unicode characters in paths either. 194 | 195 | Related to this, if your project has and your computer's user name has a Unicode character (i.e. your name is `Zoë`), any project located in your `My Documents` folder will suffer from this issue. Often simply moving your project to something like `D:\Project` will fix these mysterious issues. 196 | 197 | Using other characters outside `a-z`, `A-Z`, and `0-9` such as `@`, `-`, `_`, `,`, `*`, and `#` can also lead to unexpected and hard to track issues on other platforms, source control, and weaker engineering tools. 198 | 199 | 200 | #### No Empty Folders 201 | There simply shouldn't be any empty folders. They clutter the content browser. 202 | 203 | If you find that the content browser has an empty folder you can't delete, you should perform the following: 204 | 1. Be sure you're using source control. 205 | 1. Navigate to the folder on-disk and delete the assets inside. 206 | 1. Close the editor. 207 | 1. Make sure your source control state is in sync (i.e. if using Perforce, run a Reconcile Offline Work on your content directory) 208 | 1. Open the editor. Confirm everything still works as expected. If it doesn't, revert, figure out what went wrong, and try again. 209 | 1. Ensure the folder is now gone. 210 | 1. Submit changes to source control. 211 | 212 | 213 | 214 | ### 2.2 Use A Top Level Folder For Project Specific Assets 215 | All of a project's assets should exist in a folder named after the project. For example, if your project is named 'Generic Shooter', _all_ of it's content should exist in `Assets/GenericShooter`. 216 | 217 | > The `Developers` folder is not for assets that your project relies on and therefore is not project specific. See [Developer Folders](#2.3) for details about this. 218 | 219 | There are multiple reasons for this approach. 220 | 221 | 222 | #### No Global Assets 223 | 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. 224 | 225 | 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 [`Developer`](#2.3) folder. 226 | 227 | 228 | #### Reduce Migration Conflicts 229 | 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. 230 | 231 | By placing all project specific assets in a top level folder you reduce the chance of migration conflict when importing those assets into a new project. 232 | 233 | 234 | ##### Master Material Example 235 | 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 `Assets/MaterialLibrary/M_Master`. If the target project doesn't have a master material already, this should work without issue. 236 | 237 | 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. 238 | 239 | 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 `Assets/MaterialLibrary/M_Master` as they're instructed to, when a migration is performed there is a great chance of conflict for the previously migrated `Assets/MaterialLibrary/M_Master` asset. 240 | 241 | 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 `Assets/MaterialLibrary/M_Master` when it copies these assets to the other project and it will overwrite the existing asset. 242 | 243 | It is at this point where if the master materials for both projects are incompatible in _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. 244 | 245 | 246 | #### Samples, Templates, and 3rd Party Content Are Risk-Free 247 | An extension to [2.2.2](#2.2.2), if a team member decides to add sample content, template files, or assets they bought from a 3rd party, it is guaranteed that these new assets will not interfere with the project in any way unless your project's top level folder is not uniquely named. 248 | 249 | You can not trust 3rd party content to fully conform to the [top level folder rule](#2.2). There exist many assets that have the majority of their content in a top level folder but also have possibly modified Unity sample content as well as level files polluting the global `Assets` folder. 250 | 251 | When adhering to [2.2](#2.2), the worst 3rd party conflict you can have is if two 3rd party assets both have the same 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. 252 | 253 | #### DLC, Sub-Projects, and Patches Are Easily Maintained 254 | 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. 255 | 256 | 257 | 258 | ### 2.3 Use Developers Folder For Local Testing 259 | 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. 260 | 261 | 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 by everyone on the team to resolve. 262 | 263 | If these modular assets were placed in a Developer folder, the world builder should never of had a reason to use them and the whole issue would never happen. 264 | 265 | Once the assets are ready for use, an artist simply has to move the assets into the project specific folder. This is essentially 'promoting' the assets from experimental to production. 266 | 267 | 268 | 269 | ### 2.4 All [Scene](#terms-level-map) Files Belong In A Folder Called Scenes 270 | Level 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 `Assets/ProjectNameName/Scenes`. 271 | 272 | 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 `Scenes`, such as `Scenes/Campaign1/` or `Scenes/Arenas`, but the most important thing here is that they all exist within `Assets/ProjectNameName/Scenes`. 273 | 274 | 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 levels 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 QA processes. 275 | 276 | 277 | 278 | ### 2.5 Define Ownership 279 | In teams of more than one, define ownership of zone/assets/features. Some assets like scenes or prefabs do not handle simultaneous changes by multiple people very well, creating conflict. Having a single person who can change (or give the right to change) a given assets helps to avoid that problem. 280 | 281 | 282 | 283 | ### 2.6 Do Not Create Folders Called `Assets` or `AssetTypes` 284 | 285 | 286 | #### Creating a folder named `Assets` is redundant. 287 | All assets are assets. 288 | 289 | 290 | #### Creating a folder named `Meshes`, `Textures`, or `Materials` is redundant. 291 | 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. 292 | 293 | Want to view only static mesh in `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 `Control-Click` select two folders in the Content Browser's tree view. 294 | 295 | > This also extends the full path name of an asset for very little benefit. The `SM_` prefix for a static mesh is only three characters, whereas `Meshes/` is seven characters. 296 | 297 | Not doing this also prevents the inevitability of someone putting a static mesh or a texture in a `Materials` folder. 298 | 299 | 300 | 301 | ### 2.7 Very Large Asset Sets Get Their Own Folder Layout 302 | 303 | This can be seen as a pseudo-exception to [2.6](#2.6). 304 | 305 | 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. 306 | 307 | For example, animations that are shared across multiple characters should lay in `Characters/Common/Animations` and may have sub-folders such as `Locomotion` or `Cinematic`. 308 | 309 | > This does not apply to assets like textures and materials. It is common for a `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 [Material Library](#2.8). 310 | 311 | 312 | 313 | ### 2.8 `MaterialLibrary` 314 | 315 | 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 `Assets/ProjectName/MaterialLibrary`. 316 | 317 | This way all 'global' materials have a place to live and are easily located. 318 | 319 | > 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 `MaterialLibrary`. 320 | 321 | The `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 `MaterialLibrary/Utility`. 322 | 323 | Any testing or debug materials should be within `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. 324 | 325 | 326 | 327 | ## 2.9 Scene Structure 328 | Next to the project’s hierarchy, there’s also scene hierarchy. As before, we’ll present you a template. You can adjust it to your needs. Use named empty game objects as scene folders. 329 | 330 |
 331 | Debug
 332 | Management
 333 | UI
 334 | Cameras
 335 | Lights
 336 | World
 337 |     Terrain
 338 |     Props
 339 | Gameplay
 340 | 	Actors
 341 | 	Items
 342 | _Dynamic
 343 | 
344 | 345 | - All empty objects should be located at 0,0,0 with default rotation and scale. 346 | - For empty objects that are only containers for scripts, use “@” as prefix – e.g. @Cheats 347 | - When you’re instantiating an object in runtime, make sure to put it in _Dynamic – do not pollute the root of your hierarchy or you will find it difficult to navigate through it. 348 | 349 | **[⬆ Back to Top](#table-of-contents)** 350 | 351 | 352 | 353 | ## 3. Scripts 354 | 355 | This is a brief section detailing practices that should be followed regarding C# code for the Unity project. Follow [Microsoft's C# Coding Conventions](https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/coding-style/coding-conventions) unless otherwise noted in this guide. 356 | 357 | ### Sections 358 | > 3.1 [Class Organization](#classorganization) 359 | 360 | > 3.2 [Compiling](#compiling) 361 | 362 | > 3.3 [Variables](#variables) 363 | 364 | > 3.4 [Functions](#functions) 365 | 366 | 367 | 368 | ### 3.1 Class Organization 369 | Source files should contain only one public type, although multiple internal classes are allowed. 370 | 371 | Source files should be given the name of the public class, struct, enum or record in the file. 372 | 373 | Organize namespaces according to a well-defined structure. Mirror the namespace in the folder structure that contains the scripts. If a script is in the namespace `Game.Runtime.Input`, the .cs file should be placed at Scripts/Runtime/Input. 374 | 375 | Class members should be ordered logically, and grouped into regions: 376 | * Constant Fields 377 | * Static Fields 378 | * Fields 379 | * Properties 380 | * Events / Delegates 381 | * Constructors 382 | * LifeCycle Methods (Awake, OnEnable, OnDisable, OnDestroy) 383 | * Public Methods 384 | * Internal Methods 385 | * Protected Methods 386 | * Private Methods 387 | * Nested types 388 | 389 | Within each of these groups order by access: 390 | * public 391 | * internal 392 | * protected 393 | * private 394 | ```cs 395 | namespace ProjectName 396 | { 397 | /// 398 | /// Brief summary of what the class does 399 | /// 400 | public class Account 401 | { 402 | #region Fields 403 | 404 | public const string ShippingType = "DropShip"; 405 | 406 | public static string BankName; 407 | public static decimal Reserves; 408 | 409 | public string BankName; 410 | 411 | private float _timeToDie; 412 | 413 | #endregion 414 | 415 | #region Properties 416 | 417 | public string Number {get; set;} 418 | public DateTime DateOpened {get; set;} 419 | public DateTime DateClosed {get; set;} 420 | public decimal Balance {get; set;} 421 | 422 | #endregion 423 | 424 | #region LifeCycle 425 | 426 | public Awake() 427 | { 428 | // ... 429 | } 430 | 431 | #endregion 432 | 433 | #region Public Methods 434 | 435 | public AddObjectToBank() 436 | { 437 | // ... 438 | } 439 | 440 | #endregion 441 | } 442 | } 443 | ``` 444 | 445 | #### Script Templates 446 | To save some time you can overwrite Unity's default script template with your own to automatically setup the namespace and regions etc. See this Unity [support](https://support.unity3d.com/hc/en-us/articles/210223733-How-to-customize-Unity-script-templates) article to learn how. 447 | 448 | 449 | #### Namespace 450 | Use a namespace to ensure your scoping of classes/enum/interface/etc won't conflict with existing ones from other namespaces or the global namespace. Namespaces should be named using PascalCase. The project should at minimum use the projects name for the Namespace to prevent conflicts with any imported Third Party assets. 451 | 452 | #### All Public Functions Should Have A Summary 453 | 454 | Simply, any function that has an access modifier of Public should have its summary filled out, unless it is already documented somewhere else; i.e. Unity functions. 455 | 456 | ```cs 457 | /// 458 | /// Fire a gun 459 | /// 460 | public void Fire() 461 | { 462 | // Fire the gun. 463 | } 464 | ``` 465 | 466 | #### Language 467 | All names, including type, field, function names, as well as any comments should be in US English. 468 | 469 | #### Commenting 470 | Comments, beyond XML docs, should be kept to a minimum. Whenever you feel the need to comment something, first attempt to extract a method out of the unclear section of code. Comment only where this is not possible or sufficient. 471 | 472 | ##### Comment Style 473 | Place the comment on a separate line, not at the end of a line of code. 474 | 475 | Begin comment text with an uppercase letter. 476 | 477 | End comment text with a period. 478 | 479 | Insert one space between the comment delimiter (//) and the comment text, as shown in the following example. 480 | 481 | The // (two slashes) style of comment tags should be used in most situations. Where ever possible, place comments above the code instead of beside it. Here are some examples: 482 | ```cs 483 | // Sample comment above a variable. 484 | private int _myInt = 5; 485 | ``` 486 | 487 | #### Regions 488 | The `#region` directive enables you to collapse and hide sections of code in C# files. The ability to hide code selectively makes your files more manageable and easier to read. All region declarations should have one empty line of spacing above and below. 489 | ```cs 490 | #region Fields 491 | 492 | public int numberField = 1; 493 | 494 | #endregion 495 | ``` 496 | 497 | #### Spacing 498 | Do use a single space after a comma between function arguments. 499 | 500 | Example: `Console.In.Read(myChar, 0, 1);` 501 | * Do not use a space after the parenthesis and function arguments. 502 | * Do not use spaces between a function name and parenthesis. 503 | * Do not use spaces inside brackets. 504 | 505 | #### Attribute Placement 506 | Every attribute should be placed in its own line. 507 | ```cs 508 | // Prefer 509 | [SerializeField] 510 | [Min(0)] 511 | private int _number = 0; 512 | 513 | // Avoid 514 | [SerializeField, Min(0)] 515 | private int _number = 0; 516 | ``` 517 | #### Indentation 518 | Indentations for any block should use tabs, configured as 4 spaces long (Default setting of most IDEs). 519 | 520 | 521 | 522 | ### 3.2 Compiling 523 | All scripts should compile with zero warnings. You should fix script warnings immediately as they can quickly accumulate and pollute the console. Suppress undesirable warnings with `pragma warning disable`. Under no circumstances should you suppress warnings beyond the scope you wish to ignore. 524 | 525 | Do *not* submit broken scripts to source control. If you must store them on source control, shelve them instead. 526 | 527 | ### 3.3 Variables 528 | 529 | #### Variable Naming 530 | 531 | ##### Nouns 532 | All non-boolean variable names must be clear, unambiguous, and descriptive nouns. 533 | 534 | ##### Case 535 | All variables use PascalCase unless marked as [private](#privatevariables) or protected. 536 | Private variables *not* given the attribute `[SerializeField]` use _underScore (`private int _numberOne = 1`). 537 | 538 | Use PascalCase for abbreviations of 4 characters or more (3 chars are both uppercase). 539 | 540 | ##### Considered Context 541 | All variable names must not be redundant with their context as all variable references in the class will always have context. 542 | 543 | ###### Considered Context Examples: 544 | Consider a Class called `PlayerCharacter`. 545 | 546 | **Bad** 547 | 548 | * `PlayerScore` 549 | * `PlayerKills` 550 | * `MyTargetPlayer` 551 | * `MyCharacterName` 552 | * `CharacterSkills` 553 | * `ChosenCharacterSkin` 554 | 555 | All of these variables are named redundantly. It is implied that the variable is representative of the `PlayerCharacter` it belongs to because it is `PlayerCharacter` that is defining these variables. 556 | 557 | **Good** 558 | 559 | * `Score` 560 | * `Kills` 561 | * `TargetPlayer` 562 | * `Name` 563 | * `Skills` 564 | * `Skin` 565 | 566 | #### Variable Access Level 567 | 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. 568 | Variables should only be made public if necessary. 569 | 570 | Prefer to use the attribute `[SerializeField]` instead of making a variable public. 571 | 572 | ###### Access Level Modifiers 573 | Access level modifiers should always be explicit. Never omit a private modifier. 574 | ```cs 575 | // Prefer 576 | private int _number = 0; 577 | 578 | // Avoid 579 | int _number = 0; 580 | ``` 581 | ###### Field Declarations 582 | Prefer single declarations per line. 583 | ```cs 584 | // Prefer 585 | private int _number; 586 | private int _date; 587 | 588 | // Avoid 589 | int _number, _date; 590 | ``` 591 | 592 | ###### Implicitly Typed Variables 593 | Only ever use the `var` keyword inside `foreach` statements. 594 | 595 | 596 | ##### Private Variables 597 | Private variables should be named utilizing _underScore. 598 | 599 | 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 `protected`, reserve private for when you absolutely know you want to restrict child class usage. 600 | 601 | ##### Do _Not_ use Hungarian notation 602 | Do _not_ use Hungarian notation or any other type identification in identifiers 603 | ```cs 604 | // Correct 605 | int counter; 606 | string name; 607 | 608 | // Avoid 609 | int iCounter; 610 | string strName; 611 | ``` 612 | 613 | #### Variables accessible in the Editor 614 | 615 | ##### Variable Slider And Value Ranges 616 | All [Serializable](#serializable) variables should make use of slider and value ranges if there is ever a value that a variable should _not_ be set to. 617 | 618 | Example: A script that generates fence posts might have an editable variable named `PostsCount` and a value of -1 would not make any sense. Use the attributes `[Range(min, max)]`, `[Max(max)]` or `[Min(min)]` to limit the values. 619 | 620 | Do your best to ensure a script cannot be broken by modifying its values in the inspector. 621 | 622 | #### Variable Types 623 | 624 | ##### Booleans 625 | 626 | ###### Boolean Prefix 627 | All booleans should be prefixed with a verb. 628 | 629 | Example: Use `isDead` and `hasItem`, **not** `Dead` and `Item`. 630 | 631 | ###### Boolean Names 632 | All booleans should be named as descriptive adjectives when possible if representing general information. 633 | 634 | Try to not use verbs such as `isRunning`. Verbs tend to lead to complex states. 635 | 636 | ###### Boolean Complex States 637 | Do not use booleans to represent complex and/or dependent states. This makes state adding and removing complex and no longer easily readable. Use a ScriptableObject enum or an enum. 638 | 639 | Example: When defining a weapon, do **not** use `isReloading` and `isEquipping` if a weapon can't be both reloading and equipping. Define an enumeration or [ScriptableObject enum](https://www.youtube.com/watch?v=raQ3iHhE_Kk) named `WeaponState` and use a variable with this type named `WeaponState` instead. This makes it far easier to add new states to weapons. 640 | 641 | ##### Enums 642 | Enums use PascalCase and use singular names for enums and their values. Exception: bit field enums should be plural. Enums can be placed outside the class space to provide global access. Prefer using [ScritableObject enums](https://www.youtube.com/watch?v=raQ3iHhE_Kk) instead of C# enumerations as they're far more extensible. 643 | 644 | ##### Properties 645 | Properties always use CamelCase, irrespective of their access level. 646 | 647 | Example: 648 | ```cs 649 | public enum WeaponType 650 | { 651 | Knife, 652 | Gun 653 | } 654 | 655 | // Enum can have multiple values 656 | [Flags] 657 | public enum Dockings 658 | { 659 | None = 0, 660 | Top = 1, 661 | } 662 | 663 | public WeaponType Weapon 664 | ``` 665 | 666 | ##### Arrays 667 | Arrays follow the same naming rules as above, but should be named as a plural noun. 668 | 669 | Example: Use `Targets`, `Hats`, and `EnemyPlayers`, not `TargetList`, `HatArray`, `EnemyPlayerArray`. 670 | 671 | ##### Interfaces 672 | Interfaces are led with a capital `I` then followed with PascalCase. 673 | 674 | Example: ```public interface IControllable { }``` 675 | 676 | 677 | ### 3.4 Functions, Events, and Event Dispatchers 678 | This section describes how you should author functions, events, and event dispatchers. Everything that applies to functions also applies to events, unless otherwise noted. 679 | 680 | #### Function Naming 681 | 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: 682 | 683 | * Is it a pure function? 684 | * Is it fetching state information? 685 | * Is it a handler? 686 | * What is its purpose? 687 | 688 | These questions and more can all be answered when functions are named appropriately. 689 | 690 | 691 | #### All Functions Should Be Verbs 692 | All functions and events perform some form of action, whether its getting info, calculating data, or causing something to explode. Therefore, all functions should 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. 693 | 694 | Good examples: 695 | 696 | * `Fire` - Good example if in a Character / Weapon class, as it has context. Bad if in a Barrel / Grass / any ambiguous class. 697 | * `Jump` - Good example if in a Character class, otherwise, needs context. 698 | * `Explode` 699 | * `ReceiveMessage` 700 | * `SortPlayerArray` 701 | * `GetArmOffset` 702 | * `GetCoordinates` 703 | * `UpdateTransforms` 704 | * `EnableBigHeadMode` 705 | * `IsEnemy` - ["Is" is a verb.](http://writingexplained.org/is-is-a-verb) 706 | 707 | Bad examples: 708 | 709 | * `Dead` - Is Dead? Will deaden? 710 | * `Rock` - What is this even? 711 | * `ProcessData` - Ambiguous, these words mean nothing. 712 | * `PlayerState` - Nouns are ambiguous. 713 | * `Color` - Verb with no context, or ambiguous noun. 714 | 715 | #### Functions Should Avoid Having More Than A Single Level Of Indentation 716 | When writing a function, avoid having multiple levels of indentation. This is not always possible, but can be avoided in the vast majority of cases. Having at most a single level of indentation makes functions more readable. 717 | 718 | #### Functions Returning Bool Should Ask Questions 719 | 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 [the verb rule](#function-verbrule). 720 | 721 | 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. 722 | 723 | Good examples: 724 | 725 | * `IsDead` 726 | * `IsOnFire` 727 | * `IsAlive` 728 | * `IsSpeaking` 729 | * `IsHavingAnExistentialCrisis` 730 | * `IsVisible` 731 | * `HasWeapon` - ["Has" is a verb.](http://grammar.yourdictionary.com/parts-of-speech/verbs/Helping-Verbs.html) 732 | * `WasCharging` - ["Was" is past-tense of "be".](http://grammar.yourdictionary.com/parts-of-speech/verbs/Helping-Verbs.html) Use "was" when referring to 'previous frame' or 'previous state'. 733 | * `CanReload` - ["Can" is a verb.](http://grammar.yourdictionary.com/parts-of-speech/verbs/Helping-Verbs.html) 734 | 735 | Bad examples: 736 | 737 | * `Fire` - Is on fire? Will fire? Do fire? 738 | * `OnFire` - Can be confused with event dispatcher for firing. 739 | * `Dead` - Is dead? Will deaden? 740 | * `Visibility` - Is visible? Set visibility? A description of flying conditions? 741 | 742 | #### Event Handlers and Dispatchers Should Start With `On` 743 | Any function that handles an event or dispatches an event should start with `On` and continue to follow [the verb rule](#function-verbrule). 744 | 745 | Good examples: 746 | 747 | * `OnDeath` - Common collocation in games 748 | * `OnPickup` 749 | * `OnReceiveMessage` 750 | * `OnMessageRecieved` 751 | * `OnTargetChanged` 752 | * `OnClick` 753 | * `OnLeave` 754 | 755 | Bad examples: 756 | 757 | * `OnData` 758 | * `OnTarget` 759 | 760 | #### Parameter Naming 761 | All parameters should be named utilizing camelCase. Otherwise, utilize the same good-practices laid out above regarding function naming. 762 | 763 | #### Braces 764 | Every brace should get it's own line, as per C# convention. 765 | ```cs 766 | // Prefer 767 | private void Method() 768 | { 769 | if (condition) 770 | { 771 | } 772 | } 773 | 774 | // Avoid 775 | private void Method() { 776 | if (condition) { 777 | } 778 | } 779 | ``` 780 | Futhermore, *all* calls should be enclosed within braces, with the exception of flow control keywords, like `return`, `continue`, `break`, etc. 781 | ```cs 782 | // Prefer 783 | private void Method() 784 | { 785 | if (!condition) return; 786 | DoSomething(); 787 | } 788 | 789 | // Avoid 790 | private void Method() 791 | { 792 | if (condition) DoSomething(); 793 | else 794 | { 795 | return; 796 | } 797 | } 798 | ``` 799 | #### Line Wrapping 800 | No line should be longer than 120 characters. Wrap lines longer than this length. 801 | 802 | **[⬆ Back to Top](#table-of-contents)** 803 | 804 | 805 | 806 | ## 4. Asset Naming Conventions 807 | 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. 808 | 809 | Most things are prefixed with the prefix generally being an acronym of the asset type followed by an underscore. 810 | 811 | **Assets use [PascalCase](#cases)** 812 | 813 | 814 | 815 | ### 4.1 Base Asset Name - `Prefix_BaseAssetName_Variant_Suffix` 816 | All assets should have a _Base Asset Name_. A Base Asset Name represents a logical grouping of related assets. Any asset that is part of this logical group 817 | should follow the the standard of `Prefix_BaseAssetName_Variant_Suffix`. 818 | 819 | Keeping the pattern `Prefix_BaseAssetName_Variant_Suffix` in mind and using common sense is generally enough to warrant good asset names. Here are some detailed rules regarding each element. 820 | 821 | `Prefix` and `Suffix` are to be determined by the asset type through the following [Asset Name Modifier](#asset-name-modifiers) tables. 822 | 823 | `BaseAssetName` should be determined by 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 `BaseAssetName` of `Bob`. 824 | 825 | For unique and specific variations of assets, `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 `Bob` as the `BaseAssetName` but include a recognizable `Variant`. An 'Evil' skin would be referred to as `Bob_Evil` and a 'Retro' skin would be referred to as `Bob_Retro`. 826 | 827 | For unique but generic variations of assets, `Variant` is a two digit number starting at `01`. For example, if you have an environment artist generating nondescript rocks, they would be named `Rock_01`, `Rock_02`, `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. 828 | 829 | 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 `Flooring` with chained variants such as `Flooring_Marble_01`, `Flooring_Maple_01`, `Flooring_Tile_Squares_01`. 830 | 831 | 832 | #### Examples 833 | 834 | ##### Character 835 | 836 | | Asset Type | Asset Name | 837 | | ------------------------ | ------------ | 838 | | Skeletal Mesh | SK_Bob | 839 | | Material | M_Bob | 840 | | Texture (Diffuse/Albedo) | T_Bob_D | 841 | | Texture (Normal) | T_Bob_N | 842 | | Texture (Evil Diffuse) | T_Bob_Evil_D | 843 | 844 | ##### Prop 845 | 846 | | Asset Type | Asset Name | 847 | | ------------------------ | ------------ | 848 | | Static Mesh (01) | SM_Rock_01 | 849 | | Static Mesh (02) | SM_Rock_02 | 850 | | Static Mesh (03) | SM_Rock_03 | 851 | | Material | M_Rock | 852 | | Material Instance (Snow) | MI_Rock_Snow | 853 | 854 | 855 | ### 4.2 Asset Name Modifiers 856 | 857 | When naming an asset use these tables to determine the prefix and suffix to use with an asset's [Base Asset Name](#base-asset-name). 858 | 859 | #### Sections 860 | 861 | > 4.2.1 [Most Common](#anc-common) 862 | 863 | > 4.2.2 [Animations](#anc-animations) 864 | 865 | > 4.2.3 [Artificial Intelligence](#anc-ai) 866 | 867 | > 4.2.4 [Prefabs](#anc-prefab) 868 | 869 | > 4.2.5 [Materials](#anc-materials) 870 | 871 | > 4.2.6 [Textures](#anc-textures) 872 | 873 | > 4.2.7 [Miscellaneous](#anc-misc) 874 | 875 | > 4.2.8 [Physics](#anc-physics) 876 | 877 | > 4.2.9 [Audio](#anc-audio) 878 | 879 | > 4.2.10 [User Interface](#anc-ui) 880 | 881 | > 4.2.11 [Effects](#anc-effects) 882 | 883 | 884 | #### Most Common 885 | 886 | | Asset Type | Prefix | Suffix | Notes | 887 | | ----------------------- | ---------- | ---------- | -------------------------------- | 888 | | Level / Scene | * | | [Should be in a folder called Scenes.](#levels) e.g. `Scenes/A4_C17_Parking_Garage.unity` | 889 | | Level (Persistent) | | _P | | 890 | | Level (Audio) | | _Audio | | 891 | | Level (Lighting) | | _Lighting | | 892 | | Level (Geometry) | | _Geo | | 893 | | Level (Gameplay) | | _Gameplay | | 894 | | Prefab | PF_ | | | 895 | | Audio Clip | AUC_ | | | 896 | | Material | M_ | | | 897 | | Static Mesh | SM_ | | | 898 | | Skeletal Mesh | SK_ | | | 899 | | Texture | T_ | _? | See [Textures](#anc-textures) | 900 | | Particle System | PS_ | | | 901 | 902 | 903 | 904 | #### 4.2.1a 3D Models (FBX Files) 905 | 906 | PascalCase 907 | 908 | | Asset Type | Prefix | Suffix | Notes | 909 | | ------------- | ------ | ------ | ----- | 910 | | Characters | CH_ | | | 911 | | Vehicles | VH_ | | | 912 | | Weapons | WP_ | | | 913 | | Static Mesh | SM_ | | | 914 | | Skeletal Mesh | SK_ | | | 915 | | Skeleton | SKEL_ | | | 916 | | Rig | RIG_ | | | 917 | 918 | 919 | 920 | #### 4.2.2 Animations 921 | | Asset Type | Prefix | Suffix | Notes | 922 | | -------------------- | ------ | ------ | ----- | 923 | | Animation Clip | A_ | | | 924 | | Animation Controller | AC_ | | | 925 | | Avatar Mask | AM_ | | | 926 | | Morph Target | MT_ | | | 927 | 928 | 929 | 930 | #### 4.2.6 Textures 931 | | Asset Type | Prefix | Suffix | Notes | 932 | | ----------------------- | ---------- | ---------- | -------------------------------- | 933 | | Texture | T_ | | | 934 | | Texture (Diffuse/Albedo/Base Color)| T_ | _D | | 935 | | Texture (Normal) | T_ | _N | | 936 | | Texture (Roughness) | T_ | _R | | 937 | | Texture (Alpha/Opacity) | T_ | _A | | 938 | | Texture (Ambient Occlusion) | T_ | _AO | | 939 | | Texture (Bump) | T_ | _B | | 940 | | Texture (Emissive) | T_ | _E | | 941 | | Texture (Mask) | T_ | _M | | 942 | | Texture (Specular) | T_ | _S | | 943 | | Texture (Packed) | T_ | _* | See notes below about [packing](#anc-textures-packing). | 944 | | Texture Cube | TC_ | | | 945 | | Media Texture | MT_ | | | 946 | | Render Texture | RT_ | | | 947 | 948 | 949 | 950 | #### 4.2.6.1 Texture Packing 951 | 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. `_ERO`. 952 | 953 | > It is generally acceptable to include an Alpha/Opacity layer in your Diffuse/Albedo's alpha channel and as this is common practice, adding `A` to the `_D` suffix is optional. 954 | 955 | 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. 956 | 957 | 958 | #### 4.2.7 Miscellaneous 959 | 960 | | Asset Type | Prefix | Suffix | Notes | 961 | | ------------------------------- | ------ | ------ | ----- | 962 | | Universal Render Pipeline Asset | URP_ | | | 963 | | Post Process Volume Profile | PP_ | | | 964 | | User Interface | UI_ | | | 965 | 966 | 967 | #### 4.2.8 Physics 968 | 969 | | Asset Type | Prefix | Suffix | Notes | 970 | | ----------------- | ------ | ------ | ----- | 971 | | Physical Material | PM_ | | | 972 | 973 | 974 | 975 | #### 4.2.9 Audio 976 | 977 | | Asset Type | Prefix | Suffix | Notes | 978 | | -------------- | ------ | ------ | ------------------------------------------------------------ | 979 | | Audio Clip | AUC_ | | | 980 | | Audio Mixer | MIX_ | | | 981 | | Dialogue Voice | DV_ | | 982 | 983 | 984 | #### 4.2.10 User Interface 985 | | Asset Type | Prefix | Suffix | Notes | 986 | | ---------------- | ------ | ------ | ----- | 987 | | Font | FNT_ | | | 988 | | Texture (Sprite) | T_ | _GUI | | 989 | 990 | 991 | #### 4.2.11 Effects 992 | | Asset Type | Prefix | Suffix | Notes | 993 | | --------------- | ------ | ------ | ----- | 994 | | Particle System | PS_ | | | 995 | **[⬆ Back to Top](#table-of-contents)** 996 | 997 | 998 | 999 | ## 5. Asset Workflows 1000 | 1001 | This section describes best practices for creating and importing assets usable in Unity. 1002 | 1003 | 1004 | ### Sections 1005 | 1006 | > 5.1 [Unity Asset Import Settings](#unityimport) 1007 | > 1008 | > 5.2 [Textures](#textures) 1009 | > 1010 | > 5.3 [Audio](#audio) 1011 | 1012 | 1013 | 1014 | ### 5.1 Unity Asset Import Settings 1015 | 1016 | Unity's [AssetPostprocessor](https://docs.unity3d.com/ScriptReference/AssetPostprocessor.html) lets you hook into the import pipeline and run scripts prior to or after importing assets. This allows you to enforce import settings when assets are first imported into the project. For example textures that end with `_N` can be marked as a Normal Map on import. 1017 | 1018 | 1019 | ### 5.2 Textures 1020 | 1021 | * Textures follow the [naming convention](#anc-textures) found above. 1022 | * They are a power of two (For example, 512 x 512 or 256 x 1024). 1023 | * Use Texture Atlases wherever possible. 1024 | * 3D software should point to the Unity project textures for consistency when you save or export. 1025 | * It is better to resize the texture in Photoshop then to use Unity’s compression options when the in game texture resolution is already known. This reduces the file size and import time of the texture into Unity. 1026 | * When working with a high-resolution source PSD outside your Unity project use the same name for both the high-resolution and the imported Unity file. This allows quick iteration when swapping between the 2 textures. 1027 | 1028 | More information for importing textures can be found here: [https://docs.unity3d.com/Manual/ImportingTextures.html](https://docs.unity3d.com/Manual/ImportingTextures.html) 1029 | 1030 | Textures requiring the use of a Alpha channel should follow this guide: [https://docs.unity3d.com/Manual/HOWTO-alphamaps.html](https://docs.unity3d.com/Manual/HOWTO-alphamaps.html) 1031 | 1032 | ##### Texture File Format 1033 | 1034 | Ideally, all textures should be of the .PSD format. This facilitates quick iteration by artists. No layers should be included and only one Alpha channel in the imported file. 1035 | 1036 | **[⬆ Back to Top](#table-of-contents)** 1037 | 1038 | 1039 | ### 5.3 Audio 1040 | 1041 | Only import uncompressed audio files in to Unity using WAV or AIFF formats. 1042 | 1043 | Great guide on [Unity Audio Import Optimization](https://www.gamasutra.com/blogs/ZanderHulme/20190107/333794/Unity_Audio_Import_Optimisation__getting_more_BAM_for_your_RAM.php) 1044 | 1045 | **[⬆ Back to Top](#table-of-contents)** 1046 | 1047 | 1048 | 1049 | #### Article References: 1050 | https://unity3d.com/learn/tutorials/topics/tips/large-project-organisation 1051 | https://github.com/Allar/ue4-style-guide 1052 | http://www.arreverie.com/blogs/unity3d-best-practices-folder-structure-source-control/ 1053 | --------------------------------------------------------------------------------