View on GitHub

unity-coding-standards

A composition of coding standards for programming in Unity3D, acquired from multiple game developers across the community.

Unity3D Coding Standards

An attempt at documenting a composition of coding standards acquired from multiple game developers across the community.

Table of Contents

  1. Code Formatting
  2. Code File Layout
  3. Naming Conventions
  4. Code Documentation
  5. References

Code Formatting

// Avoid
if(playerWasHit) {
    PlaySound(playerHitSound);
    Damage(player, damageAmount);
}
// Prefer
if(playerWasHit)
{
    PlaySound(playerHitSound);
    Damage(player, damageAmount);
}
// Bad
public float Health { get { return health; } }
// Good
public float Health
{
    get
    {
        return health;
    }
}
public float Health
{
    get => health;
    set => health = value;
}
// Bad
if(enemyInRange)
    Explode();
// Good
if(enemyInRange)
{
    Explode();
}
// Avoid
Debug.Log("Player " + playerId + " took a hit from " + damageSource + " for " + damageAmount + " damage.");
// Avoid
Debug.LogFormat("Player {0} took a hit from {1} for {2} damage.", playerId, damageSource, damageAmount);
// Prefer
Debug.Log($"Player {playerId} took a hit from {damageSource} for {damageAmount} damage.");
switch(colorId)
{
    case PlayerBodyColors.White:
        {
            playerBody.SetTexture(whiteTexture);
        }
        break;
    case PlayerBodyColors.Red:
        {
            playerBody.SetTexture(redTexture);
        }
        break;
    default:
        {
            playerBody.SetTexture(defaultTexture);
        }
        break;
}

Code File Layout

// File: AiPathfinder.cs
using System.Collections.Generic;
using UnityEngine;

using WaypointMap = Dictionary<Vector3,Waypoint>;

namespace MyGame.AiNavigation
{
    public class AiPathfinder
    {
        ...
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using ExampleCompany;
using OtherCompany.BoostedInspector;
using MyUtilityLib;
using MyUtilityLib.DebugUtilities;
using MyOtherLib.Patterns;
using ThisProject;
using ThisProject.Audio;
using ThisProject.Combat;

using EntityPrefabMap = Dictionary<EntityType,GameObject>;
public class MyClass : MonoBehaviour
{
    private class MyNestedClass
    {
        ...
    }

    private const int SOME_CONSTANT = 1;

    public enum SomeEnum
    {
        FirstElement,
        SecondElement
    }

    public int SomeProperty
    {
        get => someField;
    }

    private int someField;

    private void Start()
    {
        ...
    }

    public void SomePublicMethod()
    {
        ...
    }

    private void SomePrivateMethod()
    {
        ...
    }
}
// Initialization
private void Initialize()
{
    ...
}

// Core functionality
private void Move(Vector3 direction)
{
    ...
}

// Helper
private bool CheckIfPositionIsWalkable(Vector3 position)
{
    ...
}

Naming Conventions

namespace OpenSoulsGame.Debug
public class RichTextFormatter
public string StringToBold(this string inputString)
public float DefaultSpacing
{
    ...
}
[ConsoleAttribute] private int letterSpacing;
public  int playerId;
private InputHandler playerInput;
private float health;
var name = GetPlayerName(playerId);
public const int MAX_SCENE_OBJECTS = 256;
public class XmlFormatter
public class AiBehaviour
namespace Utilities.Debug
namespace TowerDefenseGame.Combat
namespace TowerDefenseGame.UI
// A class responsible for performing movement on the player character's transform
class PlayerMotor
// An abstract class for implementing behaviors for AI Agents
abstract class AiBehaviourBase
interface IMotorTarget
interface IUiElement
// A method that performs movement on the player character
public void Move(Vector3 movement)
{
    ...
}
// Tipically, the identifier for methods without a return type should be a verb
// A method that converts radians to degrees.
private float RadianToDegrees(float radians)
{
    ...
}
// The identifier helps to understand how the returned value should be interpreted
// A method to determine if a position in the world can be traversed by the player
private bool IsPositionWalkable(Vector3 position)
IEnumerator CO_SpawnPlayer(int playerId)

Code Documentation

// Bad:
p = p + v * dt;
// Good:
position = position + velocity * deltaTime;
// Bad:
pos = Vector3.Lerp(targetEnemy.position, player.GetComponent<AutoMovementController>().targetWaypoint.nextPosition, elapsedTime / max);
// Good:
var waypoint = player.GetComponent<AutoMovementController>().targetWaypoint;
var startPosition = targetEnemy.position;
var finalPosition = waypoint.nextPosition;
var lerpPoint = elapsedTime / maxMovementTime;
position = Vector3.Lerp(startPosition, finalPosition, lerpPoint);
// Bad:
// increment player id
playerId++;
// Good:
// We know that a new player has joined, generate a new identifier.
playerId++;
// Bad:
// Increase current position by the velocity scaled by deltaTime to perform movement.
p = p + v * dt;
// Good:
position = position + velocity * deltaTime;
// Bad:
// Health value should be between 0 and 100.
private int health;

...

this.health = 150;
// Good:
// Base health values should be between 0 and 100.
private int health;

...

// Apply the temporary health buff from consuming potion.
this.health = 150;

References