350 lines
12 KiB
Markdown
350 lines
12 KiB
Markdown
# godot-cpp
|
||
|
||
**C++ bindings for the Godot script API.**
|
||
|
||
The instructions below feature the new NativeScript 1.1 class structure and will only work for modules created for Godot 3.1 and later. Use the following branches for older implementations:
|
||
|
||
Version | Branch
|
||
--- | ---
|
||
**Godot 3.0 Nativescript 1.0** | [3.0](https://github.com/GodotNativeTools/godot-cpp/tree/3.0)
|
||
**Godot 3.1 Nativescript 1.0** | [nativescript-1.0](https://github.com/GodotNativeTools/godot-cpp/tree/nativescript-1.0)
|
||
|
||
## Table of contents
|
||
|
||
- [**Contributing**](#contributing)
|
||
- [**Getting Started**](#getting-started)
|
||
- [**Creating a simple class**](#creating-a-simple-class)
|
||
|
||
## Contributing
|
||
|
||
We greatly appreciate help in maintaining and extending this project. If you
|
||
wish to help out, ensure you have an account on GitHub and create a "fork" of
|
||
this repository. Rémi "Akien" Verschelde wrote an excellent bit of documentation
|
||
for the main Godot project on this:
|
||
[Pull request workflow](https://docs.godotengine.org/en/3.0/community/contributing/pr_workflow.html)
|
||
|
||
Please install clang-format and copy the files in `misc/hooks` into `.git/hooks`
|
||
so formatting is done before your changes are submitted.
|
||
|
||
## Getting Started
|
||
|
||
| **Build latest version of Godot** | [**GitHub**](https://github.com/godotengine/godot) | [**Docs**](https://godot.readthedocs.io/en/latest/development/compiling/index.html) |
|
||
| --- | --- | --- |
|
||
|
||
### Setting up a new project
|
||
|
||
We recommend using Git for managing your project. The instructions below assume
|
||
you're using Git. Alternatively, you can download the source code directly from
|
||
GitHub. In this case, you need to download both
|
||
[godot-cpp](https://github.com/GodotNativeTools/godot-cpp) and
|
||
[godot_headers](https://github.com/GodotNativeTools/godot_headers).
|
||
|
||
```bash
|
||
mkdir SimpleLibrary
|
||
cd SimpleLibrary
|
||
mkdir bin
|
||
mkdir src
|
||
git clone --recursive https://github.com/GodotNativeTools/godot-cpp
|
||
```
|
||
|
||
If you wish to use a specific branch, add the -b option to the clone command:
|
||
|
||
```bash
|
||
git clone --recursive https://github.com/GodotNativeTools/godot-cpp -b 3.0
|
||
```
|
||
|
||
If your project is an existing repository, use a Git submodule instead:
|
||
|
||
```bash
|
||
git submodule add https://github.com/GodotNativeTools/godot-cpp
|
||
git submodule update --init --recursive
|
||
```
|
||
|
||
Right now, our directory structure should look like this:
|
||
|
||
```text
|
||
SimpleLibrary/
|
||
├─godot-cpp/
|
||
| └─godot_headers/
|
||
├─bin/
|
||
└─src/
|
||
```
|
||
|
||
### Updating the `api.json` file
|
||
|
||
Our `api.json` file contains metadata for all the classes that are part of the
|
||
Godot core. This metadata is required to generate the C++ binding classes for
|
||
use in GDNative modules.
|
||
|
||
This file is supplied with our
|
||
[godot_headers](https://github.com/GodotNativeTools/godot_headers) repository
|
||
for your convenience. However, if you're running a custom build of Godot and
|
||
need access to classes that have recent changes, you must generate a new
|
||
`api.json` file. You do this by starting your Godot executable with the
|
||
following parameters:
|
||
|
||
```bash
|
||
godot --gdnative-generate-json-api api.json
|
||
```
|
||
|
||
Now copy the `api.json` file into your folder structure to make it easier to
|
||
access.
|
||
|
||
See the remark below for the extra ```custom_api_file``` SCons argument, which
|
||
is required to tell SCons where to find your file.
|
||
|
||
### Compiling the C++ bindings library
|
||
|
||
The final step is to compile our C++ bindings library:
|
||
|
||
```bash
|
||
cd godot-cpp
|
||
scons platform=<your platform> generate_bindings=yes
|
||
cd ..
|
||
```
|
||
|
||
Replace `<your platform>` with either `windows`, `linux`, `osx` or `android`. If
|
||
you leave out `platform`, the target platform will automatically be detected
|
||
from the host platform.
|
||
|
||
The resulting library will be created in `godot-cpp/bin/`, take note of its name
|
||
as it'll differ depending on the target platform.
|
||
|
||
#### Compiling for Android
|
||
|
||
Download the latest [Android NDK](https://developer.android.com/ndk/downloads)
|
||
and set the NDK path.
|
||
|
||
```bash
|
||
scons platform=android generate_bindings=yes ANDROID_NDK_ROOT="/PATH-TO-ANDROID-NDK/" android_arch=<arch>
|
||
```
|
||
|
||
The value of `android_arch` can be `armv7, arm64v8, x86, x86_64`. Most Android
|
||
devices in use nowadays use an ARM architecture, so compiling for `armv7` and
|
||
`arm64v8` is often enough when distributing an application.
|
||
|
||
`ANDROID_NDK_ROOT` can also be set in the environment variables of your PC if
|
||
you don't want to include it in your SCons call.
|
||
|
||
#### Compilation options
|
||
|
||
You can optionally add the following options to the SCons command line:
|
||
|
||
- When targeting Linux, add `use_llvm=yes` to use Clang instead of GCC.
|
||
- When targeting Windows, add `use_mingw=yes` to use MinGW instead of MSVC.
|
||
- When targeting Windows, include `target=runtime` to build a runtime build.
|
||
- To use an alternative `api.json` file, add `use_custom_api_file=yes
|
||
custom_api_file=../api.json`. Be sure to specify the correct location where
|
||
you placed your file (it can be a relative or absolute path).
|
||
|
||
## Creating a simple class
|
||
|
||
Create `init.cpp` under `SimpleLibrary/src/` and add the following code:
|
||
|
||
```cpp
|
||
#include <Godot.hpp>
|
||
#include <Reference.hpp>
|
||
|
||
using namespace godot;
|
||
|
||
class SimpleClass : public Reference {
|
||
GODOT_CLASS(SimpleClass, Reference);
|
||
public:
|
||
SimpleClass() { }
|
||
|
||
/** `_init` must exist as it is called by Godot. */
|
||
void _init() { }
|
||
|
||
void test_void_method() {
|
||
Godot::print("This is test");
|
||
}
|
||
|
||
Variant method(Variant arg) {
|
||
Variant ret;
|
||
ret = arg;
|
||
|
||
return ret;
|
||
}
|
||
|
||
static void _register_methods() {
|
||
register_method("method", &SimpleClass::method);
|
||
|
||
/**
|
||
* The line below is equivalent to the following GDScript export:
|
||
* export var _name = "SimpleClass"
|
||
**/
|
||
register_property<SimpleClass, String>("base/name", &SimpleClass::_name, String("SimpleClass"));
|
||
|
||
/** Alternatively, with getter and setter methods: */
|
||
register_property<SimpleClass, int>("base/value", &SimpleClass::set_value, &SimpleClass::get_value, 0);
|
||
|
||
/** Registering a signal: **/
|
||
// register_signal<SimpleClass>("signal_name");
|
||
// register_signal<SimpleClass>("signal_name", "string_argument", GODOT_VARIANT_TYPE_STRING)
|
||
}
|
||
|
||
String _name;
|
||
int _value;
|
||
|
||
void set_value(int p_value) {
|
||
_value = p_value;
|
||
}
|
||
|
||
int get_value() const {
|
||
return _value;
|
||
}
|
||
};
|
||
|
||
/** GDNative Initialize **/
|
||
extern "C" void GDN_EXPORT godot_gdnative_init(godot_gdnative_init_options *o) {
|
||
godot::Godot::gdnative_init(o);
|
||
}
|
||
|
||
/** GDNative Terminate **/
|
||
extern "C" void GDN_EXPORT godot_gdnative_terminate(godot_gdnative_terminate_options *o) {
|
||
godot::Godot::gdnative_terminate(o);
|
||
}
|
||
|
||
/** NativeScript Initialize **/
|
||
extern "C" void GDN_EXPORT godot_nativescript_init(void *handle) {
|
||
godot::Godot::nativescript_init(handle);
|
||
|
||
godot::register_class<SimpleClass>();
|
||
}
|
||
```
|
||
|
||
### Compiling the GDNative library
|
||
|
||
Once you've compiled the GDNative C++ bindings (see above), you can compile the GDNative library we've just created.
|
||
|
||
#### Linux
|
||
|
||
```bash
|
||
cd SimpleLibrary
|
||
clang -fPIC -o src/init.os -c src/init.cpp -g -O3 -std=c++14 -Igodot-cpp/include -Igodot-cpp/include/core -Igodot-cpp/include/gen -Igodot-cpp/godot_headers
|
||
clang -o bin/libtest.so -shared src/init.os -Lgodot-cpp/bin -l<name of the godot-cpp>
|
||
```
|
||
|
||
You'll need to replace `<name of the godot-cpp>` with the file that was created in [**Compiling the cpp bindings library**](#compiling-the-cpp-bindings-library).
|
||
|
||
This creates the file `libtest.so` in your `SimpleLibrary/bin` directory.
|
||
|
||
#### Windows
|
||
|
||
```bash
|
||
cd SimpleLibrary
|
||
cl /Fosrc/init.obj /c src/init.cpp /nologo -EHsc -DNDEBUG /MDd /Igodot-cpp\include /Igodot-cpp\include\core /Igodot-cpp\include\gen /Igodot-cpp\godot_headers
|
||
link /nologo /dll /out:bin\libtest.dll /implib:bin\libsimple.lib src\init.obj godot-cpp\bin\<name of the godot-cpp>
|
||
```
|
||
|
||
You'll need to replace `<name of the godot-cpp>` with the file that was created
|
||
in [**Compiling the cpp bindingslibrary**](#compiling-the-cpp-bindings-library).
|
||
Replace `/MDd` with `/MD` to create a release build, which will run faster and
|
||
be smaller.
|
||
|
||
This creates the file `libtest.dll` in your `SimpleLibrary/bin` directory.
|
||
|
||
#### macOS
|
||
|
||
For macOS, you'll need to find out which compiler flags need to be used. These
|
||
are likely similar to Linux when using Clang, but may not be identical.
|
||
|
||
If you find suitable compiler flags for this example library, feel free to
|
||
submit a pull request :slightly_smiling_face:
|
||
|
||
#### Android
|
||
|
||
```bash
|
||
cd SimpleLibrary
|
||
aarch64-linux-android29-clang++ -fPIC -o src/init.os -c src/init.cpp -g -O3 -std=c++14 -Igodot-cpp/include -Igodot-cpp/include/core -Igodot-cpp/include/gen -Igodot-cpp/godot_headers
|
||
aarch64-linux-android29-clang++ -o bin/libtest.so -shared src/init.os -Lgodot-cpp/bin -l<name of the godot-cpp>
|
||
```
|
||
|
||
You'll need to replace `<name of the godot-cpp>` with the file that was created in [**Compiling the cpp bindings library**](#compiling-the-cpp-bindings-library). The command above targets `arm64v8`. To target `armv7`, use `armv7a-linux-androideabi29-clang++` instead of `aarch64-linux-android29-clang++`.
|
||
|
||
This creates the file `libtest.so` in your `SimpleLibrary/bin` directory.
|
||
|
||
#### iOS
|
||
|
||
GDNative isn't supported on iOS yet. This is because iOS only allows linking
|
||
static libraries, not dynamic libraries. In theory, it would be possible to link
|
||
a GDNative library statically, but some of GDNative's convenience would be lost
|
||
in the process as one would have to recompile the engine on every change. See
|
||
[issue #30](https://github.com/GodotNativeTools/godot_headers/issues/30) in the
|
||
Godot headers repository for more information.
|
||
|
||
#### HTML5
|
||
|
||
GDNative isn't supported on the HTML5 platform yet. Support is being tracked on
|
||
[issue #12243](https://github.com/godotengine/godot/issues/12243) in the main
|
||
Godot repository.
|
||
|
||
### Creating `.gdnlib` and `.gdns` files
|
||
|
||
Follow the instructions in
|
||
[godot_header/README.md](https://github.com/GodotNativeTools/godot_headers/blob/master/README.md#how-do-i-use-native-scripts-from-the-editor)
|
||
to create the `.gdns` file. This file contains paths to GDNative libraries for
|
||
various platforms. This makes the library usable from Godot in a
|
||
platform-independent manner.
|
||
|
||
### Implementing with GDScript
|
||
|
||
Once your GDNative library is compiled and referenced in a `.gdns` file, you can use it in GDScript or C#. Here's an example with GDScript:
|
||
|
||
```gdscript
|
||
var simpleclass = load("res://simpleclass.gdns").new();
|
||
simpleclass.method("Test argument");
|
||
```
|
||
|
||
### Using Godot classes in C++
|
||
|
||
Godot expects you to manage its classes the same way the engine does. These rules apply to all Godot classes, including your NativeScripts, but not to any normal C++ classes used in your library.
|
||
|
||
- Instantiate Objects using `_new()`, not C++'s `new` operator.
|
||
|
||
```cpp
|
||
Sprite *sprite = Sprite::_new();
|
||
```
|
||
|
||
- Destroy Nodes using `queue_free()`, not C++'s `delete` operator.
|
||
|
||
```cpp
|
||
some_old_node->queue_free();
|
||
```
|
||
|
||
- Wrap References in `Ref` instead of passing around raw pointers. They are reference-counted and don't need to be freed manually.
|
||
|
||
```cpp
|
||
Ref<Texture> texture = resource_loader->load("res://icon.png");
|
||
```
|
||
|
||
- Pass core types that do *not* inherit Object by value. The containers (Array, Dictionary, PoolArray, String) manage their own memory and do not need to be explicitly initialized or freed.
|
||
|
||
```cpp
|
||
Array ints;
|
||
ints.append(123);
|
||
return ints;
|
||
```
|
||
|
||
- Initialize your NativeScript classes in their `_init()` method, not their constructor. The constructor can't access the base class's methods.
|
||
|
||
- Cast objects using `Object::cast_to`, not unsafe C-style casts or `static_cast`.
|
||
|
||
```cpp
|
||
MeshInstance *m = Object::cast_to<MeshInstance>(get_node("ChildNode"));
|
||
// `m` will be null if it's not a MeshInstance
|
||
if (m) { ... }
|
||
```
|
||
|
||
- **Never** use Godot types in static or global variables. The Godot API isn't loaded until after their constructors are called.
|
||
|
||
```cpp
|
||
String s; // crashes
|
||
class SomeClass {
|
||
static Dictionary d; // crashes
|
||
|
||
static Node *node_a = NULL; // fine, it's just a pointer
|
||
static Node *node_b = Node::_new(); // crashes
|
||
};
|
||
```
|