Browse Source

Merge pull request #5604 from Calinou/gdnative-cpp-example-remove-nativescript-1.0

Remove references to NativeScript 1.0 in GDNative C++ example
Max Hilbrunner 3 years ago
parent
commit
37b4b1430a
1 changed files with 48 additions and 253 deletions
  1. 48 253
      tutorials/scripting/gdnative/gdnative_cpp_example.rst

+ 48 - 253
tutorials/scripting/gdnative/gdnative_cpp_example.rst

@@ -14,13 +14,6 @@ The C++ bindings for GDNative are built on top of the NativeScript GDNative API
 and provide a nicer way to "extend" nodes in Godot using C++. This is equivalent
 to writing scripts in GDScript, but in C++ instead.
 
-Godot 3.1 saw the introduction of the NativeScript 1.1 additions that enabled
-the GDNative team to build a nicer C++ bindings library. These changes have now
-been merged into the master branch and will be the way we go forward. If you
-want to write a C++ GDNative plugin that also supports Godot 3.0 you will need
-to use the 3.0 branch and the NativeScript 1.0 syntax. We'll be showing them
-side by side in this writeup.
-
 You can download the full example we'll be creating in this tutorial `on
 GitHub <https://github.com/BastiaanOlij/gdnative_cpp_example>`__.
 
@@ -48,16 +41,18 @@ with becomes your minimum version.
 
 .. note::
 
-    `GDExtension <https://godotengine.org/article/introducing-gd-extensions>`__ has been merged in the ``master`` branch of godot-cpp,
+    `GDExtension <https://godotengine.org/article/introducing-gd-extensions>`__
+    has been merged in the ``master`` branch of godot-cpp,
     but it is only compatible with the upcoming Godot 4.0.
     Therefore, you need to use the ``3.x`` branch of godot-cpp to use GDNative
     and follow this example.
 
+    This tutorial covers only GDNative in Godot 3.x, *not* GDExtension in Godot 4.0.
+
 If you are versioning your project using Git, it is a good idea to add them as
 Git submodules:
 
-.. tabs::
- .. code-tab:: none Godot
+.. code-block:: none
 
     mkdir gdnative_cpp_example
     cd gdnative_cpp_example
@@ -66,15 +61,6 @@ Git submodules:
     cd godot-cpp
     git submodule update --init
 
- .. code-tab:: none Godot 3.0
-
-    mkdir gdnative_cpp_example
-    cd gdnative_cpp_example
-    git init
-    git submodule add -b 3.0 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
@@ -82,28 +68,21 @@ layout.
 
 Do make sure you clone recursive to pull in both repositories:
 
-.. tabs::
- .. code-tab:: none Godot
+.. code-block:: none
 
     mkdir gdnative_cpp_example
     cd gdnative_cpp_example
     git clone --recursive -b 3.x https://github.com/godotengine/godot-cpp
 
- .. code-tab:: none Godot 3.0
-
-    mkdir gdnative_cpp_example
-    cd gdnative_cpp_example
-    git clone --recursive -b 3.0 https://github.com/godotengine/godot-cpp
-
 .. note::
 
     ``godot-cpp`` now includes ``godot-headers`` as a nested submodule, if you've
     manually downloaded them please make sure to place ``godot-headers`` inside
     of the ``godot-cpp`` folder.
 
-    You don't have to do it this way but we've found it easiest to manage. If you
-    decide to just download the repositories or just clone them into your folder,
-    make sure to keep the folder layout the same as we've setup here as much of
+    You don't have to do it this way, but we've found it easiest to manage. If you
+    decide to download the repositories or clone them 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
@@ -138,7 +117,8 @@ below.
 To generate and compile the bindings, use this command (replacing ``<platform>``
 with ``windows``, ``linux`` or ``osx`` 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.
+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
 
@@ -149,13 +129,9 @@ To speed up compilation, add `-jN` at the end of the SCons command line where `N
 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/``.
 
-At some point in the future, compiled binaries will be available, making this
-step optional.
-
 .. note::
 
-    You may need to add ``bits=64`` to the command on Windows or Linux. We're
-    still working on better auto detection.
+    You may need to add ``bits=64`` to the command on Windows or Linux.
 
 Creating a simple plugin
 ------------------------
@@ -178,8 +154,7 @@ directories in your GDNative module.
 In the ``src`` folder, we'll start with creating our header file for the
 GDNative node we'll be creating. We will name it ``gdexample.h``:
 
-.. tabs::
- .. code-tab:: C++ NativeScript 1.1
+.. code-block:: C++
 
     #ifndef GDEXAMPLE_H
     #define GDEXAMPLE_H
@@ -210,35 +185,6 @@ GDNative node we'll be creating. We will name it ``gdexample.h``:
 
     #endif
 
- .. code-tab:: C++ NativeScript 1.0
-
-    #ifndef GDEXAMPLE_H
-    #define GDEXAMPLE_H
-
-    #include <Godot.hpp>
-    #include <Sprite2D.hpp>
-
-    namespace godot {
-
-    class GDExample : public godot::GodotScript<Sprite2D> {
-        GODOT_CLASS(GDExample)
-
-    private:
-        float time_passed;
-
-    public:
-        static void _register_methods();
-
-        GDExample();
-        ~GDExample();
-
-        void _process(float delta);
-    };
-
-    }
-
-    #endif
-
 There are a few things of note to the above. We're including ``Godot.hpp`` which
 contains all our basic definitions. After that, we include ``Sprite2D.hpp`` which
 contains bindings to the Sprite2D class. We'll be extending this class in our
@@ -271,8 +217,7 @@ our object.
 
 Let's implement our functions by creating our ``gdexample.cpp`` file:
 
-.. tabs::
- .. code-tab:: C++ NativeScript 1.1
+.. code-block:: C++
 
     #include "gdexample.h"
 
@@ -302,33 +247,6 @@ Let's implement our functions by creating our ``gdexample.cpp`` file:
         set_position(new_position);
     }
 
- .. code-tab:: C++ NativeScript 1.0
-
-    #include "gdexample.h"
-
-    using namespace godot;
-
-    void GDExample::_register_methods() {
-        register_method((char *)"_process", &GDExample::_process);
-    }
-
-    GDExample::GDExample() {
-        // Initialize any variables here
-        time_passed = 0.0;
-    }
-
-    GDExample::~GDExample() {
-        // Add your cleanup procedure 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)));
-
-        owner->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 that the ``register_method`` call
 **must** expose the ``_process`` method, otherwise Godot will not be able to use
@@ -340,8 +258,7 @@ of how much time has passed and calculates a new position for our sprite using a
 sine and cosine function. What stands out is calling
 ``owner->set_position`` to call one of the build in methods of our Sprite2D. This
 is because our class is a container class; ``owner`` points to the actual Sprite2D
-node our script relates to. Since NativeScript 1.1, ``set_position``
-can be called directly on our class.
+node our script relates to.
 
 There is one more C++ file we need; we'll name it ``gdlibrary.cpp``. Our
 GDNative plugin can contain multiple NativeScripts, each with their own header
@@ -531,8 +448,7 @@ In our ``gdexample.h`` file we simply need to add a member variable like so:
 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:
 
-.. tabs::
- .. code-tab:: C++ NativeScript 1.1
+.. code-block:: C++
 
     void GDExample::_register_methods() {
         register_method("_process", &GDExample::_process);
@@ -556,31 +472,7 @@ show the methods we end up changing, don't remove the lines we're omitting:
         set_position(new_position);
     }
 
- .. code-tab:: C++ NativeScript 1.0
-
-    void GDExample::_register_methods() {
-        register_method((char *)"_process", &GDExample::_process);
-        register_property<GDExample, float>("amplitude", &GDExample::amplitude, 10.0);
-    }
-
-    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))
-        );
-
-        owner->set_position(new_position);
-    }
-
-Once you compile the module with these changes in place you will see that a
+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.
@@ -591,11 +483,11 @@ larger figure.
     ``true`` for the Godot editor to automatically pick up the newly added
     property.
 
-    However, this setting should be used with care especially when tool classes
+    However, this setting should be used with care, especially when tool classes
     are used, as the editor might hold objects then that have script instances
     attached to them that are managed by a GDNative library.
 
-Lets do the same but for the speed of our animation and use a setter and getter
+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:
 
@@ -613,8 +505,7 @@ code:
 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:
 
-.. tabs::
- .. code-tab:: C++ NativeScript 1.1
+.. code-block:: C++
 
     void GDExample::_register_methods() {
         register_method("_process", &GDExample::_process);
@@ -648,53 +539,19 @@ showing the methods that have changed so don't remove anything we're omitting:
         return speed;
     }
 
- .. code-tab:: C++ NativeScript 1.0
-
-    void GDExample::_register_methods() {
-        register_method((char *)"_process", &GDExample::_process);
-        register_property<GDExample, float>("amplitude", &GDExample::amplitude, 10.0);
-        register_property<GDExample, float>("speed", &GDExample::set_speed, &GDExample::get_speed, 1.0);
-    }
-
-    GDExample::GDExample() {
-        // initialize any variables here
-        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))
-        );
-
-        owner->set_position(new_position);
-    }
-
-    void GDExample::set_speed(float p_speed) {
-        speed = p_speed;
-    }
-
-    float GDExample::get_speed() {
-        return speed;
-    }
-
-Now when the project is compiled we'll see another property called 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.
 
-For this example there is no obvious advantage of using a setter and getter.
-A good reason for a setter would be if you wanted to react on the variable being changed, but in
-many cases binding the variable is enough.
+For this example, there is no obvious advantage of using a setter and getter.
+A good reason for a setter would be if you wanted to react on the variable being changed.
+If you don't need to do something like that, binding the variable is enough.
 
 Getters and setters become far more useful in more complex scenarios where you
 need to make additional choices based on the state of your object.
 
 .. note::
 
-    For simplicity we've left out the optional parameters in the
+    For simplicity, we've left out the optional parameters in the
     register_property<class, type> method call. These parameters are
     ``rpc_mode``, ``usage``, ``hint`` and ``hint_string``. These can be used to
     further configure how properties are displayed and set on the Godot side.
@@ -711,26 +568,20 @@ 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 however is the required syntax:
+This is the required syntax:
 
-.. tabs::
- .. code-tab:: C++ NativeScript 1.1
+.. code-block:: C++
 
     some_other_node->connect("the_signal", this, "my_method");
 
- .. code-tab:: C++ NativeScript 1.0
-
-    some_other_node->connect("the_signal", owner, "my_method");
-
 Note that you can only call ``my_method`` if you've previously registered it in
 your ``_register_methods`` method.
 
-Having your object sending out signals is far more common. For our wobbling
-Godot icon we'll do something silly just to show how it works. We're going to
+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 just need to define a new member
-``time_emit``:
+In our ``gdexample.h`` header file, we need to define a new member ``time_emit``:
 
 .. code-block:: C++
 
@@ -740,15 +591,14 @@ In our ``gdexample.h`` header file we just need to define a new member
         float amplitude;
     ...
 
-The changes in ``gdexample.cpp`` are a bit more elaborate this time. First
+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. But the other two needed changes we'll look at one by one.
+constructor. We'll look at the other 2 needed changes one by one.
 
-In our ``_register_methods`` method we need to declare our signal and we do this
+In our ``_register_methods`` method, we need to declare our signal. This is done
 as follows:
 
-.. tabs::
- .. code-tab:: C++ NativeScript 1.1
+.. code-block:: C++
 
     void GDExample::_register_methods() {
         register_method("_process", &GDExample::_process);
@@ -758,31 +608,13 @@ as follows:
         register_signal<GDExample>((char *)"position_changed", "node", GODOT_VARIANT_TYPE_OBJECT, "new_pos", GODOT_VARIANT_TYPE_VECTOR2);
     }
 
- .. code-tab:: C++ NativeScript 1.0
+Here, our ``register_signal`` method can be a single call first taking the
+signals name, then having pairs of values specifying the parameter name and
+type of each parameter we'll send along with this signal.
 
-    void GDExample::_register_methods() {
-        register_method((char *)"_process", &GDExample::_process);
-        register_property<GDExample, float>("amplitude", &GDExample::amplitude, 10.0);
-        register_property<GDExample, float>("speed", &GDExample::set_speed, &GDExample::get_speed, 1.0);
-
-        Dictionary args;
-        args[Variant("node")] = Variant(Variant::OBJECT);
-        args[Variant("new_pos")] = Variant(Variant::VECTOR2);
-        register_signal<GDExample>((char *)"position_changed", args);
-    }
-
-Here we see a nice improvement in the latest version of godot-cpp where our
-``register_signal`` method can be a single call first taking the signals name,
-then having pairs of values specifying the parameter name and type of each
-parameter we'll send along with this signal.
-
-For NativeScript 1.0 we first build a dictionary in which we tell Godot about
-the types of arguments we will pass to our signal, and then register it.
+Next, we'll need to change our ``_process`` method:
 
-Next we'll need to change our ``_process`` method:
-
-.. tabs::
- .. code-tab:: C++ NativeScript 1.1
+.. code-block:: C++
 
     void GDExample::_process(float delta) {
         time_passed += speed * delta;
@@ -802,59 +634,22 @@ Next we'll need to change our ``_process`` method:
         }
     }
 
- .. code-tab:: C++ NativeScript 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))
-        );
-
-        owner->set_position(new_position);
-
-        time_emit += delta;
-        if (time_emit > 1.0) {
-            Array args;
-            args.push_back(Variant(owner));
-            args.push_back(Variant(new_position));
-            owner->emit_signal("position_changed", args);
-
-            time_emit = 0.0;
-        }
-    }
-
-After a second has passed we emit our signal and reset our counter. Again in the
-new version of godot-cpp we can add our parameter values directly to
-``emit_signal``. In NativeScript 1.0 We first build an array of values and then
-call ``emit_signal``.
+After a second has passed, we emit our signal and reset our counter. We can add
+our parameter values directly to ``emit_signal``.
 
-Once compiled we can go into Godot and select our sprite node. On our ``Node``
-tab we find our new signal and link it up by pressing connect. We've added a
-script on our main node and implemented our signal like this:
+Once the GDNative 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:: none
+.. code-block:: GDScript
 
     extends Node
 
     func _on_Sprite2D_position_changed(node, new_pos):
         print("The position of " + node.name + " is now " + str(new_pos))
 
-Every second we simply output our position to the console.
-
-NativeScript 1.1 vs NativeScript 1.0
-------------------------------------
-
-So far in our example above there doesn't seem to be a lot of difference between
-the old and new syntax. The class is defined slightly differently and we no
-longer use the ``owner`` member to call methods on the Godot side of our object.
-A lot of the improvements are hidden under the hood.
-
-This example only deals with simple variables and methods. Especially
-once you start passing references to other objects or when you start calling
-methods that require more complex parameters, NativeScript 1.1 does start to
-show its benefits.
+Every second, we output our position to the console.
 
 Next steps
 ----------
@@ -864,4 +659,4 @@ build upon this example to create full-fledged scripts to control nodes in Godot
 using C++.
 
 To edit and recompile the plugin while the Godot editor
-remains open, rerun the project after the library has finished building.
+remains open, re-run the project after the library has finished building.