Godot, an open-source game engine known for its versatility and simplicity, is gaining popularity among both indie developers and the broader game development community. While Godot comes with its own scripting language, GDScript, it also supports the widely-used C# language, familiar to Unity and Unreal Engine developers.
In this tutorial, we will use “Dodge the Creeps”, a popular beginner project for learning the Godot game engine. “Dodge the Creeps” is a simple 2D game where players avoid enemies (creeps) while learning essential game development concepts. We will set up automated build pipelines to build, test, and publish the game using TeamCity and work with both the GDScript and C# versions of the game.
Godot with GDScript
Build and export GDScript game for Windows target
In TeamCity, there are two primary ways to configure build chains: through the UI or using the Kotlin DSL (Configuration as Code). Each method has its advantages depending on your needs.
- UI configuration is the more traditional approach, where users set up and manage build configurations directly within TeamCity’s graphical interface. It’s intuitive and accessible, making it easy to quickly define builds, adjust settings, and link build steps together without needing any coding skills. The downside is that this approach can be cumbersome for larger, more complex pipelines.
- The TeamCity Kotlin DSL allows you to define build chains programmatically. This approach offers version control and reusability, making it ideal for complex build setups and automation.
In these examples, we will show you how to set up Godot pipelines both ways. We will use the barichello/godot-ci Docker images (barichello/godot-ci:4.2.1
) to set up the Godot environment. This includes the Godot engine itself, export templates, and the Butler utility for publishing games to Itch.io.
UI configuration:
- In the TeamCity UI, create a new build configuration.
- Set up your version control system (VCS) settings to pull the code from your repository.
- Add a build step using the Command Line runner.
- Configure the build step with the following commands to build your Godot game:
godot -v -e --quit --headless godot -v --export-release --headless "Windows" Dodge-Windows.zip
The first command is necessary to open the editor in headless mode to import all assets, and the second command is then used to export the game for a specific platform (like Windows) in release mode, packaging everything into the final build.
Kotlin DSL configuration:
If you’re working with the Kotlin DSL (Configuration as Code), you can define the build configuration programmatically:
script { name = "Build for Windows" scriptContent = """ godot -v -e --quit --headless godot -v --export-release --headless "Windows" Dodge-Windows.zip """.trimIndent() dockerImage = "barichello/godot-ci:4.2.1" }
This process can be easily adapted for other platforms by adjusting the export target from Windows to Linux, WebGL HTML5, etc.
You can find more information about exporting projects here:
https://docs.godotengine.org/en/stable/tutorials/export/exporting_projects.html
Here, we see the result of a build as a published artifact. To publish the artifact, it must be configured in the “General settings” tab of the build configuration.
As you can see, building a Godot game in TeamCity is a straightforward process. For smaller or simpler projects, the UI-based configuration offers an intuitive way to quickly set up build pipelines without the need for coding. However, for more complex build setups, the Kotlin DSL provides a more powerful, scalable, and reusable solution through code-based configuration.
Unit tests reporting
In recent examples, we used the command line runner, which means tests aren’t detected automatically by TeamCity as they usually would be. However, we can still use the XML Report Processing build feature to handle the test results.
For the GDScript version of Godot, several unit testing frameworks are available, with the most popular being GdUnit, WAT, and GUT. All of these frameworks support JUnit standard XML reporting, which TeamCity can easily import and process using its XML Report Processing feature.
Kotlin DSL configuration:
features { xmlReport { reportType = XmlReport.XmlReportType.JUNIT rules = "**/report.xml" } }
Godot with C#
Why choose C# scripting in Godot?
While GDScript offers strong integration with Godot as a default language, C# provides distinct advantages. Since C# is compiled, it performs significantly better, often running up to four times faster than the interpreted GDScript, which can be crucial for gameplay optimization.
As a strongly typed language, C# reduces potential coding errors, making it easier to understand and maintain complex code. Additionally, using .NET opens up access to powerful development tools like JetBrains Rider, dotTrace, and dotMemory, improving workflow and debugging.
Building and Exporting a .NET 8 game
Building a .NET project in Godot is similar to building a GDScript project. The main difference is that we will use a different Docker image (barichello/godot-ci:mono-4.2.1
), and we will need to install .NET separately, because the image contains only mono.
script { name = "Build Game" scriptContent = """ set -e wget https://packages.microsoft.com/config/debian/12/packages-microsoft-prod.deb -O packages-microsoft-prod.deb dpkg -i packages-microsoft-prod.deb apt-get update apt-get install -y dotnet-sdk-8.0 godot --headless --verbose --editor --quit godot --headless --verbose --export-release "Windows Desktop" Dodge-Windows.zip """.trimIndent() dockerImage = "barichello/godot-ci:mono-4.2.1" }
Unit testing C# game with on-the-fly test reporting
First, we add the TeamCity.VSTest.TestAdapter
NuGet package to get on-the-fly test reporting during the build. Unit tests project file should look like this:
<ItemGroup> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" /> <PackageReference Include="gdUnit4.api" Version="4.2.3" /> <PackageReference Include="gdUnit4.test.adapter" Version="1.1.1" /> <PackageReference Include="TeamCity.VSTest.TestAdapter" Version="1.0.40" /> </ItemGroup>
Kotlin DSL configuration:
script { name = "Build Game" scriptContent = """ set -e echo "##teamcity[blockOpened name='Setup .NET']" wget https://packages.microsoft.com/config/debian/12/packages-microsoft-prod.deb -O packages-microsoft-prod.deb dpkg -i packages-microsoft-prod.deb apt-get update apt-get install -y dotnet-sdk-8.0 echo "##teamcity[blockClosed name='Setup .NET']" echo "##teamcity[blockOpened name='Import assets']" godot --headless --verbose --editor --quit echo "##teamcity[blockClosed name='Import assets']" echo "##teamcity[blockOpened name='Run tests']" export GODOT_BIN=/usr/local/bin/godot dotnet test --settings .runsettings echo "##teamcity[blockClosed name='Run tests']" echo "##teamcity[blockOpened name='Export game']" godot --headless --verbose --export-release "Windows Desktop" Dodge-Windows.zip echo "##teamcity[blockClosed name='Export game']" """.trimIndent() dockerImage = "barichello/godot-ci:mono-4.2.1" }
In this example, the script begins by setting up the .NET environment, downloading the necessary dotnet-sdk
(version 8.0 in this case). It then imports the game assets into Godot, runs the unit tests, and finally exports the game to a Windows executable. TeamCity’s blockOpened and blockClosed service messages allow developers to clearly see each stage of the process in the build logs, making it easier to debug and track.
Publish the game
WebGL to S3
The next step is distributing the game to your players. In this case, we’re automating the upload of the game to platforms like S3 for HTML5 builds.
script { name = "Publish to S3 bucket" scriptContent = """ mv DodgeTheCreeps.html index.html aws s3 sync . s3://danielgallo-gdc-unity-game/Godot-DodgeTheCreeps """.trimIndent() }
Publish exported Windows game to iItch.io using butler tool
Butler is a command-line tool created for developers to easily upload, update, and manage their games or digital projects on the indie game platform itch.io. Instead of manually uploading files through the website, Butler automates the process, ensuring smooth, incremental updates without re-uploading entire files.
It also provides version control, allowing developers to push only changes, which reduces upload time. Ideal for game developers who frequently update their projects, it simplifies deployment, improves workflow efficiency, and ensures users always have the latest version of their content.
params { param("env.ITCHIO_USERNAME", "teamcity-demo") password("env.BUTLER_API_KEY", "******") param("env.ITCHIO_GAME", "dodge-the-creeps") } … steps { script { name = "Publish to Itch.io" scriptContent = "butler push build %env.ITCHIO_USERNAME%/%env.ITCHIO_GAME%:windows" dockerImage = "barichello/godot-ci:4.2.1" } }
As you can see, setting up a Godot build pipeline with TeamCity is relatively straightforward, largely because of the Godot engine simplicity. This is the reason why we don’t provide dedicated support in the form of a runner.
However, if your scenario is more complex and you believe better support is needed, please feel free to share your suggestions in the comments section of this blog post.