mirror of
https://github.com/godotengine/godot-docs.git
synced 2026-01-05 22:09:56 +03:00
GDExtension docs
Renames from GDNative to GDExtension Add Pictures/Gifs and clarified compatability Remove GDNative language bindings from GDExtension docs Update SConstruct and AddingProperties section updated with suggestions Added property hint example + updated to API naming changes Fixed redirect.csv
This commit is contained in:
@@ -403,3 +403,7 @@ source,destination
|
||||
/tutorials/physics/using_kinematic_body_2d.html,/tutorials/physics/using_character_body_2d.html
|
||||
/tutorials/plugins/editor/spatial_gizmos.html,/tutorials/plugins/editor/3d_gizmos.html
|
||||
/tutorials/3d/procedural_geometry/immediategeometry.html,/tutorials/3d/procedural_geometry/immediatemesh.html
|
||||
/tutorials/scripting/gdnative/index.html,/tutorials/scripting/gdextension/index.html
|
||||
/tutorials/scripting/gdnative/what_is_gdnative.html,/tutorials/scripting/gdnative/what_is_gdextension.html
|
||||
/tutorials/scripting/gdnative/gdnative_c_example.html,/tutorials/plugins/gdextension/gdextension_cpp_example.html
|
||||
/tutorials/scripting/gdnative/gdnative_cpp_example.html,/tutorials/plugins/gdextension/gdextension_cpp_example.html
|
||||
|
||||
|
@@ -109,6 +109,7 @@ Scripting
|
||||
- :ref:`doc_debugger_panel`
|
||||
- :ref:`doc_creating_script_templates`
|
||||
- :ref:`doc_evaluating_expressions`
|
||||
- :ref:`doc_what_is_gdextension`
|
||||
- :ref:`doc_gdscript_warning_system` (split from :ref:`doc_gdscript_static_typing`)
|
||||
|
||||
User Interface (UI)
|
||||
|
||||
@@ -246,7 +246,7 @@ We also need to process what happens when the player loses. The code below will
|
||||
.. code-tab:: cpp
|
||||
|
||||
// This code goes in `hud.cpp`.
|
||||
// There is no `yield` in GDNative, so we need to have every
|
||||
// There is no `yield` in GDExtension, so we need to have every
|
||||
// step be its own method that is called on timer timeout.
|
||||
void HUD::show_get_ready() {
|
||||
_message_label->set_text("Get Ready");
|
||||
|
||||
@@ -126,10 +126,10 @@ officially supported .NET option.
|
||||
in GDScript, C#, or C++ won't have a significant impact on
|
||||
performance.
|
||||
|
||||
C and C++ via GDExtension
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
C++ via GDExtension
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
GDExtension allows you to write game code in C or C++ without needing to recompile
|
||||
GDExtension allows you to write game code in C++ without needing to recompile
|
||||
or even restart Godot.
|
||||
|
||||
.. image:: img/scripting_cpp.png
|
||||
|
||||
@@ -178,4 +178,4 @@ Customizing the build
|
||||
---------------------
|
||||
|
||||
Feature tags can be used to customize a build process too, by writing a custom **ExportPlugin**.
|
||||
They are also used to specify which shared library is loaded and exported in **GDNative**.
|
||||
They are also used to specify which shared library is loaded and exported in **GDExtension**.
|
||||
|
||||
@@ -37,7 +37,7 @@ Using WebRTC in Godot
|
||||
|
||||
WebRTC is implemented in Godot via two main classes :ref:`WebRTCPeerConnection <class_WebRTCPeerConnection>` and :ref:`WebRTCDataChannel <class_WebRTCDataChannel>`, plus the multiplayer API implementation :ref:`WebRTCMultiplayerPeer <class_WebRTCMultiplayerPeer>`. See section on :ref:`high-level multiplayer <doc_high_level_multiplayer>` for more details.
|
||||
|
||||
.. note:: These classes are available automatically in HTML5, but **require an external GDNative plugin on native (non-HTML5) platforms**. Check out the `webrtc-native plugin repository <https://github.com/godotengine/webrtc-native>`__ for instructions and to get the latest `release <https://github.com/godotengine/webrtc-native/releases>`__.
|
||||
.. note:: These classes are available automatically in HTML5, but **require an external GDExtension plugin on native (non-HTML5) platforms**. Check out the `webrtc-native plugin repository <https://github.com/godotengine/webrtc-native>`__ for instructions and to get the latest `release <https://github.com/godotengine/webrtc-native/releases>`__.
|
||||
|
||||
.. warning::
|
||||
|
||||
|
||||
@@ -135,19 +135,19 @@ From your script::
|
||||
print(singleton.myPluginFunction("World"))
|
||||
|
||||
|
||||
Bundling GDNative resources
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Bundling GDExtension resources
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
An Android plugin can define and provide C/C++ GDNative resources, either to provide and/or access functionality from the game logic.
|
||||
The GDNative resources can be bundled within the plugin ``aar`` file which simplifies the distribution and deployment process:
|
||||
An Android plugin can define and provide C/C++ GDExtension resources, either to provide and/or access functionality from the game logic.
|
||||
The GDExtension resources can be bundled within the plugin ``aar`` file which simplifies the distribution and deployment process:
|
||||
|
||||
- The shared libraries (``.so``) for the defined GDNative libraries will be automatically bundled by the ``aar`` build system.
|
||||
- The shared libraries (``.so``) for the defined GDExtension libraries will be automatically bundled by the ``aar`` build system.
|
||||
- Godot ``*.gdnlib`` and ``*.gdns`` resource files must be manually defined in the plugin ``assets`` directory.
|
||||
The recommended path for these resources relative to the ``assets`` directory should be: ``godot/plugin/v1/[PluginName]/``.
|
||||
|
||||
For GDNative libraries, the plugin singleton object must override the ``org.godotengine.godot.plugin.GodotPlugin::getPluginGDNativeLibrariesPaths()`` method,
|
||||
and return the paths to the bundled GDNative libraries config files (``*.gdnlib``). The paths must be relative to the ``assets`` directory.
|
||||
At runtime, the plugin will provide these paths to Godot core which will use them to load and initialize the bundled GDNative libraries.
|
||||
For GDExtension libraries, the plugin singleton object must override the ``org.godotengine.godot.plugin.GodotPlugin::getPluginGDNativeLibrariesPaths()`` method,
|
||||
and return the paths to the bundled GDExtension libraries config files (``*.gdextension``). The paths must be relative to the ``assets`` directory.
|
||||
At runtime, the plugin will provide these paths to Godot core which will use them to load and initialize the bundled GDExtension libraries.
|
||||
|
||||
Reference implementations
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
32
tutorials/scripting/gdextension/files/cpp_example/SConstruct
Normal file
32
tutorials/scripting/gdextension/files/cpp_example/SConstruct
Normal file
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env python
|
||||
import os
|
||||
import sys
|
||||
|
||||
env = SConscript("godot-cpp/SConstruct")
|
||||
|
||||
# For reference:
|
||||
# - CCFLAGS are compilation flags shared between C and C++
|
||||
# - CFLAGS are for C-specific compilation flags
|
||||
# - CXXFLAGS are for C++-specific compilation flags
|
||||
# - CPPFLAGS are for pre-processor flags
|
||||
# - CPPDEFINES are for pre-processor defines
|
||||
# - LINKFLAGS are for linking flags
|
||||
|
||||
# tweak this if you want to use different folders, or more folders, to store your source code in.
|
||||
env.Append(CPPPATH=["src/"])
|
||||
sources = Glob("src/*.cpp")
|
||||
|
||||
if env["platform"] == "macos":
|
||||
library = env.SharedLibrary(
|
||||
"demo/bin/libgdexample.{}.{}.framework/libgdexample.{}.{}".format(
|
||||
env["platform"], env["target"], env["platform"], env["target"]
|
||||
),
|
||||
source=sources,
|
||||
)
|
||||
else:
|
||||
library = env.SharedLibrary(
|
||||
"demo/bin/libgdexample{}{}".format(env["suffix"], env["SHLIBSUFFIX"]),
|
||||
source=sources,
|
||||
)
|
||||
|
||||
Default(library)
|
||||
638
tutorials/scripting/gdextension/gdextension_cpp_example.rst
Normal file
638
tutorials/scripting/gdextension/gdextension_cpp_example.rst
Normal file
@@ -0,0 +1,638 @@
|
||||
.. _doc_gdextension_cpp_example:
|
||||
|
||||
GDExtension C++ example
|
||||
=======================
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
The C++ bindings for GDExtension are built on top of the C GDExtension API
|
||||
and provide a nicer way to "extend" nodes and other built-in classes in Godot using C++.
|
||||
This new system allows the extension of Godot to nearly the same
|
||||
level as statically linked C++ modules.
|
||||
|
||||
You can download the included example in the test folder of the godot-cpp
|
||||
repository `on GitHub <https://github.com/godotengine/godot-cpp>`__.
|
||||
|
||||
Setting up the project
|
||||
----------------------
|
||||
|
||||
There are a few prerequisites you'll need:
|
||||
|
||||
- a Godot 4 executable,
|
||||
- a C++ compiler,
|
||||
- SCons as a build tool,
|
||||
- a copy of the `godot-cpp
|
||||
repository <https://github.com/godotengine/godot-cpp>`__.
|
||||
|
||||
See also :ref:`Compiling <toc-devel-compiling>` as the build tools are identical
|
||||
to the ones you need to compile Godot from source.
|
||||
|
||||
You can download this repository from GitHub or let Git do the work for you.
|
||||
Note that this repository has different branches for different versions
|
||||
of Godot. GDExtensions will not work in older versions of Godot (only Godot 4 and up) and vice versa, so make sure you download the correct branch.
|
||||
|
||||
.. note::
|
||||
|
||||
To use `GDExtension <https://godotengine.org/article/introducing-gd-extensions>`__
|
||||
you need to use the ``master`` branch of godot-cpp,
|
||||
which is only compatible with Godot 4.0 and follow this example.
|
||||
|
||||
If you are versioning your project using Git, it is a good idea to add it as
|
||||
a Git submodule:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
mkdir gdextension_cpp_example
|
||||
cd gdextension_cpp_example
|
||||
git init
|
||||
git submodule add -b master https://github.com/godotengine/godot-cpp
|
||||
cd godot-cpp
|
||||
git submodule update --init
|
||||
|
||||
If you decide to just download the repositories or clone them into your project
|
||||
folder, make sure to keep the folder layout identical to the one described here,
|
||||
as much of the code we'll be showcasing here assumes the project follows this
|
||||
layout.
|
||||
|
||||
Do make sure you clone recursively to pull in both repositories:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
mkdir gdextension_cpp_example
|
||||
cd gdextension_cpp_example
|
||||
git clone -b master https://github.com/godotengine/godot-cpp
|
||||
|
||||
.. note::
|
||||
|
||||
If you decide to download the repository or clone it into your folder,
|
||||
make sure to keep the folder layout the same as we've setup here. Much of
|
||||
the code we'll be showcasing here assumes the project has this layout.
|
||||
|
||||
If you cloned the example from the link specified in the introduction, the
|
||||
submodules are not automatically initialized. You will need to execute the
|
||||
following commands:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
cd gdextension_cpp_example
|
||||
git submodule update --init
|
||||
|
||||
This will initialize the repository in your project folder.
|
||||
|
||||
Building the C++ bindings
|
||||
-------------------------
|
||||
|
||||
Now that we've downloaded our prerequisites, it is time to build the C++
|
||||
bindings.
|
||||
|
||||
The repository contains a copy of the metadata for the current Godot release,
|
||||
but if you need to build these bindings for a newer version of Godot, simply
|
||||
call the Godot executable:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
godot --dump-extension-api extension_api.json
|
||||
|
||||
Place the resulting ``extension_api.json`` file in the project folder and add
|
||||
``custom_api_file=<PATH_TO_FILE>`` to the scons command
|
||||
below.
|
||||
|
||||
To generate and compile the bindings, use this command (replacing ``<platform>``
|
||||
with ``windows``, ``linux`` or ``macos`` depending on your OS):
|
||||
|
||||
To speed up compilation, add `-jN` at the end of the SCons command line where `N`
|
||||
is the number of CPU threads you have on your system. The example below uses 4 threads.
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
cd godot-cpp
|
||||
scons platform=<platform> -j4 custom_api_file=<PATH_TO_FILE>
|
||||
cd ..
|
||||
|
||||
This step will take a while. When it is completed, you should have static
|
||||
libraries that can be compiled into your project stored in ``godot-cpp/bin/``.
|
||||
|
||||
.. note::
|
||||
|
||||
You may need to add ``bits=64`` to the command on Windows or Linux.
|
||||
|
||||
Creating a simple plugin
|
||||
------------------------
|
||||
|
||||
Now it's time to build an actual plugin. We'll start by creating an empty Godot
|
||||
project in which we'll place a few files.
|
||||
|
||||
Open Godot and create a new project. For this example, we will place it in a
|
||||
folder called ``demo`` inside our GDExtension's folder structure.
|
||||
|
||||
In our demo project, we'll create a scene containing a Node called "Main" and
|
||||
we'll save it as ``main.tscn``. We'll come back to that later.
|
||||
|
||||
Back in the top-level GDExtension module folder, we're also going to create a
|
||||
subfolder called ``src`` in which we'll place our source files.
|
||||
|
||||
You should now have ``demo``, ``godot-cpp``, and ``src``
|
||||
directories in your GDExtension module.
|
||||
|
||||
Your folder structure should now look like this:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
gdextension_cpp_example/
|
||||
|
|
||||
+--demo/ # game example/demo to test the extension
|
||||
|
|
||||
+--godot-cpp/ # C++ bindings
|
||||
|
|
||||
+--src/ # source code of the extension we are building
|
||||
|
||||
In the ``src`` folder, we'll start with creating our header file for the
|
||||
GDExtension node we'll be creating. We will name it ``gdexample.h``:
|
||||
|
||||
.. code-block:: C++
|
||||
|
||||
#ifndef GDEXAMPLE_H
|
||||
#define GDEXAMPLE_H
|
||||
|
||||
#include <godot_cpp/classes/sprite2d.hpp>
|
||||
|
||||
namespace godot {
|
||||
|
||||
class GDExample : public Sprite2D {
|
||||
GDCLASS(GDExample, Sprite2D)
|
||||
|
||||
private:
|
||||
float time_passed;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
GDExample();
|
||||
~GDExample();
|
||||
|
||||
void _process(float delta);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
There are a few things of note to the above. We include ``sprite2d.hpp`` which
|
||||
contains bindings to the Sprite2D class. We'll be extending this class in our
|
||||
module.
|
||||
|
||||
We're using the namespace ``godot``, since everything in GDExtension is defined
|
||||
within this namespace.
|
||||
|
||||
Then we have our class definition, which inherits from our Sprite2D through a
|
||||
container class. We'll see a few side effects of this later on. The
|
||||
``GDCLASS`` macro sets up a few internal things for us.
|
||||
|
||||
After that, we declare a single member variable called ``time_passed``.
|
||||
|
||||
In the next block we're defining our methods, we have our constructor
|
||||
and destructor defined, but there are two other functions that will likely look
|
||||
familiar to some, and one new method.
|
||||
|
||||
The first is ``_bind_methods``, which is a static function that Godot will
|
||||
call to find out which methods can be called and which properties it exposes.
|
||||
The second is our ``_process`` function, which will work exactly the same
|
||||
as the ``_process`` function you're used to in GDScript.
|
||||
|
||||
Let's implement our functions by creating our ``gdexample.cpp`` file:
|
||||
|
||||
.. code-block:: C++
|
||||
|
||||
#include "gdexample.h"
|
||||
#include <godot_cpp/core/class_db.hpp>
|
||||
|
||||
using namespace godot;
|
||||
|
||||
void GDExample::_bind_methods() {
|
||||
}
|
||||
|
||||
GDExample::GDExample() {
|
||||
// initialize any variables here
|
||||
time_passed = 0.0;
|
||||
}
|
||||
|
||||
GDExample::~GDExample() {
|
||||
// add your cleanup here
|
||||
}
|
||||
|
||||
void GDExample::_process(float delta) {
|
||||
time_passed += delta;
|
||||
|
||||
Vector2 new_position = Vector2(10.0 + (10.0 * sin(time_passed * 2.0)), 10.0 + (10.0 * cos(time_passed * 1.5)));
|
||||
|
||||
set_position(new_position);
|
||||
}
|
||||
|
||||
This one should be straightforward. We're implementing each method of our class
|
||||
that we defined in our header file.
|
||||
|
||||
Note our ``_process`` function, which keeps track of how much time has passed
|
||||
and calculates a new position for our sprite using a sine and cosine function.
|
||||
|
||||
There is one more C++ file we need; we'll name it ``register_types.cpp``. Our
|
||||
GDExtension plugin can contain multiple classes, each with their own header
|
||||
and source file like we've implemented ``GDExample`` up above. What we need now
|
||||
is a small bit of code that tells Godot about all the classes in our
|
||||
GDExtension plugin.
|
||||
|
||||
.. code-block:: C++
|
||||
|
||||
#include "register_types.h"
|
||||
|
||||
#include "gdexample.h"
|
||||
|
||||
#include <gdextension_interface.h>
|
||||
#include <godot_cpp/core/defs.hpp>
|
||||
#include <godot_cpp/core/class_db.hpp>
|
||||
#include <godot_cpp/godot.hpp>
|
||||
|
||||
using namespace godot;
|
||||
|
||||
void initialize_example_module(ModuleInitializationLevel p_level) {
|
||||
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
|
||||
return;
|
||||
}
|
||||
|
||||
ClassDB::register_class<GDExample>();
|
||||
}
|
||||
|
||||
void uninitialize_example_module(ModuleInitializationLevel p_level) {
|
||||
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
// Initialization.
|
||||
GDExtensionBool GDE_EXPORT example_library_init(const GDExtensionInterface *p_interface, const GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) {
|
||||
godot::GDExtensionBinding::InitObject init_obj(p_interface, p_library, r_initialization);
|
||||
|
||||
init_obj.register_initializer(initialize_example_module);
|
||||
init_obj.register_terminator(uninitialize_example_module);
|
||||
init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SCENE);
|
||||
|
||||
return init_obj.init();
|
||||
}
|
||||
}
|
||||
|
||||
The ``initialize_example_module`` and ``uninitialize_example_module`` functions get
|
||||
called respectively when Godot loads our plugin and when it unloads it. All
|
||||
we're doing here is parse through the functions in our bindings module to
|
||||
initialize them, but you might have to set up more things depending on your
|
||||
needs. We call the function ``register_class`` for each of our classes in our library.
|
||||
|
||||
The important function is the third function called ``example_library_init``.
|
||||
We first call a function in our bindings library that creates an initilization object.
|
||||
This object registrates the initialization and termination functions of the GDExtension.
|
||||
Furthermore, it sets the level of initilization (core, servers, scene, editor, level).
|
||||
|
||||
At last, we need the header file for the ``register_types.cpp`` named
|
||||
``register_types.h``.
|
||||
|
||||
.. code-block:: C++
|
||||
|
||||
#ifndef GDEXAMPLE_REGISTER_TYPES_H
|
||||
#define GDEXAMPLE_REGISTER_TYPES_H
|
||||
|
||||
void initialize_example_module();
|
||||
void uninitialize_example_module();
|
||||
|
||||
#endif // GDEXAMPLE_REGISTER_TYPES_H
|
||||
|
||||
|
||||
Compiling the plugin
|
||||
--------------------
|
||||
|
||||
We cannot easily write by hand a ``SConstruct`` file that SCons would use for
|
||||
building. For the purpose of this example, just use
|
||||
:download:`this hardcoded SConstruct file <files/cpp_example/SConstruct>` we've
|
||||
prepared. We'll cover a more customizable, detailed example on how to use these
|
||||
build files in a subsequent tutorial.
|
||||
|
||||
.. note::
|
||||
|
||||
This ``SConstruct`` file was written to be used with the latest ``godot-cpp``
|
||||
master, you may need to make small changes using it with older versions or
|
||||
refer to the ``SConstruct`` file in the Godot 4.0 documentation.
|
||||
|
||||
Once you've downloaded the ``SConstruct`` file, place it in your GDExtension folder
|
||||
structure alongside ``godot-cpp``, ``src`` and ``demo``, then run:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
scons platform=<platform>
|
||||
|
||||
You should now be able to find the module in ``demo/bin/<platform>``.
|
||||
|
||||
.. note::
|
||||
|
||||
Here, we've compiled both godot-cpp and our gdexample library as debug
|
||||
builds. For optimized builds, you should compile them using the
|
||||
``target=template_release`` switch.
|
||||
|
||||
Using the GDExtension module
|
||||
----------------------------
|
||||
|
||||
Before we jump back into Godot, we need to create one more file in
|
||||
``demo/bin/``.
|
||||
|
||||
This file lets Godot know what dynamic libraries should be
|
||||
loaded for each platform and the entry function for the module. It is called ``gdexample.gdextension``.
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
[configuration]
|
||||
|
||||
entry_symbol = "example_library_init"
|
||||
|
||||
[libraries]
|
||||
|
||||
linux.64="res://bin/libgdexample.linux.64.so"
|
||||
windows.x86_64="res://bin/libgdexample.windows.x86_64.dll"
|
||||
macos="res://bin/libgdexample.macos.framework"
|
||||
|
||||
This file contains a ``configuration`` section that controls the entry function of the module.
|
||||
|
||||
The ``libraries`` section is the important bit: it tells Godot the location of the
|
||||
dynamic library in the project's filesystem for each supported platform. It will
|
||||
also result in *just* that file being exported when you export the project,
|
||||
which means the data pack won't contain libraries that are incompatible with the
|
||||
target platform.
|
||||
|
||||
Finally, the ``dependencies`` section allows you to name additional dynamic
|
||||
libraries that should be included as well. This is important when your GDExtension
|
||||
plugin implements someone else's library and requires you to supply a
|
||||
third-party dynamic library with your project.
|
||||
|
||||
Here is another overview to check the correct file structure:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
gdextension_cpp_example/
|
||||
|
|
||||
+--demo/ # game example/demo to test the extension
|
||||
| |
|
||||
| +--main.tscn
|
||||
| |
|
||||
| +--bin/
|
||||
| |
|
||||
| +--gdexample.gdextension
|
||||
|
|
||||
+--godot-cpp/ # C++ bindings
|
||||
|
|
||||
+--src/ # source code of the extension we are building
|
||||
| |
|
||||
| +--register_types.cpp
|
||||
| +--register_types.h
|
||||
| +--gdexample.cpp
|
||||
| +--gdexample.h
|
||||
|
||||
Time to jump back into Godot. We load up the main scene we created way back in
|
||||
the beginning and now add a newly available GDExample node to the scene:
|
||||
|
||||
.. image:: img/gdextension_cpp_nodes.webp
|
||||
|
||||
We're going to assign the Godot logo to this node as our texture, disable the
|
||||
``centered`` property:
|
||||
|
||||
.. image:: img/gdextension_cpp_sprite.webp
|
||||
|
||||
We're finally ready to run the project:
|
||||
|
||||
.. image:: img/gdextension_cpp_animated.gif
|
||||
|
||||
Adding properties
|
||||
-----------------
|
||||
|
||||
GDScript allows you to add properties to your script using the ``export``
|
||||
keyword. In GDExtension you have to register the properties with a getter and
|
||||
setter function or directly implement the ``_get_property_list``, ``_get`` and
|
||||
``_set`` methods of an object (but that goes far beyond the scope of this
|
||||
tutorial.
|
||||
|
||||
Lets add a property that allows us to control the amplitude of our wave.
|
||||
|
||||
In our ``gdexample.h`` file we need to add a member variable and getter and setter
|
||||
functions:
|
||||
|
||||
.. code-block:: C++
|
||||
|
||||
...
|
||||
private:
|
||||
float time_passed;
|
||||
float amplitude;
|
||||
|
||||
public:
|
||||
void set_amplitude(const float amplitude);
|
||||
float get_amplitude() const;
|
||||
...
|
||||
|
||||
In our ``gdexample.cpp`` file we need to make a number of changes, we will only
|
||||
show the methods we end up changing, don't remove the lines we're omitting:
|
||||
|
||||
.. code-block:: C++
|
||||
|
||||
void GDExample::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("get_amplitude"), &GDExample::get_amplitude);
|
||||
ClassDB::bind_method(D_METHOD("set_amplitude", "p_amplitude"), &GDExample::set_amplitude);
|
||||
ClassDB::add_property("GDExample", PropertyInfo(Variant::FLOAT, "amplitude"), "set_amplitude", "get_amplitude");
|
||||
}
|
||||
|
||||
void GDExample::GDExample() {
|
||||
// initialize any variables here
|
||||
time_passed = 0.0;
|
||||
amplitude = 10.0;
|
||||
}
|
||||
|
||||
void GDExample::_process(float delta) {
|
||||
time_passed += delta;
|
||||
|
||||
Vector2 new_position = Vector2(
|
||||
amplitude + (amplitude * sin(time_passed * 2.0)),
|
||||
amplitude + (amplitude * cos(time_passed * 1.5))
|
||||
);
|
||||
|
||||
set_position(new_position);
|
||||
}
|
||||
|
||||
void GDExample::set_amplitude(const float p_amplitude) {
|
||||
amplitude = p_amplitude;
|
||||
}
|
||||
|
||||
float GDExample::get_amplitude() const {
|
||||
return amplitude;
|
||||
}
|
||||
|
||||
Once you compile the module with these changes in place, you will see that a
|
||||
property has been added to our interface. You can now change this property and
|
||||
when you run your project, you will see that our Godot icon travels along a
|
||||
larger figure.
|
||||
|
||||
Let's do the same but for the speed of our animation and use a setter and getter
|
||||
function. Our ``gdexample.h`` header file again only needs a few more lines of
|
||||
code:
|
||||
|
||||
.. code-block:: C++
|
||||
|
||||
...
|
||||
float amplitude;
|
||||
float speed;
|
||||
...
|
||||
void _process(float delta) override;
|
||||
void set_speed(float p_speed);
|
||||
float get_speed();
|
||||
...
|
||||
|
||||
This requires a few more changes to our ``gdexample.cpp`` file, again we're only
|
||||
showing the methods that have changed so don't remove anything we're omitting:
|
||||
|
||||
.. code-block:: C++
|
||||
|
||||
void GDExample::_bind_methods() {
|
||||
...
|
||||
ClassDB::bind_method(D_METHOD("get_speed"), &GDExample::get_speed);
|
||||
ClassDB::bind_method(D_METHOD("set_speed", "p_speed"), &GDExample::set_speed);
|
||||
ClassDB::add_property("GDExample", PropertyInfo(Variant::FLOAT, "speed", PROPERTY_HINT_RANGE, "0,20,0.01"), "set_speed", "get_speed");
|
||||
}
|
||||
|
||||
void GDExample::GDExample() {
|
||||
time_passed = 0.0;
|
||||
amplitude = 10.0;
|
||||
speed = 1.0;
|
||||
}
|
||||
|
||||
void GDExample::_process(float delta) {
|
||||
time_passed += speed * delta;
|
||||
|
||||
Vector2 new_position = Vector2(
|
||||
amplitude + (amplitude * sin(time_passed * 2.0)),
|
||||
amplitude + (amplitude * cos(time_passed * 1.5))
|
||||
);
|
||||
|
||||
set_position(new_position);
|
||||
}
|
||||
|
||||
...
|
||||
|
||||
void GDExample::set_speed(float p_speed) {
|
||||
speed = p_speed;
|
||||
}
|
||||
|
||||
float GDExample::get_speed() const {
|
||||
return speed;
|
||||
}
|
||||
|
||||
Now when the project is compiled, we'll see another property called speed.
|
||||
Changing its value will make the animation go faster or slower.
|
||||
Furthermore, we added a property range which describes in which range the value can be.
|
||||
The first two arguments are the minimum and maximum value and the third is the step size.
|
||||
|
||||
.. note::
|
||||
|
||||
For simplicity, we've only used the hint_range of the property method.
|
||||
There are a lot more options to choose from. These can be used to
|
||||
further configure how properties are displayed and set on the Godot side.
|
||||
|
||||
Signals
|
||||
-------
|
||||
|
||||
Last but not least, signals fully work in GDExtension as well. Having your extension
|
||||
react to a signal given out by another object requires you to call ``connect``
|
||||
on that object. We can't think of a good example for our wobbling Godot icon, we
|
||||
would need to showcase a far more complete example.
|
||||
|
||||
This is the required syntax:
|
||||
|
||||
.. code-block:: C++
|
||||
|
||||
some_other_node->connect("the_signal", this, "my_method");
|
||||
|
||||
Note that you can only call ``my_method`` if you've previously registered it in
|
||||
your ``_bind_methods`` method.
|
||||
|
||||
Having your object sending out signals is more common. For our wobbling
|
||||
Godot icon, we'll do something silly just to show how it works. We're going to
|
||||
emit a signal every time a second has passed and pass the new location along.
|
||||
|
||||
In our ``gdexample.h`` header file, we need to define a new member ``time_emit``:
|
||||
|
||||
.. code-block:: C++
|
||||
|
||||
...
|
||||
float time_passed;
|
||||
float time_emit;
|
||||
float amplitude;
|
||||
...
|
||||
|
||||
This time, the changes in ``gdexample.cpp`` are more elaborate. First,
|
||||
you'll need to set ``time_emit = 0.0;`` in either our ``_init`` method or in our
|
||||
constructor. We'll look at the other 2 needed changes one by one.
|
||||
|
||||
In our ``_bind_methods`` method, we need to declare our signal. This is done
|
||||
as follows:
|
||||
|
||||
.. code-block:: C++
|
||||
|
||||
void GDExample::_bind_methods() {
|
||||
...
|
||||
ClassDB::add_property("GDExample", PropertyInfo(Variant::FLOAT, "speed", PROPERTY_HINT_RANGE, "0,20,0.01"), "set_speed", "get_speed");
|
||||
|
||||
ADD_SIGNAL(MethodInfo("position_changed", PropertyInfo(Variant::OBJECT, "node"), PropertyInfo(Variant::VECTOR2, "new_pos")));
|
||||
}
|
||||
|
||||
Here, our ``ADD_SIGNAL`` method can be a single call first taking the
|
||||
signals name, then having pairs of the type specifying the parameter name and
|
||||
the value of each parameter we'll send along with this signal.
|
||||
|
||||
Next, we'll need to change our ``_process`` method:
|
||||
|
||||
.. code-block:: C++
|
||||
|
||||
void GDExample::_process(float delta) {
|
||||
time_passed += speed * delta;
|
||||
|
||||
Vector2 new_position = Vector2(
|
||||
amplitude + (amplitude * sin(time_passed * 2.0)),
|
||||
amplitude + (amplitude * cos(time_passed * 1.5))
|
||||
);
|
||||
|
||||
set_position(new_position);
|
||||
|
||||
time_emit += delta;
|
||||
if (time_emit > 1.0) {
|
||||
emit_signal("position_changed", this, new_position);
|
||||
|
||||
time_emit = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
After a second has passed, we emit our signal and reset our counter. We can add
|
||||
our parameter values directly to ``emit_signal``.
|
||||
|
||||
Once the GDExtension library is compiled, we can go into Godot and select our sprite
|
||||
node. In the **Node** dock, we can find our new signal and link it up by pressing
|
||||
the **Connect** button or double-clicking the signal. We've added a script on
|
||||
our main node and implemented our signal like this:
|
||||
|
||||
.. code-block:: GDScript
|
||||
|
||||
extends Node
|
||||
|
||||
func _on_Sprite2D_position_changed(node, new_pos):
|
||||
print("The position of " + node.get_class() + " is now " + str(new_pos))
|
||||
|
||||
Every second, we output our position to the console.
|
||||
|
||||
Next steps
|
||||
----------
|
||||
|
||||
We hope the above example showed you the basics. You can
|
||||
build upon this example to create full-fledged scripts to control nodes in Godot
|
||||
using C++.
|
||||
BIN
tutorials/scripting/gdextension/img/gdextension_cpp_animated.gif
Normal file
BIN
tutorials/scripting/gdextension/img/gdextension_cpp_animated.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
BIN
tutorials/scripting/gdextension/img/gdextension_cpp_nodes.webp
Normal file
BIN
tutorials/scripting/gdextension/img/gdextension_cpp_nodes.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 37 KiB |
BIN
tutorials/scripting/gdextension/img/gdextension_cpp_sprite.webp
Normal file
BIN
tutorials/scripting/gdextension/img/gdextension_cpp_sprite.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.6 KiB |
9
tutorials/scripting/gdextension/index.rst
Normal file
9
tutorials/scripting/gdextension/index.rst
Normal file
@@ -0,0 +1,9 @@
|
||||
GDExtension
|
||||
===========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:name: toc-tutorials-gdnative
|
||||
|
||||
what_is_gdextension
|
||||
gdextension_cpp_example
|
||||
94
tutorials/scripting/gdextension/what_is_gdextension.rst
Normal file
94
tutorials/scripting/gdextension/what_is_gdextension.rst
Normal file
@@ -0,0 +1,94 @@
|
||||
.. _doc_what_is_gdextension:
|
||||
|
||||
What is GDExtension?
|
||||
====================
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
**GDExtension** is a Godot-specific technology that lets the engine interact with
|
||||
native `shared libraries <https://en.wikipedia.org/wiki/Library_(computing)#Shared_libraries>`__
|
||||
at run-time. You can use it to run native code without compiling it with the engine.
|
||||
|
||||
.. note:: GDExtension is *not* a scripting language and has no relation to
|
||||
:ref:`GDScript <doc_gdscript>`.
|
||||
|
||||
Differences between GDExtension and C++ modules
|
||||
-----------------------------------------------
|
||||
|
||||
You can use both GDExtension and :ref:`C++ modules <doc_custom_modules_in_c++>` to
|
||||
run C or C++ code in a Godot project.
|
||||
|
||||
They also both allow you to integrate third-party libraries into Godot. The one
|
||||
you should choose depends on your needs.
|
||||
|
||||
Advantages of GDExtension
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Unlike modules, GDExtension doesn't require compiling the engine's source code,
|
||||
making it easier to distribute your work. It gives you access to most of the API
|
||||
available to GDScript and C#, allowing you to code game logic with full control
|
||||
regarding performance. It's ideal if you need high-performance code you'd like
|
||||
to distribute as an add-on in the :ref:`asset library <doc_what_is_assetlib>`.
|
||||
|
||||
Also:
|
||||
|
||||
- GDExtension is not limited to C and C++. Thanks to :ref:`third-party bindings
|
||||
<doc_what_is_gdnative_third_party_bindings>`, you can use it with many other
|
||||
languages.
|
||||
- You can use the same compiled GDExtension library in the editor and exported
|
||||
project. With C++ modules, you have to recompile all the export templates you
|
||||
plan to use if you require its functionality at run-time.
|
||||
- GDExtension only requires you to compile your library, not the whole engine.
|
||||
That's unlike C++ modules, which are statically compiled into the engine.
|
||||
Every time you change a module, you need to recompile the engine. Even with
|
||||
incremental builds, this process is slower than using GDExtension.
|
||||
|
||||
Advantages of C++ modules
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
We recommend :ref:`C++ modules <doc_custom_modules_in_c++>` in cases where
|
||||
GDExtension isn't enough:
|
||||
|
||||
- C++ modules provide deeper integration into the engine. GDExtension's access is not as deep as
|
||||
static modules
|
||||
- You can use C++ modules to provide additional features in a project without
|
||||
carrying native library files around. This extends to exported projects.
|
||||
|
||||
Supported languages
|
||||
-------------------
|
||||
|
||||
The Godot developers officially support the following language bindings for
|
||||
GDExtension:
|
||||
|
||||
- C++ :ref:`(tutorial) <doc_gdextension_cpp_example>`
|
||||
|
||||
.. note::
|
||||
|
||||
There are no plans to support additional languages with GDExtension officially.
|
||||
That said, the community offers several bindings for other languages (see
|
||||
below).
|
||||
|
||||
.. _doc_what_is_gdnative_third_party_bindings:
|
||||
|
||||
The bindings below are developed and maintained by the community:
|
||||
|
||||
.. Binding developers: Feel free to open a pull request to add your binding if it's well-developed enough to be used in a project.
|
||||
.. Please keep languages sorted in alphabetical order.
|
||||
|
||||
- `Rust <https://github.com/godot-rust/godot-rust>`__
|
||||
|
||||
.. note::
|
||||
|
||||
Not all bindings mentioned here may be production-ready. Make sure to
|
||||
research options thoroughly before starting a project with one of those.
|
||||
Also, double-check whether the binding is compatible with the Godot version
|
||||
you're using.
|
||||
|
||||
Version compatibility
|
||||
---------------------
|
||||
|
||||
GDExtension add-ons compiled for a given Godot version are only guaranteed to work
|
||||
with the same minor release series. For example, a GDExtension add-on compiled for
|
||||
Godot 4.0 will only work with Godot 4.0, 4.0.1, 4.0.2. In addition, GDExtension is
|
||||
not compatible with Godot 3.x.
|
||||
@@ -19,6 +19,7 @@ The sections below each focus on a given programming language.
|
||||
|
||||
gdscript/index
|
||||
c_sharp/index
|
||||
gdextension/index
|
||||
|
||||
Core features
|
||||
-------------
|
||||
|
||||
Reference in New Issue
Block a user