diff --git a/_tools/redirects/redirects.csv b/_tools/redirects/redirects.csv index 1e1eb66e282c..7eefd4be0dcf 100644 --- a/_tools/redirects/redirects.csv +++ b/_tools/redirects/redirects.csv @@ -18,8 +18,8 @@ source,destination /community/contributing/updating_the_class_reference.html,/contributing/documentation/updating_the_class_reference.html /community/contributing/ways_to_contribute.html,/contributing/ways_to_contribute.html /community/tutorials/3d/mesh_generation_with_heightmap_and_shaders.html,/tutorials/3d/mesh_generation_with_heightmap_and_shaders.html -/community/tutorials/gdnative/gdnative-c-example.html,/tutorials/plugins/gdnative/gdnative-c-example.html -/community/tutorials/gdnative/index.html,/tutorials/plugins/gdnative/index.html +/community/tutorials/gdextension/gdextension-c-example.html,/tutorials/plugins/gdextension/gdextension-c-example.html +/community/tutorials/gdextension/index.html,/tutorials/plugins/gdextension/index.html /community/tutorials/vr/index.html,/tutorials/vr/index.html /community/tutorials/vr/vr_primer.html,/tutorials/vr/vr_primer.html /content/3d/making_trees.html,/tutorials/content/making_trees.html @@ -376,9 +376,9 @@ source,destination /tutorials/platform/android_in_app_purchases.html,/tutorials/platform/android/android_in_app_purchases.html /tutorials/plugins/android/android_plugin.html,/tutorials/platform/android/android_plugin.html /tutorials/plugins/android/index.html,/tutorials/platform/android/index.html -/tutorials/plugins/gdnative/gdnative-c-example.html,/tutorials/scripting/gdnative/gdnative_c_example.html -/tutorials/plugins/gdnative/gdnative-cpp-example.html,/tutorials/scripting/gdnative/gdnative_cpp_example.html -/tutorials/plugins/gdnative/index.html,/tutorials/scripting/gdnative/index.html +/tutorials/plugins/gdextension/gdextension-c-example.html,/tutorials/scripting/gdextension/gdextension_c_example.html +/tutorials/plugins/gdextension/gdextension-cpp-example.html,/tutorials/scripting/gdextension/gdextension_cpp_example.html +/tutorials/plugins/gdextension/index.html,/tutorials/scripting/gdextension/index.html /tutorials/shading/advanced_postprocessing.html,/tutorials/shaders/advanced_postprocessing.html /tutorials/shading/godot_shader_language_style_guide.html,/tutorials/shaders/shaders_style_guide.html /tutorials/shading/index.html,/tutorials/shaders/index.html diff --git a/about/docs_changelog.rst b/about/docs_changelog.rst index bd28199a6fea..2f774e9c1893 100644 --- a/about/docs_changelog.rst +++ b/about/docs_changelog.rst @@ -107,6 +107,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) diff --git a/getting_started/first_2d_game/06.heads_up_display.rst b/getting_started/first_2d_game/06.heads_up_display.rst index a60b07346336..e9ba9e1908e9 100644 --- a/getting_started/first_2d_game/06.heads_up_display.rst +++ b/getting_started/first_2d_game/06.heads_up_display.rst @@ -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"); diff --git a/getting_started/step_by_step/scripting_languages.rst b/getting_started/step_by_step/scripting_languages.rst index 4cd33def7202..a2d8886fd373 100644 --- a/getting_started/step_by_step/scripting_languages.rst +++ b/getting_started/step_by_step/scripting_languages.rst @@ -124,10 +124,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 diff --git a/tutorials/export/feature_tags.rst b/tutorials/export/feature_tags.rst index 3bbcfad2796d..f7e270026a1c 100644 --- a/tutorials/export/feature_tags.rst +++ b/tutorials/export/feature_tags.rst @@ -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**. diff --git a/tutorials/networking/webrtc.rst b/tutorials/networking/webrtc.rst index c486f3eb204d..b90da25a42b6 100644 --- a/tutorials/networking/webrtc.rst +++ b/tutorials/networking/webrtc.rst @@ -35,7 +35,7 @@ Using WebRTC in Godot WebRTC is implemented in Godot via two main classes :ref:`WebRTCPeerConnection ` and :ref:`WebRTCDataChannel `, plus the multiplayer API implementation :ref:`WebRTCMultiplayerPeer `. See section on :ref:`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 `__ for instructions and to get the latest `release `__. +.. 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 `__ for instructions and to get the latest `release `__. .. warning:: diff --git a/tutorials/platform/android/android_plugin.rst b/tutorials/platform/android/android_plugin.rst index 72c5fa110615..0f927b5b8b79 100644 --- a/tutorials/platform/android/android_plugin.rst +++ b/tutorials/platform/android/android_plugin.rst @@ -133,19 +133,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 ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tutorials/scripting/gdextension/files/cpp_example/SConstruct b/tutorials/scripting/gdextension/files/cpp_example/SConstruct new file mode 100644 index 000000000000..691f81319445 --- /dev/null +++ b/tutorials/scripting/gdextension/files/cpp_example/SConstruct @@ -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) diff --git a/tutorials/scripting/gdextension/gdextension_cpp_example.rst b/tutorials/scripting/gdextension/gdextension_cpp_example.rst new file mode 100644 index 000000000000..5cdf8046883b --- /dev/null +++ b/tutorials/scripting/gdextension/gdextension_cpp_example.rst @@ -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 `__. + +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 `__. + +See also :ref:`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 `__ + 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=`` to the scons command +below. + +To generate and compile the bindings, use this command (replacing ```` +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= -j4 custom_api_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 + + 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 + + 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 + #include + #include + #include + + using namespace godot; + + void initialize_example_module(ModuleInitializationLevel p_level) { + if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) { + return; + } + + ClassDB::register_class(); + } + + 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 ` 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= + +You should now be able to find the module in ``demo/bin/``. + +.. 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.png + +We're going to assign the Godot logo to this node as our texture, disable the +``centered`` property: + +.. image:: img/gdextension_cpp_sprite.png + +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++. diff --git a/tutorials/scripting/gdextension/img/gdextension_cpp_animated.gif b/tutorials/scripting/gdextension/img/gdextension_cpp_animated.gif new file mode 100644 index 000000000000..9a5488889fba Binary files /dev/null and b/tutorials/scripting/gdextension/img/gdextension_cpp_animated.gif differ diff --git a/tutorials/scripting/gdextension/img/gdextension_cpp_nodes.png b/tutorials/scripting/gdextension/img/gdextension_cpp_nodes.png new file mode 100644 index 000000000000..c4a93cb088ad Binary files /dev/null and b/tutorials/scripting/gdextension/img/gdextension_cpp_nodes.png differ diff --git a/tutorials/scripting/gdextension/img/gdextension_cpp_sprite.png b/tutorials/scripting/gdextension/img/gdextension_cpp_sprite.png new file mode 100644 index 000000000000..2ad007126f3a Binary files /dev/null and b/tutorials/scripting/gdextension/img/gdextension_cpp_sprite.png differ diff --git a/tutorials/scripting/gdextension/index.rst b/tutorials/scripting/gdextension/index.rst new file mode 100644 index 000000000000..23a5c19d4ee8 --- /dev/null +++ b/tutorials/scripting/gdextension/index.rst @@ -0,0 +1,9 @@ +GDExtension +=========== + +.. toctree:: + :maxdepth: 1 + :name: toc-tutorials-gdnative + + what_is_gdextension + gdextension_cpp_example \ No newline at end of file diff --git a/tutorials/scripting/gdextension/what_is_gdextension.rst b/tutorials/scripting/gdextension/what_is_gdextension.rst new file mode 100644 index 000000000000..fe2c287d2392 --- /dev/null +++ b/tutorials/scripting/gdextension/what_is_gdextension.rst @@ -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 `__ +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 `. + +Differences between GDExtension and C++ modules +----------------------------------------------- + +You can use both GDExtension and :ref:`C++ modules ` 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 `. + +Also: + +- GDExtension is not limited to C and C++. Thanks to :ref:`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 ` 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) ` + +.. 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 `__ + +.. 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. diff --git a/tutorials/scripting/index.rst b/tutorials/scripting/index.rst index 2ba0ad7d2ae2..3d3ca7feffae 100644 --- a/tutorials/scripting/index.rst +++ b/tutorials/scripting/index.rst @@ -19,6 +19,7 @@ The sections below each focus on a given programming language. gdscript/index c_sharp/index + gdextension/index Core features -------------