Write Godot games in flavoured C++, without the boilerplate.
GD++ is a programming language for Godot. It compiles to C++, and plugs into Godot through GDExtension. It's inspired by the conciseness and simplicity of GDScript.
GD++ mixes GDScript and C++, but it is neither GDScript nor C++:
- Declarations look like GDScript.
- Function bodies are flavoured C++: C++ with a few custom words, like
emitto send a signal.
GD++ writes the C++ you would write by hand with godot-cpp: headers, _bind_methods, getters, setters, #include lines and class registration. Math and loops run 15 to 50 times faster than in GDScript (see gd++ man performance).
GD++ comes as one command line tool, gd++: the compiler, a build system that downloads godot-cpp for you, and a built-in manual.
Note
The code was mostly written by AI, but a senior engineer made all design decisions.
Save it as player.gd++ anywhere in a Godot project, and run:
gd++ init . --bind 10.0.0-stable --spec 4.7.2-stable
gd++ fetch --missing
gd++ buildOpen the project in Godot: Player is now a node type, like any built-in node. Debug builds hot reload while the editor is open.
To see the C++ that GD++ writes for you, run gd++ trans player.gd++.
You need Godot 4, and Go to build gd++ itself:
make && sudo make install # builds gd++ and copies it to /usr/local/binThen install the tools that compile C++ (Git, SCons, Python and a C++ compiler):
gd++ install # asks before running anything
gd++ install --echo # or just prints the commands, to run them yourselfgd++ install supports Debian, Ubuntu, Fedora, Arch, openSUSE, macOS (with Homebrew) and Windows (with winget). It's experimental, and hasn't been tested on every platform. On Linux and macOS, it also installs MinGW-w64, to build for Windows.
The full documentation is built into the tool, and matches the version you run. Run gd++ man to list its pages, and start with gd++ man intro and gd++ man lang.
Unlike GDScript, blocks use braces, and every value has a static type. Types are Godot's, e.g. int, Vector3 or Node3D. Each one maps to a C++ type, e.g. int64_t, Vector3 and Node3D *.
For GD++'s custom words in C++, see gd++ man rewrites. GD++ binds the function, so GDScript can call it too. gd is short for UtilityFunctions, Godot's global functions.
A call to an @onthread function returns right away, with an Async task. The task holds the result once it's ready. No frame waits for the search.
@rpc takes the same arguments as in GDScript. rpc calls the function on other peers.
Each feature has its page in the manual:
- Classes: file-level with
class_name, or inline withclass Name { ... }. Seegd++ man classes. @toolclasses: run the class's code in the editor too. Seegd++ man classes.@game_onlyclasses: run the class's code only in the game. Seegd++ man classes.@icon: give a class its icon in the editor. Seegd++ man classes.- Typed arrays and dictionaries:
Array[T]andDictionary[K, V]. Seegd++ man types. - Casts:
value as Tconverts between any two types, and checks downcasts. Seegd++ man cast. - Properties: variables with their own
getandsetblocks. Seegd++ man variables. @onreadyvariables: get their values when the node is ready. Seegd++ man lifecycle.- Exports:
@exportand its family, e.g.@export_range, show variables in the inspector. Seegd++ man exports. - Inspector sections:
@export_category,@export_groupand@export_subgroup. Seegd++ man exports. - Signals:
signal name(params), sent withemit name(args). Seegd++ man signals. @overridefunctions: override an engine callback, e.g._ready, or a@virtualfunction. Seegd++ man functions.@virtualfunctions: subclasses and GDScript can override them.@finalstops that. Seegd++ man functions.@constand@staticfunctions. Seegd++ man functions.- Default values: any C++ expression, even a block of code. See
gd++ man functions. @deferredfunctions: every call runs later, throughcall_deferred. Seegd++ man functions.@thread_safefunctions: calls from other threads run later, on the main thread. Seegd++ man functions.@onthreadfunctions: run on a worker thread, and return anAsynctask. Seegd++ man async.@rpcfunctions: callable over the network, withrpc name(args). Seegd++ man rpc.- Enums and constants:
enum Name { A B C }andenum NAME = 42. Seegd++ man enums. @bitfieldenums: values are flags, 1, 2, 4 and so on. Seegd++ man enums.- Extending enums: copy the values of another enum, e.g.
extends Node.ProcessMode. Seegd++ man enums. - Constructors and destructors:
ctor { ... }anddtor { ... }. Seegd++ man lifecycle. - Notification handlers:
notif(PREDELETE) { ... }. Seegd++ man lifecycle. - Externs: use classes of other packages, GDExtensions and scripts. See
gd++ man externs. @trace: print calls, variable changes and signals while the game runs. Seegd++ man debugging.@profile: time code, live in the editor's monitors. Seegd++ man debugging.decl,impland@globalblocks: put any C++ into the generated files. Seegd++ man code.importandnoimport: adjust the automatic includes. Seegd++ man includes.- Doc comments:
///and/** */become the editor's help. Seegd++ man docs. gd_assert: like GDScript'sassert, and gone in release builds. Seegd++ man runtime.GDPP_STRING_NAME: aStringNamecreated once, for fast calls by name. Seegd++ man runtime.
@trace and @profile generate no code unless a build turns them on, e.g. gd++ build --trace Player. So you can leave them in your code for good.
- A project is a normal Godot project.
- A package is a directory with a
gd++pkg.tomlfile. It builds into one GDExtension library. - Dependencies are the Godot C++ bindings (godot-cpp) and the Godot API specs.
gd++ init --vcs git # keep GD++'s files out of git
gd++ init . --bind 10.0.0-stable --spec 4.7.2-stable # make the project root a package
gd++ init tools --bind 10.0.0-stable --spec 4.7.2-stable # or add a package anywhere
gd++ fetch --index # list the dependencies that are available
gd++ fetch --missing # download what the packages need
gd++ checkin --spec 4.7.2-stable # commit a dependency with the project
gd++ vendor --spec my-4.7 --from my-4.7 # add a custom one, e.g. from your own Godot build
gd++ build # build the package you're in, for this machine, in debug mode
gd++ build --proj # build every package of the project
gd++ build --ship --for l.x64 w.x64 # release builds for Linux and Windows
gd++ clean # delete the build cache
gd++ ls # an overview of the project
gd++ trans player.gd++ # print the C++ that GD++ generates from a file
gd++ doc TypedArray # show what godot-cpp declares under a name
gd++ cat player.gd++ # show a file, highlighted
gd++ fix # tidy up the projectThe build writes the libraries and a .gdextension file into the package root, so Godot loads them right away.
A package can also hold plain C++ classes, written the usual godot-cpp way. gd++ init . --class Foo --include pkg://foo.h registers them with Godot.
GD++ is ready to be used, but it's still experimental, and comes with absolutely no warranty. Syntax versions are designed for backward compatibility, but no guarantees can be given yet.
| Syntax | Status |
|---|---|
| 0 | Nightly: the language as it's being developed. Never use it in production. |
| 1 | Stable in theory, but experimental in practice. |
Each package chooses its syntax version in its gd++pkg.toml.
- Foliage3D: a realistic project by the same author, written fully in GD++, which shows what GD++ can do.
- gdpp-vim: Vim bindings for GD++.
- Godot Object Compiler: a similar project, which generates the boilerplate of GDExtensions from macros in plain C++ code.
GD++ is licensed under the MIT License.
GD++ was created by caphindsight. If GD++ helps you make a game, a mention in its credits would be very much appreciated. The MIT License doesn't require it.
