gdnative-cpp-example.rst 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. .. _doc_gdnative_cpp_example:
  2. GDNative C++ example
  3. ====================
  4. Introduction
  5. ------------
  6. This tutorial builds on top of the information given in the
  7. :ref:`GDNative C example <doc_gdnative_c_example>`, so we highly
  8. recommend you read that first.
  9. The C++ bindings for GDNative are built on top of the
  10. NativeScript GDNative API and provide a nicer way to "extend" nodes
  11. in Godot using C++. This is equivalent to writing scripts in GDScript,
  12. but in C++ instead.
  13. We'll be looking at NativeScript 1.0 which is available in Godot 3.0.
  14. Godot 3.1 will see the introduction of NativeScript 1.1, which comes with a
  15. number of improvements. We'll update this tutorial once it is
  16. officially released, but the overall structure remains similar.
  17. You can download the full example we'll be creating in this tutorial
  18. `on GitHub <https://github.com/BastiaanOlij/gdnative_cpp_example>`_.
  19. Setting up the project
  20. ----------------------
  21. There are a few prerequisites you'll need:
  22. - a Godot 3.x executable,
  23. - a C++ compiler,
  24. - SCons as a build tool,
  25. - a copy of the `godot_headers repository <https://github.com/GodotNativeTools/godot_headers>`_,
  26. - a copy of the `godot-cpp repository <https://github.com/GodotNativeTools/godot-cpp>`_.
  27. See also :ref:`Compiling <toc-devel-compiling>` as the build tools are identical
  28. to the ones you need to compile Godot from source.
  29. You can download these repositories from GitHub or let Git
  30. do the work for you.
  31. Note that these repositories now have different branches for different versions of Godot. GDNative modules written for an earlier version of Godot will work in newer versions (with the exception of one breaking change in ARVR interfaces between 3.0 and 3.1) but not vise versa so make sure you download the correct branch.
  32. If you are versioning your project using Git,
  33. it is a good idea to add them as Git submodules:
  34. .. code-block:: none
  35. mkdir gdnative_cpp_example
  36. cd gdnative_cpp_example
  37. git init
  38. git submodule add -b 3.0 https://github.com/GodotNativeTools/godot-cpp
  39. cd godot-cpp
  40. git submodule init
  41. git submodule update
  42. cd ..
  43. If you decide to just download the repositories or clone them
  44. into your project folder, make sure to keep the folder layout identical
  45. to the one described here, as much of the code we'll be showcasing here
  46. assumes the project follows this layout.
  47. Do make sure you clone recursive to pull in both repositories:
  48. .. code-block:: none
  49. mkdir gdnative_cpp_example
  50. cd gdnative_cpp_example
  51. git clone --recursive -b 3.0 https://github.com/GodotNativeTools/godot-cpp
  52. .. note:: The ``-b 3.0`` I've added as an example to show how to select a specific branch for a specific version of Godot.
  53. Also ``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.
  54. You don't have to do it this way but I've found it easiest to manage. If you decide to just download the repositories or just clone them into your folder, makes sure to keep the folder layout the same as I've setup here as much of the code we'll be showcasing here assumes the project has this layout.
  55. If you cloned the example from the link specified in
  56. the introduction, the submodules are not automatically initialized.
  57. You will need to execute the following commands:
  58. .. code-block:: none
  59. cd gdnative_cpp_example
  60. git submodule --init update --recursive
  61. This will clone these two repositories into your project folder.
  62. Building the C++ bindings
  63. -------------------------
  64. Now that we've downloaded our prerequisites, it is time to build
  65. the C++ bindings.
  66. The repository contains a copy of the metadata for the current Godot release,
  67. but if you need to build these bindings for a newer version of Godot,
  68. simply call the Godot executable:
  69. .. code-block:: none
  70. godot --gdnative-generate-json-api api.json
  71. Place the resulting ``api.json`` file in the project folder and add ``use_custom_api_file=yes custom_api_file=../api.json`` to the scons command below.
  72. To generate and compile the bindings, use this command (replacing
  73. ``<platform>`` with ``windows``, ``x11`` or ``osx`` depending on your OS):
  74. .. code-block:: none
  75. cd godot-cpp
  76. scons platform=<platform> generate_bindings=yes
  77. cd ..
  78. This step will take a while. When it is completed, you should have static
  79. libraries that can be compiled into your project stored in ``godot-cpp/bin/``.
  80. At some point in the future, compiled binaries will be available,
  81. making this step optional.
  82. Creating a simple plugin
  83. ------------------------
  84. Now it's time to build an actual plugin. We'll start by creating an
  85. empty Godot project in which we'll place a few files.
  86. Open Godot and create a new project. For this example, we will place it
  87. in a folder called ``demo`` inside our GDNative module's folder structure.
  88. In our demo project, we'll create a scene containing a Node called "Main"
  89. and we'll save it as ``main.tscn``. We'll come back to that later.
  90. Back in the top-level GDNative module folder, we're also going to create
  91. a subfolder called ``src`` in which we'll place our source files.
  92. You should now have ``demo``, ``godot-cpp``, ``godot_headers``,
  93. and ``src`` directories in your GDNative module.
  94. In the ``src`` folder, we'll start with creating our header file
  95. for the GDNative node we'll be creating. We will name it ``gdexample.h``:
  96. .. code:: C++
  97. #ifndef GDEXAMPLE_H
  98. #define GDEXAMPLE_H
  99. #include <Godot.hpp>
  100. #include <Sprite.hpp>
  101. namespace godot {
  102. class gdexample : public godot::GodotScript<Sprite> {
  103. GODOT_CLASS(gdexample)
  104. private:
  105. float time_passed;
  106. public:
  107. static void _register_methods();
  108. gdexample();
  109. ~gdexample();
  110. void _process(float delta);
  111. };
  112. }
  113. #endif
  114. There are a few things of note to the above.
  115. We're including ``Godot.hpp`` which contains all our basic definitions.
  116. After that, we include ``Sprite.hpp`` which contains bindings
  117. to the Sprite class. We'll be extending this class in our module.
  118. We're using the namespace ``godot``, since everything in GDNative
  119. is defined within this namespace.
  120. Then we have our class definition, which inherits from our Sprite
  121. through a container class. We'll see a few side effects of this later on.
  122. This is also the main bit that is going to improve in NativeScript 1.1.
  123. The ``GODOT_CLASS`` macro sets up a few internal things for us.
  124. After that, we declare a single member variable called ``time_passed``.
  125. In the next block we're defining our methods, we obviously have
  126. our constructor and destructor defined, but there are two other
  127. functions that will likely look familiar to some.
  128. The first is ``_register_methods``, which is a static function that Godot
  129. will call to find out which methods can be called on our NativeScript
  130. and which properties it exposes. The second is our ``_process`` function,
  131. which will work exactly the same as the ``_process`` function
  132. you're used to in GDScript.
  133. So, let's implement our functions by creating our ``gdexample.cpp`` file:
  134. .. code:: C++
  135. #include "gdexample.h"
  136. using namespace godot;
  137. void gdexample::_register_methods() {
  138. register_method((char *)"_process", &gdexample::_process);
  139. }
  140. gdexample::gdexample() {
  141. // Initialize any variables here
  142. time_passed = 0.0;
  143. }
  144. gdexample::~gdexample() {
  145. // Add your cleanup procedure here
  146. }
  147. void gdexample::_process(float delta) {
  148. time_passed += delta;
  149. Vector2 new_position = Vector2(10.0 + (10.0 * sin(time_passed * 2.0)), 10.0 + (10.0 * cos(time_passed * 1.5)));
  150. owner->set_position(new_position);
  151. }
  152. This one should be straightforward. We're implementing each method of
  153. our class that we defined in our header file.
  154. Note that the ``register_method`` call **must** expose the ``_process`` method,
  155. otherwise Godot will not be able to use it. However, we do not have to tell Godot
  156. about our constructor and destructor.
  157. The other method of note is our ``_process`` function, which simply keeps track
  158. of how much time has passed and calculates a new position for our sprite
  159. using a simple sine and cosine function.
  160. What stands out is calling ``owner->set_position`` to call one of the build
  161. in methods of our Sprite. This is because our class is a container class;
  162. ``owner`` points to the actual Sprite node our script relates to.
  163. In the upcoming NativeScript 1.1, ``set_position`` can be called
  164. directly on our class.
  165. There is one more C++ file we need; we'll name it ``gdlibrary.cpp``.
  166. Our GDNative plugin can contain multiple NativeScripts, each with their
  167. own header and source file like we've implemented ``gdexample`` up above.
  168. What we need now is a small bit of code that tells Godot about all the
  169. NativeScripts in our GDNative plugin.
  170. .. code:: C++
  171. #include "gdexample.h"
  172. extern "C" void GDN_EXPORT godot_gdnative_init(godot_gdnative_init_options *o) {
  173. godot::Godot::gdnative_init(o);
  174. }
  175. extern "C" void GDN_EXPORT godot_gdnative_terminate(godot_gdnative_terminate_options *o) {
  176. godot::Godot::gdnative_terminate(o);
  177. }
  178. extern "C" void GDN_EXPORT godot_nativescript_init(void *handle) {
  179. godot::Godot::nativescript_init(handle);
  180. godot::register_class<godot::gdexample>();
  181. }
  182. Note that we are not using the ``godot`` namespace here, since the
  183. three functions implemented here need to be defined without a namespace.
  184. The ``godot_gdnative_init`` and ``godot_gdnative_terminate`` functions
  185. get called respectively when Godot loads our plugin and when it unloads it.
  186. All we're doing here is parse through the functions in our bindings module
  187. to initialize them, but you might have to set up more things depending
  188. on your needs.
  189. The important function is the third function called
  190. ``godot_nativescript_init``. We first call a function in our bindings
  191. library that does its usual stuff. After that, we call the function
  192. ``register_class`` for each of our classes in our library.
  193. Compiling the plugin
  194. --------------------
  195. We cannot easily write by hand a ``SConstruct`` file that SCons would
  196. use for building. For the purpose of this example, just use
  197. :download:`this hardcoded SConstruct file <files/cpp_example/SConstruct>`
  198. we've prepared. We'll cover a more customizable, detailed example on
  199. how to use these build files in a subsequent tutorial.
  200. Once you've downloaded the ``SConstruct`` file, place it in your
  201. GDNative module folder besides ``godot-cpp``, ``godot_headers``
  202. and ``demo``, then run:
  203. .. code-block:: none
  204. scons platform=<platform>
  205. You should now be able to find the module in ``demo/bin/<platform>``.
  206. .. note::
  207. Here, we've compiled both godot-cpp and our gdexample library
  208. as debug builds. For optimized builds, you should compile them using
  209. the ``target=release`` switch.
  210. Using the GDNative module
  211. -------------------------
  212. Before we jump back into Godot, we need to create two more files
  213. in ``demo/bin/``. Both can be created using the Godot editor,
  214. but it may be faster to create them directly.
  215. The first one is a file that lets Godot know what dynamic libraries
  216. should be loaded for each platform and is called ``gdexample.gdnlib``.
  217. .. code-block:: none
  218. [general]
  219. singleton=false
  220. load_once=true
  221. symbol_prefix="godot_"
  222. [entry]
  223. X11.64="res://bin/x11/libgdexample.so"
  224. Windows.64="res://bin/win64/libgdexample.dll"
  225. OSX.64="res://bin/osx/libgdexample.dylib"
  226. [dependencies]
  227. X11.64=[]
  228. Windows.64=[]
  229. OSX.64=[]
  230. This file contains a ``general`` section that controls how the module is loaded.
  231. It also contains a prefix section which should be left on ``godot_`` for now.
  232. If you change this, you'll need to rename various functions that are
  233. used as entry points. This was added for the iPhone platform because it doesn't
  234. allow dynamic libraries to be deployed, yet GDNative modules
  235. are linked statically.
  236. The ``entry`` section is the important bit: it tells Godot the location of
  237. the dynamic library in the project's filesystem for each supported platform.
  238. It will also result in *just* that file being exported when you export the
  239. project, which means the data pack won't contain libraries that are
  240. incompatible with the target platform.
  241. Finally, the ``dependencies`` section allows you to name additional
  242. dynamic libraries that should be included as well. This is important when
  243. your GDNative plugin implements someone else's library and requires you
  244. to supply a third-party dynamic library with your project.
  245. If you double click on the ``gdexample.gdnlib`` file within Godot,
  246. you'll see there are far more options to set:
  247. .. image:: img/gdnative_library.png
  248. The second file we need to create is a file used by each NativeScript
  249. we've added to our plugin. We'll name it ``gdexample.gdns`` for our
  250. gdexample NativeScript.
  251. .. code-block:: none
  252. [gd_resource type="NativeScript" load_steps=2 format=2]
  253. [ext_resource path="res://bin/gdexample.gdnlib" type="GDNativeLibrary" id=1]
  254. [resource]
  255. resource_name = "gdexample"
  256. class_name = "gdexample"
  257. library = ExtResource( 1 )
  258. _sections_unfolded = [ "Resource" ]
  259. This is a standard Godot resource; you could just create it directly
  260. in of your scene, but saving it to a file makes it much easier to reuse it
  261. in other places. This resource points to our gdnlib file, so that Godot
  262. can know which dynamic library contains our NativeScript. It also defines
  263. the ``class_name`` which identifies the NativeScript in our plugin
  264. we want to use.
  265. Time to jump back into Godot. We load up the main scene we created way back
  266. in the beginning and now add a Sprite to our scene:
  267. .. image:: img/gdnative_cpp_nodes.png
  268. We're going to assign the Godot logo to this sprite as our texture,
  269. disable the ``centered`` property and drag our ``gdexample.gdns`` file
  270. onto the ``script`` property of the sprite:
  271. .. image:: img/gdnative_cpp_sprite.png
  272. We're finally ready to run the project:
  273. .. image:: img/gdnative_cpp_animated.gif
  274. Next steps
  275. ----------
  276. The above is only a simple example, but we hope it shows you the basics.
  277. You can build upon this example to create full-fledged scripts to control
  278. nodes in Godot using C++.
  279. You should be able to edit and recompile the plugin while the Godot editor
  280. remains open; just rerun the project after the library has finished building.