Skip to content

Instantly share code, notes, and snippets.

@talenguyen
Last active June 9, 2025 09:19
Show Gist options
  • Select an option

  • Save talenguyen/510222faab6e7bef9f845f0f2f980704 to your computer and use it in GitHub Desktop.

Select an option

Save talenguyen/510222faab6e7bef9f845f0f2f980704 to your computer and use it in GitHub Desktop.
Unity C# Style Guide Template
using System;
using System.Collections.Generic; // For List
using UnityEngine;
// GLOBAL ENUM EXAMPLE
/// <summary>
/// Describes the state of the game.
/// </summary>
public enum GameState // Pascal case, singular noun
{
MainMenu, // Pascal case
Playing,
Paused,
GameOver
}
// INTERFACE EXAMPLES
/// <summary>
/// Interface for objects that can be killed.
/// </summary>
public interface IKillable // Prefix with "I" and use an adjective
{
bool IsDead { get; } // Property asking a question
void Kill(); // Method starts with a verb
}
/// <summary>
/// Interface for objects that can take damage.
/// </summary>
public interface IDamageable<T> // Prefix with "I" and use an adjective
{
void Damage(T damageTaken); // Method starts with a verb, camel case parameter
}
/// <summary>
/// Example MonoBehaviour class following the style guide.
/// </summary>
public class GameManager : MonoBehaviour, IKillable // Pascal case noun for class name
{
// FIELDS
// Prefer [SerializeField] over public attributes
[SerializeField] private float _spawnInterval = 2.0f;
[SerializeField] private int _maxEnemies = 10;
[SerializeField] private bool _canSpawnEnemies = true; // Prefixed with a verb
private int _currentEnemyCount; // private field with _ prefix, camel case, noun
private float _timeSinceLastSpawn;
private bool _isGameActive; // private boolean with _ prefix, prefixed with a verb
// Example of a public field (less preferred than [SerializeField] for inspector exposure)
public string GameVersion = "1.0.0"; // Pascal case for public field
// PROPERTIES
/// <summary>
/// Gets the current number of enemies. Read-only.
/// </summary>
public int CurrentEnemyCount => _currentEnemyCount; // Expression-bodied property for single line read-only
/// <summary>
/// Gets or sets the maximum number of enemies.
/// </summary>
public int MaxEnemies
{
get => _maxEnemies; // Explicitly implementing getter
set => _maxEnemies = Mathf.Max(0, value); // Explicitly implementing setter
}
/// <summary>
/// Indicates if the game is currently active.
/// </summary>
public bool IsGameActive // Asks a question
{
get { return _isGameActive; }
private set { _isGameActive = value; } // Auto-implemented property syntax for other cases
}
// IKillable implementation
public bool IsDead => _currentHealth <= 0; // Expression-bodied property
private float _currentHealth = 100f; // private field for IKillable implementation
// EVENTS / DELEGATES
/// <summary>
/// Event triggered before the game starts.
/// </summary>
public event Action GameStarting; // Name with a verb phrase, present participle
/// <summary>
/// Event triggered after the game has started.
/// </summary>
public event Action GameStarted; // Name with a verb phrase, past participle
/// <summary>
/// Event triggered when an enemy is spawned, includes the enemy count.
/// </summary>
public event Action<int> EnemySpawned; // Using System.Action delegate
// MONOBEHAVIOUR METHODS
private void Awake()
{
// Initialization code
_currentEnemyCount = 0;
_timeSinceLastSpawn = 0f;
}
private void Start()
{
// Good use of var when type is obvious
var enemyList = new List<GameObject>();
var settings = new Dictionary<string, float>();
// AVOID: potential ambiguity with var
// var currentSettings = GetGameSettings(); // Assuming GetGameSettings() returns a complex or not immediately obvious type
StartGame();
}
private void OnEnable()
{
// Example: Subscribing to an external event (if GameEvents class existed)
// Assuming _gameEvents is an instance of a class like GameEvents from the style guide
// _gameEvents.DoorOpened += GameEvents_DoorOpened;
}
private void OnDisable()
{
// Example: Unsubscribing from an external event
// _gameEvents.DoorOpened -= GameEvents_DoorOpened;
}
private void Update()
{
if (!_isGameActive || !_canSpawnEnemies) return;
_timeSinceLastSpawn += Time.deltaTime;
if (_timeSinceLastSpawn >= _spawnInterval && _currentEnemyCount < _maxEnemies)
{
SpawnEnemy();
_timeSinceLastSpawn = 0f;
}
}
// PUBLIC METHODS
/// <summary>
/// Starts the game.
/// </summary>
public void StartGame() // Starts with a verb
{
if (_isGameActive) return;
OnGameStarting(); // Prefix event raising method with "On"
_isGameActive = true;
Debug.Log("Game Started!");
OnGameStarted(); // Prefix event raising method with "On"
}
/// <summary>
/// Ends the game.
/// </summary>
public void EndGame() // Starts with a verb
{
_isGameActive = false;
Debug.Log("Game Over!");
// Potentially raise a GameOver event here
}
/// <summary>
/// Checks if the maximum number of enemies has been reached.
/// </summary>
/// <returns>True if max enemies reached, false otherwise.</returns>
public bool HasMaxEnemies() // Method returning bool asks a question
{
return _currentEnemyCount >= _maxEnemies;
}
/// <summary>
/// Inflicts damage on the GameManager (as an IKillable entity).
/// </summary>
/// <param name="damageAmount">The amount of damage to inflict.</param>
public void InflictDamage(float damageAmount, bool isCriticalHit) // Parameters are camel case
{
// Local variable, noun
float totalDamage = damageAmount;
if (isCriticalHit) // isCriticalHit is a boolean parameter, prefixed with a verb
{
totalDamage *= 2.0f; // Using a magic number, consider making it a const or field
}
_currentHealth -= totalDamage;
Debug.Log($"GameManager took {totalDamage} damage. Current health: {_currentHealth}");
if (IsDead)
{
Kill();
}
}
// IKillable implementation
public void Kill() // Starts with a verb
{
if (IsDead)
{
Debug.Log("GameManager has been 'killed' (e.g., core destroyed).");
EndGame();
}
}
// PRIVATE METHODS
/// <summary>
/// Spawns a new enemy.
/// </summary>
private void SpawnEnemy() // Starts with a verb
{
_currentEnemyCount++;
Debug.Log($"Enemy spawned. Total enemies: {_currentEnemyCount}");
OnEnemySpawned(_currentEnemyCount); // Prefix event raising method with "On"
}
/// <summary>
/// Raises the GameStarting event.
/// </summary>
private void OnGameStarting() // Prefix with "On" for event raising method
{
GameStarting?.Invoke(); // Using System.Action
}
/// <summary>
/// Raises the GameStarted event.
/// </summary>
private void OnGameStarted() // Prefix with "On" for event raising method
{
GameStarted?.Invoke();
}
/// <summary>
/// Raises the EnemySpawned event.
/// </summary>
/// <param name="enemyCount">The current count of enemies.</param>
private void OnEnemySpawned(int enemyCount) // Prefix with "On" for event raising method
{
EnemySpawned?.Invoke(enemyCount); // Using System.Action<T>
}
// Example of an event handler method (if GameEvents class existed and we were observing it)
// /// <summary>
// /// Handles the DoorOpened event from GameEvents.
// /// </summary>
// private void GameEvents_DoorOpened() // Prefix with subject's name and underscore
// {
// Debug.Log("Notification received: A door was opened!");
// }
}
using UnityEngine;
// Example: Enum conventions
// Use PascalCase for enum names and values, place public enums outside the class, and use a singular noun for the enum name.
public enum PlayerState
{
Idle,
Running,
Jumping,
Dead
}
// Example: Interface conventions
// Use PascalCase for interface names, prefix with 'I' and use an adjective describing the functionality
public interface IDamageable
{
void TakeDamage(int amount);
}
// Example: Class conventions
// Use PascalCase nouns for class names, ensure MonoBehaviour filename matches and only one per file
public class UnityStyleGuideExample : MonoBehaviour
{
//==================== Fields ====================
// Use nouns for variable names
[SerializeField] private int _playerScore;
[SerializeField] private float _movementSpeed;
// Prefix booleans with a verb
[SerializeField] private bool _isJumping;
[SerializeField] private bool _hasPowerUp;
// Use meaningful names. Don’t abbreviate (unless it’s math)
[SerializeField] private string _playerName;
[SerializeField] private int _numberOfLives;
// Use PascalCase for public fields
public int MaxHealth;
public float JumpHeight;
// Use camelCase with _ prefix for private fields
private int _currentHealth;
private float _jumpCooldown;
// Prefer [SerializeField] over public for Inspector exposure
[SerializeField] private int _coinsCollected;
[SerializeField] private bool _canDoubleJump;
private int _experiencePoints;
//==================== Properties ====================
// Example: Properties conventions
// Use expression-bodied property for single line read-only property
public int PlayerScore => _playerScore;
// Use auto-implemented property for read/write
public int Level { get; set; }
// Multi-line property with custom logic, braces aligned
public int ExperiencePoints
{
get { return _experiencePoints; }
set
{
if (value >= 0)
_experiencePoints = value;
}
}
//==================== Events / Delegates ====================
// Example: Events and event handlers conventions
// Name the event with a verb phrase, use System.Action, and prefix raiser with 'On'
public event System.Action DoorOpened;
public event System.Action<int> PlayerScored;
//==================== Monobehaviour Methods ====================
// (Add Unity lifecycle methods here as needed)
//==================== Public Methods ====================
// Use camelCase for local variables
public void UpdatePlayerScore(int score)
{
int newScore = _playerScore + score;
_playerScore = newScore;
}
// Example: Methods conventions
// Start method names with a verb and add context if necessary
public Vector3 GetDirection(Vector3 targetPosition)
{
return (targetPosition - transform.position).normalized;
}
public void FindTarget(string targetTag)
{
GameObject target = GameObject.FindWithTag(targetTag);
// ...additional logic...
}
// Use camelCase for parameters
public void MovePlayer(float moveSpeed)
{
transform.Translate(Vector3.forward * moveSpeed * Time.deltaTime);
}
// Methods returning bool should ask questions and be prefixed with a verb
public bool IsGameOver()
{
return _currentHealth <= 0;
}
public bool HasStartedTurn()
{
return _numberOfLives > 0 && _playerScore > 0;
}
// Method to raise the event, prefixed with 'On'
protected virtual void OnDoorOpened()
{
DoorOpened?.Invoke();
}
protected virtual void OnPlayerScored(int score)
{
PlayerScored?.Invoke(score);
}
// Example observer/handler method, prefixed with subject name and underscore
public void UnityStyleGuideExample_DoorOpened()
{
// Handle door opened event
}
public void UnityStyleGuideExample_PlayerScored(int score)
{
// Handle player scored event
}
//==================== Private Methods ====================
// (Add private helper methods here)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment