Godot 3: Script with F#

Date: 2022-11-09 | godot | fsharp | csharp |

If you are running Godot 4, refer to the Godot 4 guide instead.

Overview

F# has quickly become my favorite programming language / ecosystem. Yet it is still behind in direct support in many domains - game / 3D development included - meaning a bit of tinkering is required to get up and running.

In this post, we'll walkthrough setting up a Godot project that can run scripts in both C# and F#.

Requirements

  • Godot 3 (Mono version) - We need the Godot Mono version so that we have C# support. This implicitly gives us .NET support which we'll be leveraging to run our F# code.
  • .NET SDK - We need .NET SDK installed on our machine so we can utilize the dotnet command to create and modify .csproj and .fsproj files

Create a Godot project

Note: you can grab the full Godot and F# project source code on GitHub.

The first thing we'll do is create a new Godot project that is C# and F# compatible.

  • Open Godot
  • Create a new Godot Project
  • Add a C# script to the project - this will force the project to create a .csproj and will enable C# script support for our project
    • You can do this by right-clicking in the Scene Explorer and going through the options to create a new C# script

Our project should now have C# support. We can check this by creating an empty node in the project and attaching a simple script that will print to console. When we run it, we should see the output in our console.

SimplePrintCs.cs

using Godot;
using System;

public class SimplePrintCs : Node
{
	// Called when the node enters the scene tree for the first time.
	public override void _Ready()
	{
		GD.Print("SimplePrintCs: C# Running...");
	}
}

When we run our Godot project, we'd expect it to output:

SimplePrintCs: C# Running...

Enable F# in Godot

Note: you can grab the full Godot and F# project source code on GitHub.

Now that we have a .csproj in our Godot project, we can start to modify it to enable F#.

First we'll create an F# library project.

  • Create a new folder in your project (like ScriptsFs)
  • Navigate to that directory (like cd ScriptsFs)
  • Create a new F# library project:
    • dotnet new classlib -lang "F#"

This should output a minimal F# project with an .fsproj and an example .fs script.

Now that we have this minimal F# project, we need to modify its build dependencies in .fsproj to make it compatible with our Godot project and scripts.

Open the .fsproj and make changes to match the .csproj:

  • Sdk - At time of writing the current Godot LTS is Godot.NET.Sdk/3.3.0 but this may change and the important thing is that .csproj and .fsproj match. By referencing the Godot SDK directly, we give our F# code access to the Godot APIs
  • PropertyGroup > TargetFramework - At time of writing, Godot is targeting net472, but again the important part is that your .csproj and .fsproj agree on targets.

At this point we have a C# project and F# project that understand Godot, but they don't yet know about each other. We can change this by adding a project reference from our .csproj to our .fsproj - this will allow our C# code to call into our F# code.

Add a reference from C# to F#:

  • Navigate to root of your Godot project (where the .csproj is)
  • Run dotnet add ./CSPROJ_NAME.csproj reference ./ScriptsFs/ScriptsFs.fsproj
    • (Replace CSPROJ_NAME with the actual name of your .csproj)

With any luck we should now be able to call our F# code from C#.

F# Scripts in Godot

Godot knows about our C# project and our C# project knows about our F# project but currently Godot does not know about F# so it can't directly call it. There are some workarounds to this on the web but I find them to be a bit to clunky and manual so instead of enabling that, we'll just call all F# from a base C# file.

When you want to reference F# scripts in Godot, we'll do something like this:

  • C# File: FSharpHolder.cs -> references actual code
  • F# File: Actual Code -> real logic lives here

So let's say we want a script that prints to console. We can write that in F# like this:

SimplePrintFs.fs

namespace ScriptsFs

open Godot

type SimplePrintFs() =
    inherit Node()

    override this._Ready() =
        GD.Print("SimplePrintFs: F# Running...")

Note: Make sure you update your .fsproj so it knows to compile this new script!

Now we create a placeholder C# file which we'll attach to our Godot scene to faciliate the Godot -> F# connection. The placeholder C# file just inherits directly from our F# file allowing it to run directly.

SimplePrintFsHolder.cs

using ScriptsFs;

public class SimplePrintFsHolder : SimplePrintFs
{}

Now when we run this, we expect to get both the C# and F# prints!

SimplePrintCs: C# Running...
SimplePrintFs: F# Running...

Next Steps

Hopefully this gets you started on your Godot x F# journey!

Want more like this?

The best / easiest way to support my work is by subscribing for future updates and sharing with your network.