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:

  1. Run your game right from VSCode.
  2. Breakpoint debugging in VSCode.
  3. Crash logs when you share your game.
  4. 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.

  1. Go to Editor menu > Editor Settings
  2. Under Mono > Builds
    • Build Tool: Select either “MSBuild (VS Build Tools)” if on Windows or “MSBuild (Mono)” for other platforms.
  3. Under Mono > Editor
    • External Editor: Visual Studio Code
  4. Under Text Editor > Files
    • Open Dominant Script On Scene Change: Uncheck
  5. Close the editor settings dialog
  6. Go to Project menu > Project Settings
  7. 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.
  8. 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.

  1. Download the latest release of MonoDebuggerQM.
  2. Extract the zip to the addons folder of your project. For example if your project is located at c:\myproject then you should have a c:\myproject\addons\MonoDebuggerQM-1.0.1\ directory after extracting the zip.
  3. Go to Project menu > Project Settings > Plugins and change the Status of the MonoDebugger plugin to Active. 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.

  1. Right click on your scene root and click Attach Script
  2. Change the Language to C# and click Create.

After this happens a new option is available to us that we should change.

  1. Go to Project menu > Project Settings
  2. 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.

  1. Go to the Extensions tab on the left hand side.
  2. 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.

  1. Open your .csproj file. If your project is named MyGodotGame then the file will be called MyGodotGame.csproj.
  2. 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.

  1. 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.

  1. 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.

  1. In VSCode, click on Debug menu > Open Configurations
  2. 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.
  3. 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 with godot-mono or wherever you have Godot installed.
  4. Click on Terminal menu > Configure Tasks…
  5. Once again if you don’t have a tasks.json yet defined then choose to create a new one.
  6. 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 to MsBuild.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 and nuget for the command. They should be installed in your /usr/local/bin directory.
  7. 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 your settings.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.

  1. Click on the Debug icon on the left hand menu bar and change the Debug configuration to Run and Attach vscode debug

  2. 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.
    Annotation 2019-11-10 182216.png

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:

Annotation 2019-11-10 182707.png

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.

Annotation 2019-11-10 183026.png

To see the output of your code, you will need to switch the Debug Console to the Run configuration.

Annotation 2019-11-10 183346.png

Basically what is happening is that we have three different configurations in the launch.json.

  1. Run: Starts the Godot editor from VSCode
  2. Attach: Starts the Mono debugger in VSCode. The debugger listens for connections that your game establishes when you have the Wait For Debugger option enabled in Godot.
  3. 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.

Annotation 2019-11-10 183639.png

Anytime you switch back to Godot and wish to run the project from Godot itself then you have the following options.

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:

  1. 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.

  1. 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.

  1. Open your workspace settings by pressing Ctrl+Shift+P and typing >Preferences: Open Workspace Settings then add the following setting { "omnisharp.enableRoslynAnalyzers": true }
  2. Perform a nuget restore by pressing Ctrl+Shift+P, typing >Tasks: Run Tasks, and choosing the nugetrestore task. If you have any errors make sure that your nuget.exe is configured correctly in the .vscode/tasks.json file. You can also run this on the command line by executing nuget.exe restore in your project root.
  3. Reload VSCode.

If we now type some code that fails one of the static analysis rules we will receive a warning. For example

Annotation 2019-11-10 185850.png

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+.

Annotation 2019-11-10 185949.png

I’ve gone ahead and applied all of the automatic code fixes

Annotation 2019-11-10 190121.png

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

Annotation 2019-11-10 190500.png

We can perform an automated refactoring if we focus on the if statement

Annotation 2019-11-10 190540.png

which will change this to a ternary operator

Annotation 2019-11-10 190640.png

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.

 
218
Kudos
 
218
Kudos