Code Style
Valk edited this page Apr 28, 2024
·
107 revisions
// Variables accessed from other scripts should be public properties with the exception of Godot
// exports as shown below
public int Property { get; }
// Always use fields when using Godot exports because properties can break with custom defined
// resource types and properties with the get modifier alone cannot be done.
// Below are two examples of what is acceptable
[Export] public int Width;
[Export] int secretId;
// Variables that exist only within the scope of a script should be private fields
// Please do not add the private access modifier on private fields or functions
int field;
void MyFunction()
{
//...
}
// Always write out the entire type unless the below scenario applies
// Using var here is okay because 'options.Actions' returns
// 'Dictionary<int, Dictionary<StringName, Array<InputEvent>>>'
// which is rather a bit much to write out
var actions = options.Actions;
// These are always defined in the main manager script as 'global usings' so there is no need
// to add them to every script
using Godot;
using System;
// Some usings should be local as they are specific to a file
using Newtonsoft.Json;
// As long as the namespace is defined, global usings will be included.
// The line below is called a file-scoped namespace; notice there are no '{ }'
namespace MyProject;
// Lets say 'XYZ' is a user defined class
XYZ.CallDeferred("...");
// The following is undesired because there is no way of using
// nameof(FunctionName) here which means you can not ctrl click
// on FunctionName making it tedious to find the function definition.
// Consider waiting one frame instead or finding an alterative
// My reason to use C# Delegate Events over Godot Signals is the same with CallDeferred,
// you cannot Ctrl + Click to go to the original definition.
// Below is an example of how to setup and use a C# delegate
public partial class UIJob : Node
{
// Define the event
public event Action<int> RaccoonCountChanged;
void OnAddRaccoonButtonPressed()
{
// 'raccoonCount' is a private field defined above
// Add 1 to 'raccoonCount' and notify all listeners that this event was fired
RaccoonCountChanged?.Invoke(++raccoonCount);
}
}
public partial class UIInfo : Node
{
// Listen and do something when the event is fired
uiJob.RaccoonCountChanged += count =>
{
UpdateUI(count);
}
}
public partial class Player : CharacterBody2D
{
// Static members exist for the duration of the applications life which can
// increase memory usage
//
// Static removes the 'modularity' making testability harder and a programmer
// is more prone to using a static where it should not be used
//
// By making this lives property static, this assumes that there will only be
// one player which will make implementing multiplayer much harder later on
public static int Lives { get; set; }
// The Service Provider pattern can be used to avoid static
// Non-persistent services are cleaned up just before the scene changes
public override void _Ready()
{
Global.Services.Add(this, persistent: false);
}
}
// Then in whatever class you want to get player do
Player player = Global.Services.Get<Player>();
int lives = player.Lives; // of course 'Lives' is a non-static property
// Avoid this
public void Foo(){GD.Print("Bar");}
// This is okay
public void Foo()
{
// Use 4 spaces over tabs
GD.Print("Bar");
}
// Please separate very large indentation commits from more sophisticated commits