What?
Glodot == Godot + Gleam. It's a way to run Gleam code inside Godot.
Who?
"Who discover this?" - Me!
"Glodot is for whom?" - It's for people who like FP (Functional programming) and want to use it for gamedev.
When/where?
Glodot is ideal for the domain logic (like writing complex algorithms). Even for simple stuff like handling result from swipe gestures in a 2048 game, writing in Gleam is way more breathable compared to GDScript.
However, it's hard to interacts directly outside of domain logic from the Gleam code (like interacts heavily with the node tree and handling physics for exmaple)...
Why?
Godot is a great game engine but GDscript is not a good language to do domain logic stuffs. And yes, C# is better but not as good as a real FP langauge.
Gleam is the savior that fill the gap in the Godot ecosystem. Its syntax is beautiful, modern, familiar, easy to read, to manage and to learn (can be learn in a day). Plus Gleam's tooling is convenient, more than its of Lua, Python, C#...
Therefore, this is the perfect combination:
- GDscript for convenient "real world" interactions and handle physic.
- Gleam for writing domain logic functions with predefined input and output, like complex algorithms/calculations.
How?
The road to connect from Godot to Gleam is as follows:
- Godot Mono: To use C# in Godot.
- ClearScript: Use that NuGet package in Godot to run Javascript code in C#.
- Bun or any JS bundler: To bundler Javascript code to one single
.js
file. - Gleam compiler: To compiler all the epic codes you write.
Your Glodot files structure should look like this:
. (Root of Godot project)
├── core (Root of Gleam package)
│ ├── gleam.toml
│ ├── manifest.toml
│ ├── package.json
│ ├── src
│ │ └── core
│ │ ├── core.gleam (The file that contains all functions to be accessible from outside Gleam)
│ │ └── ...
├── project.godot
├── project.csproj
├── core.txt (Bundled Gleam-to-JS code)
├── core.gd (Util to execute bundled code in Godot)
└── V8.cs (Util to execute JS code in Godot)
Gleam side
First create a Gleam package inside your Godot project's root:
gleam new core # It's could be named anything.
Then write your domain logic stuffs here. When you done, make a signle file that contains all functions to be accessible from outside of Gleam (name it core.gleam
):
import core/a_stuffs
import core/b_stuffs
pub fn fn_a(input: String) -> String {
a_stuffs.fn_a(input)
}
pub fn fn_b(input: String) -> String {
b_stuffs.fn_b(input)
}
// ...
⚠️ WARNING! BIG WARNING! You cannot use custom Gleam type as input/output outside of Gleam, at least it's not behaved as you thinks. You can only use Int
, Float
and String
. Even List
and Dict
is not the same as JS's Array and Object. The best solution is to warp input and output as JSON string.
So after you write you fancy code in a Gleam package for your game, make sure to set the target to JS in the gleam.toml
config file:
name = "core"
version = "1.0.0"
+ target = "javascript"
...
Then bundler the JS codes after each time you compiler:
cd ./core
bun build ./build/dev/javascript/core/core/core.mjs --outfile ../core.txt
Yep it's end with .txt
so that Godot can detect and read the texts inside that file.
And remember to remove the export
part inside the bundled file so that V8 don't warning.
Godot side
First install ClearScript to your system:
nuget install Microsoft.ClearScript.Complete
Then add it to the project.csproj
file:
<Project Sdk="Godot.NET.Sdk/4.4.1">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<EnableDynamicLoading>true</EnableDynamicLoading>
<RootNamespace>project</RootNamespace>
</PropertyGroup>
+ <ItemGroup>
+ <PackageReference Include="Microsoft.ClearScript.Complete" Version="7.5.0" />
+ </ItemGroup>
</Project>
Write an util name V8.cs
in your project to execute JS code:
using Godot;
using System;
using Microsoft.ClearScript.V8;
public partial class V8 : Node
{
private static V8ScriptEngine _engine = new V8ScriptEngine();
public static string eval(string code)
{
return Convert.ToString(_engine.Evaluate(code));
}
}
Finally, make an util to execute Gleam-to-JS bundled code (name it core.gd
):
extends Node
const _v8 := preload("res://src/V8.cs")
func _ready() -> void:
var core_file := FileAccess.open(&"res://core.txt", FileAccess.READ)
var core_code := core_file.get_as_text()
_v8.eval(core_code)
func fn_a(arg: Variant) -> Variant:
return _invoke(&"fn_a", arg)
func fn_b(arg: Variant) -> Variant:
return _invoke(&"fn_b", arg)
func _invoke(funcName: String, argument: Variant) -> Variant:
var code: Variant = &"{funcName}(\"{argument}\")".format({
&"funcName": funcName,
&"argument": JSON.stringify(argument).json_escape(),
})
var result: Variant = _v8.eval(code)
var json := JSON.new()
var error := json.parse(result)
if error:
if result != &"":
printerr(result)
return null
return json.data
Export to web
As said in the Godot document:
Projects written in C# using Godot 4 currently cannot be exported to the web. See this blog post for more information.
However you can fallback to use JavaScriptBridge
to run JS code instate of C# + ClearScript when export to web.
Additional
Here are some Gleam libraries that are useful for gamedev:
gleam_community_maths
: A basic mathematics library that contains some of the most fundamental mathematics functions and utilities.prng
: A lib to handle PRNG (Pure Random Number Generator).vec
: A vector library, has almost everything that can be done in Godot.vec_dict
: This is to represent and handle a 2D, 3D and even 4D grid.
Alternatives route?
The Godot Mono - ClearScript route mentioned above seems quite roundabout, but it's currently the most "official" way. Godot Mono is an official version of Godot, and ClearScript is a library from Microsoft (the creator of C#), make this approach quite stable.
Glodot could potentially be made by using GodotJS to replace the route above, connecting Godot to compiled Gleam code purely through JS/TS.
But that is a shortcut, because at the time of writing, GodotJS is quite buggy/janky. I hope it will improve soon, because if GodotJS becomes as stable and easy to set up as Godot Mono, it would be an ideal method.
But if I could wish, I want a Godot plugin that could automatically compile a specified Gleam package and then provide an API to easily run it.
Well that's all fork, stay gleamy~!