The Ultimate Godot C# Setup Guide
Update: Since posting this article, a new VSCode extension has been released which may simplify some of the steps below. I have been using Rider instead of VSCode so I have not had a chance to try it out first hand and update this article with the new information.
There are a few different guides out there for setting up Godot but I feel like many don’t give you all of the nitty gritty details needed to get a great workflow. This guide is a bit long but it will set you up with the following:
- Run your game right from VSCode.
- Breakpoint debugging in VSCode.
- Crash logs when you share your game.
- Advanced code analysis/automated refactoring with Roslynator. For those familiar with Resharper this is an open source alternative that supports VSCode.
I have tested this setup on Windows and Linux. If you have any issues on other platforms message me on discord @giulianob#9552. If you’re looking for just a template, head on over to the sample Github repo.
Step 1) Install VSCode #
Download the latest version of VSCode from the official website and complete the installation.
Windows users will also need to download the NuGet command line utility. Save the nuget.exe
to a directory you will remember for example c:\bin\nuget.exe
.
Step 2) Download Godot #
Download the latest version of Godot with Mono and extract it to a directory of your choice.
If you’re on Windows then install the Visual Studio Build Tools. For other platforms, install the Mono SDK.
Step 3) Configure Godot Project #
Start up Godot and create a new project or open your existing project.
There are a few settings we should change to work with VSCode and improve our workflow.
- Go to Editor menu > Editor Settings
- Under Mono > Builds
- Build Tool: Select either “MSBuild (VS Build Tools)” if on Windows or “MSBuild (Mono)” for other platforms.
- Under Mono > Editor
- External Editor: Visual Studio Code
- Under Text Editor > Files
- Open Dominant Script On Scene Change: Uncheck
- Close the editor settings dialog
- Go to Project menu > Project Settings
- Under Logging > File Logging
- Enable File Logging: Check. This will make it easier to track down certain errors that crash your game unexpectedly. Feel free to lower the “Max Log Files” setting.
- Under Mono > Debugger Agent
- Port: 23685
- Wait Timeout: 3000
Step 4) Install MonoDebuggerQM Addon #
This is an addon that gives us a shortcut to the “Mono > Debugger Agent > Wait For Debugger” setting. We’ll need to toggle this setting whenever we would like to perform a debugging session.
- Download the latest release of MonoDebuggerQM.
- Extract the zip to the
addons
folder of your project. For example if your project is located atc:\myproject
then you should have ac:\myproject\addons\MonoDebuggerQM-1.0.1\
directory after extracting the zip. - Go to Project menu > Project Settings > Plugins and change the
Status
of the MonoDebugger plugin toActive
. If you don’t see the plugin make sure you extracted it to the right location.
Step 5) Configure C# Project #
Let’s create your initial scene. Just create a scene with a simple Node2D
or anything you like. Click Play
or press F5
and make sure the game runs.
Now let’s start setting up the C# project.
- Right click on your scene root and click
Attach Script
- Change the
Language
to C# and click Create.
After this happens a new option is available to us that we should change.
- Go to Project menu > Project Settings
- Under Mono > Project
- Auto Update Project: Uncheck. This will make it so Godot doesn’t automatically add or remove files from our csproj. It often fails to do it correctly so we’ll do it in a simpler way.
Step 6) Configure VSCode #
VSCode should have opened when we created our script, if it didn’t, just double click on your script in the FileSystem
view or click on the script icon on your root node.
- Go to the Extensions tab on the left hand side.
- Install the following extensions:
- C# (by Microsoft)
- Mono Debug (by Microsoft)
Step 7) Configure csproj
File #
Now let’s configure our csproj file to include some extra goodies.
- Open your
.csproj
file. If your project is named MyGodotGame then the file will be calledMyGodotGame.csproj
. - Under the first
<PropertyGroup>
change the following line
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
to
<Configuration Condition=" '$(Configuration)' == '' ">Tools</Configuration>
This is technically not required but if you ever build your own addons you will not receive Intellisense unless you change the project default to Tools
instead of Debug
like we did above.
- Add the following lines after the
<Configuration ..
line we just edited above:
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<LangVersion>7.3</LangVersion>
This will enable some newer C# features that are not available in the default settings of the csproj file.
- Find the last
<ItemGroup>
which should contain the.cs
file you created. For example mine is:
<ItemGroup>
<Compile Include="Default.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
change it to
<ItemGroup>
<Compile Include="**\*.cs" />
</ItemGroup>
This option configures our project to build every .cs
file it finds and gets around that unreliable setting we disabled earlier to auto update the project file.
You can view my full csproj for reference on Github.
Switch back to Godot and make sure you can still run your game. If you get any Godot editor crashes now or in the future try deleting your .mono
directory.
Step 8) Configure VSCode Launching/Debugging #
Let’s configure the ability to run your game right from VSCode.
- In VSCode, click on Debug menu > Open Configurations
- If you don’t yet have a
launch.json
it will ask you to choose a template. Choose anything, we’ll be replacing the contents. - Replace the contents of the
launch.json
file with this one from Github. I’ll explain this file in more detail later.- Windows Users: Replace the path to the Godot
.exe
to wherever you have Godot installed. - Linux Users: Replace the path to the Godot
.exe
withgodot-mono
or wherever you have Godot installed.
- Windows Users: Replace the path to the Godot
- Click on Terminal menu > Configure Tasks…
- Once again if you don’t have a
tasks.json
yet defined then choose to create a new one. - Replace the contents of the
tasks.json
file with this one from Github.- Windows Users: Replace the location of
nuget.exe
with wherever you saved it from step 1. The location toMsBuild.exe
may need to be updated as well if you have installed a different version of Build tools for Visual Studio. - Linux Users: Just simply use
msbuild
andnuget
for the command. They should be installed in your/usr/local/bin
directory.
- Windows Users: Replace the location of
- Open your workspace settings by pressing
Ctrl+Shift+P
(to open the command palette) and typing>Preferences> Open Workspace Settings
then add the following to yoursettings.json
{
"mono-debug.exceptionOptions": {
"System.ArithmeticException": "always",
"System.ArrayTypeMismatchException": "always",
"System.DivideByZeroException": "always",
"System.Exception": "always",
"System.IndexOutOfRangeException": "always",
"System.InvalidCastException": "always",
"System.NullReferenceException": "always",
"System.OutOfMemoryException": "always",
"System.OverflowException": "always",
"System.StackOverflowException": "always",
"System.SystemException": "always",
"System.TypeInitializationException": "always"
}
}
These settings will make sure that the debugger pauses if you receive any exceptions in your game. Typically the game will just crash and you may not even get a stacktrace which makes it extremely difficult to debug.
Click on the Debug icon on the left hand menu bar and change the Debug configuration to
Run and Attach
Switch back to Godot for just a second and check the “Wait for Debugger” option on the top-right Debugger menu that was added by the MonoDebugger addon.
We’re all set up and we should be able to run our project right from VSCode!
Open your main C# file and add the following code
public override void _Ready()
{
var name = "Godot";
GD.PrintS("Hello", name);
}
Add a breakpoint by clicking on the margin or pressing F9
on the print line. Start the project by hitting the Start Debugging
play button or F5
. Your code should stop at your breakpoint, for example:
You can see on the left hand side all of your local variables. You can add other variables to watch in the Watch window or use the Debug Console.
To see the output of your code, you will need to switch the Debug Console to the Run
configuration.
Basically what is happening is that we have three different configurations in the launch.json
.
-
Run
: Starts the Godot editor from VSCode -
Attach
: Starts the Mono debugger in VSCode. The debugger listens for connections that your game establishes when you have theWait For Debugger
option enabled in Godot. -
Run and Attach
: This will run the two configurations above to both start the debugger and your game.
We have to switch between the two configurations to see the output because we are actually running both the Run and the Attach task at the same time. If anyone has a better solution for this please let me know!
Now to stop debugging you have to either click the Stop button twice or press Shift+F5
twice. If you just try to close the game you will notice that it just freezes.
Anytime you switch back to Godot and wish to run the project from Godot itself then you have the following options.
- Option 1) Disable the “Wait for Debugger” option otherwise your game will run for a few seconds then quit because it cannot connect to the debugger. You will get a socket timeout error.
- Option 2) Change VSCode to use the “Attach” task, hit
F5
, then run Godot so it can attach to the debugger with the “Wait for Debugger” option enabled. If you do this, you will need to start the VSCode debugger every time you restart your game in Godot. I typically just disable the “Wait for Debugger” option if I’m working within Godot and enable when in VSCode.
Step 9) Install Roslynator (Optional) #
Roslynator is an open source static analysis tool that can also perform some automatic code fixes. If you have experience with Resharper it’s an open source alternative that has much better performance.
To install Roslynator:
- Open your
csproj
file and add the following: In the first<PropertyGroup>
add
<CodeAnalysisRuleSet>roslynator.ruleset</CodeAnalysisRuleSet>
Then add a new <ItemGroup>
with the following
<ItemGroup>
<PackageReference Include="Roslynator.Analyzers">
<Version>2.2.0</Version>
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
At the time of this post Roslynator is at version 2.2.0 but feel free to install a newer version if available.
You can see my full csproj file for reference.
- Create a new file in the root of your project called
roslynator.ruleset
. I recommend adding the following content in this file:
<?xml version="1.0" encoding="utf-8"?>
<RuleSet Name="Rules for Project" ToolsVersion="15.0">
<Rules AnalyzerId="Microsoft.CodeAnalysis.CSharp.Features" RuleNamespace="Microsoft.CodeAnalysis.CSharp.Features">
<Rule Id="IDE0060" Action="None" />
<Rule Id="IDE0005" Action="Info" />
<Rule Id="IDE0051" Action="None" />
<Rule Id="IDE0004" Action="Info" />
<Rule Id="RCS1129" Action="None" />
<Rule Id="RCS1074" Action="Info" />
</Rules>
<Rules AnalyzerId="Roslynator.CSharp.Analyzers" RuleNamespace="Roslynator.CSharp.Analyzers">
<Rule Id="RCS1090" Action="None" />
<Rule Id="RCS1079" Action="None" />
<Rule Id="RCS1171" Action="None" />
<Rule Id="RCS1036" Action="None" />
<Rule Id="RCS1037" Action="None" />
<Rule Id="RCS1124" Action="None" />
<Rule Id="RCS1096" Action="None" />
</Rules>
</RuleSet>
This file defines some overrides to the default rules. For example, you may not like some of the warnings Roslynator gives you. The file above are some rules that I personally disable or lower the severity to Info.
You can start with a blank ruleset (just make sure you have the root RuleSet
element) and add exceptions as needed. You can view the full set of analyzers on the Roslynator project.
- Open your workspace settings by pressing
Ctrl+Shift+P
and typing>Preferences: Open Workspace Settings
then add the following setting{ "omnisharp.enableRoslynAnalyzers": true }
- Perform a nuget restore by pressing
Ctrl+Shift+P
, typing>Tasks: Run Tasks
, and choosing thenugetrestore
task. If you have any errors make sure that yournuget.exe
is configured correctly in the.vscode/tasks.json
file. You can also run this on the command line by executingnuget.exe restore
in your project root. - Reload VSCode.
If we now type some code that fails one of the static analysis rules we will receive a warning. For example
We can access the quick-fix menu by putting the cursor over one of the issues and either clicking the lightbulb icon or pressing Ctrl+.
I’ve gone ahead and applied all of the automatic code fixes
You can also access quite a few automated refactorings by pressing the same shortcut even when there isn’t a warning. For example given the following code
We can perform an automated refactoring if we focus on the if
statement
which will change this to a ternary operator
You can actually keep going and it will offer to inline the offset
.
Step 10) Add Unhandled Exception Handler (Optional) #
There are times where your game can crash during start up, we enabled pausing on exceptions in an earlier step which means the debugger will stop whenever there’s an exception. However, it’s possible that once you export a release version of your project you have some exceptions that you need to debug. That’s why we enabled the file logging option in Godot in the beginning of this tutorial. File logging will log all of our game’s GD.Print
statements in a file located at %APPDATA\Roaming\Godot\app_userdata\YourProjectName
. However, Godot by default will not log exceptions thrown from your application so we have to do this ourselves by adding the following code at your main scene cs file.
using System;
using Godot;
namespace SampleProject
{
public class Node : Node2D
{
public override void _Ready()
{
AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionHandler;
}
private void UnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs e)
{
GD.PrintS($"Got unhandled exception {e.ExceptionObject}");
GD.PrintErr("Quitting due to exception");
}
}
}
Now whenever your game throws an exception you will be guaranteed to have the error logged in the file. Again this is mainly useful when you start sharing your game with others and need them to send you the crash logs.
That’s it! #
I hope everything here made sense. If you need any help join the official Godot #csharp channel on Discord and feel free to message me on Discord at giulianob#9552.
You can find a sample project over at Github with all of the configurations complete.