Template
Template copied to clipboard
Template to be used for all Godot 4 C# starting projects
Template
The template I use when starting a new Godot C# game.
Feature Summary
- Pre-configured project.godot .csproj .editorconfig .gitignore
- Godot Utils
- UIConsole
- Hotkey Management
- Audio Management
- Several Options
- Global Autoload
- Localisation
- Credits Scene
- And lots more!
Setup
- Download and install the latest Godot 4 C# release
- Clone this repository with all its submodules
git clone --recursive https://github.com/ValksGodotTools/Template
If for whatever reason you forget to clone with the --recursive flag. Run the following command below to retrieve the submodules.
git submodule update --init --recursive
Main Menu

Options

Credits

Hotkeys

Services
Stop using static everywhere! Static exists for the lifetime of the application wasting valuable game memory. Instead lets make use of Global.Services.
In the _Ready() of any node add Global.Services.Add(this). (if the script does not extend from node, you can use Global.Services.Add<Type>)
public partial class UIVignette : ColorRect
{
public override void _Ready()
{
// Set persistent to true if this is an autoload script
// (scripts that do not extend from Node are persistent by default)
// Non persistent services will get removed just before the scene is changed
// Example of persistent service: AudioManager; a node like this should exist
// for the entire duration of the game
// However this UIVignette exists within the scene so it should not be persistent
Global.Services.Add(this, persistent: false);
}
public void LightPulse() { ... }
}
Now you can get the instance of UIVignette from anywhere! No static or long GetNode<T> paths involved. It's magic.
UIVignette vignette = Global.Services.Get<UIVignette>();
vignette.LightPulse();
Console Commands
// Simply add the "ConsoleCommand" attribute to any function
// it will be registered as a new console command
// Note to bring up the console in-game press F12
[ConsoleCommand("help")]
void Help()
{
IEnumerable<string> cmds =
Global.Services.Get<UIConsole>().Commands.Select(x => x.Name);
Global.Services.Get<Logger>().Log(cmds.Print());
}
// Console commands can have aliases, this command has a
// alias called "exit"
[ConsoleCommand("quit", "exit")]
void Quit()
{
GetTree().Root.GetNode<Global>("/root/Global").Quit();
}
// Method parameters are supported
[ConsoleCommand("debug")]
void Debug(int x, string y)
{
Global.Services.Get<Logger>().Log($"Debug {x}, {y}");
}
Prefabs
// Load all your scene prefabs here. This script can be found in
// "res://Scripts/Static/Prefabs.cs". Note that music and sounds are
// loaded in very similarily and these scripts can be found in the
// static folder as well.
public static class Prefabs
{
public static PackedScene Options { get; } = Load("UI/options");
static PackedScene Load(string path) =>
GD.Load<PackedScene>($"res://Scenes/Prefabs/{path}.tscn");
}
// Prefabs are instantiated like this
UIOptions options = Prefabs.Options.Instantiate<UIOptions>();
AudioManager
AudioManager audioManager = Global.Services.Get<AudioManager>();
// Play a soundtrack
audioManager.PlayMusic(Music.Menu);
// Play a sound
audioManager.PlaySFX(Sounds.GameOver);
// Set the music volume
audioManager.SetMusicVolume(75);
// Set the sound volume
audioManager.SetSFXVolume(100);
// Gradually fade out all sounds
audioManager.FadeOutSFX();
SceneManager
// Switch to a scene instantly
Global.Services.Get<SceneManager>().SwitchScene("main_menu");
// Switch to a scene with a fade transition
Global.Services.Get<SceneManager>().SwitchScene("level_2D_top_down",
SceneManager.TransType.Fade);
Experimental EventManager
If you like the idea of having a universal static event manager that handles everything then try out the code below in your own project.
Event Enums
public enum EventGeneric
{
OnKeyboardInput
}
public enum EventPlayer
{
OnPlayerSpawn
}
Event Dictionaries
public static class Events
{
public static EventManager<EventGeneric> Generic { get; } = new();
public static EventManager<EventPlayer> Player { get; } = new();
}
Example #1
Events.Generic.AddListener(EventGeneric.OnKeyboardInput, (args) =>
{
GD.Print(args[0]);
GD.Print(args[1]);
GD.Print(args[2]);
}, "someId");
Events.Generic.RemoveListeners(EventGeneric.OnKeyboardInput, "someId");
// Listener is never called because it was removed
Events.Generic.Notify(EventGeneric.OnKeyboardInput, 1, 2, 3);
Example #2
Events.Player.AddListener<PlayerSpawnArgs>(EventPlayer.OnPlayerSpawn, (args) =>
{
GD.Print(args.Name);
GD.Print(args.Location);
GD.Print(args.Player);
});
Events.Player.Notify(EventPlayer.OnPlayerSpawn, new PlayerSpawnArgs(name, location, player));
Contributing
Any kind of contributions are very much welcomed!
Contact me over Discord (valk2023)
Credit
See credits.txt