Awesome
<img src="https://discordapp.com/api/guilds/162395145352904705/widget.png?style=shield" alt="#hxgodot channel"/></a>
HxGodot - A Haxe GDExtension for Godot 4
HxGodot combines Haxe's hxcpp target with Godot 4's GDExtension mechanism to supercharge the way you build games with Godot. Nodes are written in Haxe, bundled as a GDExtension and behave like any other Node in your scenes(attach scripts, signals, etc).
Warning There might be crashes, pieces of the API not working or straight up missing. That being said, we appreciate you testing HxGodot in smaller projects. Feel free to get in touch in should you face issues or bugs.
Getting started
Prerequisites & Toolchain:
HxGodot builds as a GdExtension DLL and therefore required the same build environment as Godot itself. Please refer to the official Godot Documentation here
In summary:
- A Commandline shell of your choice. We assume a *nix-based shell for all commands presented here.
- A C++ compiler, python and scons for your target platform
- Haxe 4.3.1+ Install Haxe and setup Haxe's package manager via
haxelib setup
- hxcpp 4.3.1+ Install hxcpp by running
haxelib install hxcpp
- CompileTime library Install it by running
haxelib install compiletime
- Godot 4.2.1+
First time setup
When you are first starting out HxGodot is able to generate a simple example project for you. Let's go into a shell and do that:
-
Install hxgodot via
haxelib
:haxelib git hxgodot https://github.com/HxGodot/hxgodot.git
-
Create yourself a folder somewhere for the sample project we are about to generate and enter it:
mkdir <sample_project> && cd <sample_project>
-
Now run the included cli-tool and and follow the instructions:
haxelib run hxgodot init
Let's take a closer look at the folder's content, that we just generated for you:
bin
: Will contain the compiled gdextension binaries laterbindings
: Will contain the generated Haxe bindings for Godot4's classes. Also holds alog.txt
which contains reports about things that were ignored or could not be handled. Useful if you miss a function in Godot's API, here you will usually find the reason why.build.hxml
: this contains the build-instructions for Haxe when building the extension. Here you can add extra compiler defines for debugging or specify which Haxe code modules you want to include in your extension or which third party Haxe libraries to include. See the included comments.example.gdextension
: This is the extension-file Godot4 will use to load the correct binaries for your CPU architecture.project.godot
: Main Godot Project File. This file is the entry-point for Godot and includes a section to include loading ourexample.gdextension
fileSConstruct
: This is the SCONS build file. This what runs the build pipeline and assembles the binary of your choice.src
: This folder contains the sample's Haxe code. It holds basic examples of a few Godot nodes written in Haxe and runs a few tests & interactions.If you add more folders with Haxe-code to
src
, make sure you take a look atbuild.hxml
. You need to let HxGodot know about which subfolders insrc
to include.
-
Build the extension according to your platform's flavor:
scons platform=<windows|linux|macos> target=<debug|release> arch=<x86_64|x86_32|arm64>
Examples:
- for Apple Silicon:
scons platform=macos arch=arm64
- for Apple Silicon:
-
Open the sample-project in Godot4. Please be aware, that you might need to restart the editor after the first start for everything to setup correctly:
Here you will find the scenetree with the custom Haxe nodes that are contained in the extension.
-
You can now study the included Haxe code and play around with it. Just repeat Step 4 and restart Godot. Feel free to modify this project or use it as a base for a more complex project.
Speaking of a more complex project, you can also checkout our full sample game here: https://github.com/HxGodot/squash-the-creeps-3d-hxgodot
Updating the HxGodot in an existing project
In cases where hxgodot was updated you dont need to recreate your existing project. In such cases you can follow the following steps:
- Update hxgodot via git
haxelib git hxgodot https://github.com/HxGodot/hxgodot.git
-
Update your projects
SConstruct
file. This can be necessary when there have been changes/updates in the build pipelinehaxelib run hxgodot copy_buildfiles
-
Generate a new set of bindings (usually updates come with improvements)
haxelib run hxgodot generate_bindings
-
Rebuild your project's extension
scons platform=<windows|linux|macos> target=<debug|release>
About Godot versions and binding generation
HxGodot ships with an extension_api.json
file that was generated by an official Godot 4.2.1 build. In cases where you build the engine yourself or wanna HxGodot try a different version, you want to generate custom HxGodot bindings. You can do that by running:
<path to your godot executable> --dump-extension-api-with-docs
This will generate your extension_api.json
in the folder you ran the command in. In your project you now need to regenerate the bindings:
haxelib run hxgodot generate_bindings --extension-api-json=<path to your extension_api.json>
Now you can build HxGodot and test your project.
Common pitfalls
Assigning properties
You may attempt to update certain member properties in the following way and notice that the position wont get applied to the node.
class HxCoolNode extends Node2D {
override function _ready() {
this.position.x = 100.0; // this wont apply the value to the position
}
}
This is actually normal. The position
Vector2 is accessed and copied from Godot and you can do calculations with it. But in order to apply it you need to assign the property again or use the setter function like this:
class HxCoolNode extends Node2D {
override function _ready() {
var pos = this.position;
pos.x = 100.0;
this.position = pos;
// or
this.set_position(pos); // that would also work
// or
this.position = new Vector2(100.0, this.position.y); // while not optimal, this also works
// or
this.position = [100.0, this.position.y]; // while not optimal, this also works since Vector2 is an array under the hood
}
}
Dangerous GDArrays
Dont work with GDArrays naively! They contain Variants and by default they can convert into types prematurely and cause a crash.
// triangles_gd holds an array of Int64
var triangles_gd:GDArray = surface_data[cast MeshArrayType.ARRAY_INDEX];
var index:Int = triangles_gd[tidx]; // UNDEFINED BEHAVIOR, DONT DO THIS! The Variant returned from the GDArray sees the `Int` and casts itself to `Int` too early, writing its `Int64` into a the pointer of an `Int`, effectively causing a stack-corruption!!!
// Instead explicitly force the Variant to cast into the original type first and cast into the wanted type secondly
var index:Int = ((triangles_gd[tidx]:cpp.Int64):Int); // Good! Unpack Int64 and cast to Int
Debugging
- Windows: Startup your VisualStudio and setup it up to debug launch your compile Godot 4.x executable with the test-project defined on the cmdline.
You should be able to step through the code on both sides(godot & hxgodot) and see what's going on.
Good to know
- Godot exposes around 850 classes in the extension API. Haxe's compiler will automatically only compile classes that your code actually imports / uses into the extension.