Declarations
Access Level Modifiers
Access level modifiers should be explicitly defined at all times, ever if its not needed to compile (private/internal/public etc.)
Using Lines
Keep using lines at the top of your file. Remove unsed lines (most IDE’s show which are not in use).
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
Fields & Variables
Prefer single declaration per line, its easier to follow.
Prefer
private string username;
private string twitterHandle;
Avoid
private string username, twitterHandle;
Properties
Prefer shorthand where possible. Only use braces & vertical spacing where additional logic is required. If a property logic is getting large, consider making it a method instead. You may use [field: SerializeField] to see properties in the inspector, but this should only be used for debugging purposes.
Examples
private string Username { get; set; }
private string Username => userName;
private string TwitterHandle
{
get => twitterHandle;
set => twitterHandle = value;
}
Classes
Exactly one class per source file. Even if it makes classes which are just a declaration. Its easier to find files that digging through other classes to find a hidden class at the bottom of a file.
Interfaces
All interfaces should be prefaced with the letter I.
Enums / FlagEnums
- No prefix or suffix.
- Use
[InspectorName]
attribute to change the name if needed.
- Only store in a class if it is only local to the class in question and not used or called outside of said class, otherwise store in a seperate file for ease of navigation.
Prefer
public enum Direction
{
North,
South,
East,
West,
}
public enum AttackModes
{
// Decimal // Binary
None = 0, // 000000
Melee = 1, // 000001
Ranged = 2, // 000010
Special = 4, // 000100
MeleeAndSpecial = Melee | Special // 000101
}
Avoid
public enum DirectionEnum
{
North,
South,
East,
West,
}
Actions / Events
- Methods handling events should use the prefix “On” and then be named based on the event they are handling, e.g. “OnDoorOpened”.
- Event raising can happen where appropiate in your code or with a raising method with the prefix Raise, e.g. “RaiseDoorOpened”.
// These are event raising methods, e.g. RaiseDoorOpened, RaisePointsScored, etc.
public void RaiseDoorOpened()
{
DoorOpened.Raise(); // Evt
DoorOpened?.Invoke(); // Action
}
public void RaisePointsScored(int points)
{
PointsScored.Raise(points); // Evt
PointsScored?.Invoke(points); // Action
}
// These are event listening methods, e.g. OnDoorOpened, OnPointsScored, etc.
private void OnDoorOpened()
{
// Logic here...
}
private void OnPointsScored(int points)
{
// Logic here...
}
Spacing
Spacing is especially important, as code needs to be easily readable. Seperate elements of your methods where needed to help with clarity & readability. If a method is large, consider spliting the logic into smaller methods for readability.
Indentation
Indentation should be done using tabs โ never spaces.
Blocks
Indentation for blocks uses 4 spaces (1 Tab) for optimal readability
Prefer
for (int i = 0; i < 10; i++)
{
Debug.Log("index=" + i);
}
Avoid
for (int i = 0; i < 10; i++)
{
Debug.Log("index=" + i);
}
Line Wraps
Indentation for line wraps should use 4 spaces (1 Tab) (not the default 8/2 tab)
Prefer
CoolUiWidget widget =
someIncrediblyLongExpression(that, reallyWouldNotFit, on, aSingle, line);
Avoid
CoolUiWidget widget =
someIncrediblyLongExpression(that, reallyWouldNotFit, on, aSingle, line);
Line Length
Lines should be no longer than 120 characters long. You can set this in your IDE if needed.
Vertical Spacing
There should be two blank lines between methods to aid in visual clarity and organization. Whitespace within methods should separate functionality, but having too many sections in a method often means you should refactor into several methods. If there is a section comment after or before a method, only one blank line should be used.
private int health;
private int mana;
/// <summary>
// The health of the user
/// </summary>
public int Health => health;
/// <summary>
// The mana of the user
/// </summary>
public int Mana => mana;
/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
| Methods
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
/// <summary>
// Sets the user's health
/// </summary>
public void SetHealth(int value)
{
health = value;
}
/// <summary>
// Sets the user's mana
/// </summary>
public void SetMana(int value)
{
mana = value;
}
Brace Style
All braces get their own line as it is a C# convention. It is also a lot easier to read at a glance.
Prefer
public class MyClass
{
public void DoSomething()
{
if (someTest)
{
// ...
}
else
{
// ...
}
}
}
Avoid
public class MyClass {
public void DoSomething() {
if (someTest) {
// ...
} else {
// ...
}
}
}
Conditional statements are always required to be enclosed with braces when more then 1 line long. When the logic enclosed is a return/continue it can be on the same line as the statement. If the enclosed logic is a single line that isn’t a return/continue etc you should have braces for clarity.
Prefer
if (someTest)
{
DoSomething();
}
if (someTest)
{
DoSomethingElse();
}
if (someTest) return;
Avoid
if (someTest)
doSomething();
if (someTest) doSomethingElse();
if (someTest)
{
return;
}
Switch Statements
Switch statements come with default a case by default. If the default
case is never reached, be sure to remove it. You don’t need braces for ease case in the switch statement.
Prefer
switch (variable)
{
case 1:
break;
case 2:
break;
}
Avoid
switch (variable)
{
case 1:
break;
case 2:
break;
default:
break;
}
Language
Use US English spelling, even though its the wrong spelling for me being in the UK, the US spelling is more commonly used worldwide.
Prefer
private string color = "red";
Avoid
private string colour = "red";