gdnative-cpp-example.rst 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852
  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. Godot 3.1 saw the introduction of the NativeScript 1.1 additions that
  14. enabled the GDNative team to build a nicer C++ bindings library.
  15. These changes have now been merged into the master branch and will
  16. be the way we go forward. If you want to write a C++ GDNative plugin
  17. that also supports Godot 3.0 you will need to use the 3.0 branch and
  18. the NativeScript 1.0 syntax. We'll be showing them side by side in
  19. this writeup.
  20. You can download the full example we'll be creating in this tutorial
  21. `on GitHub <https://github.com/BastiaanOlij/gdnative_cpp_example>`_.
  22. Setting up the project
  23. ----------------------
  24. There are a few prerequisites you'll need:
  25. - a Godot 3.x executable,
  26. - a C++ compiler,
  27. - SCons as a build tool,
  28. - a copy of the `godot-cpp repository <https://github.com/GodotNativeTools/godot-cpp>`_.
  29. See also :ref:`Compiling <toc-devel-compiling>` as the build tools are identical
  30. to the ones you need to compile Godot from source.
  31. You can download these repositories from GitHub or let Git
  32. do the work for you.
  33. Note that these repositories now have different branches for different
  34. versions of Godot. GDNative modules written for an earlier version of
  35. Godot will work in newer versions (with the exception of one breaking
  36. change in ARVR interfaces between 3.0 and 3.1) but not vice versa so
  37. make sure you download the correct branch.
  38. Also note that the version of Godot you use to generate the ``api.json``
  39. with becomes your minimum version.
  40. If you are versioning your project using Git,
  41. it is a good idea to add them as Git submodules:
  42. .. tabs::
  43. .. code-tab:: none Godot
  44. mkdir gdnative_cpp_example
  45. cd gdnative_cpp_example
  46. git init
  47. git submodule add https://github.com/GodotNativeTools/godot-cpp
  48. cd godot-cpp
  49. git submodule update -- init
  50. .. code-tab:: none Godot 3.0
  51. mkdir gdnative_cpp_example
  52. cd gdnative_cpp_example
  53. git init
  54. git submodule add -b 3.0 https://github.com/GodotNativeTools/godot-cpp
  55. cd godot-cpp
  56. git submodule update -- init
  57. If you decide to just download the repositories or clone them
  58. into your project folder, make sure to keep the folder layout identical
  59. to the one described here, as much of the code we'll be showcasing here
  60. assumes the project follows this layout.
  61. Do make sure you clone recursive to pull in both repositories:
  62. .. tabs::
  63. .. code-tab:: none Godot
  64. mkdir gdnative_cpp_example
  65. cd gdnative_cpp_example
  66. git clone --recursive https://github.com/GodotNativeTools/godot-cpp
  67. .. code-tab:: none Godot 3.0
  68. mkdir gdnative_cpp_example
  69. cd gdnative_cpp_example
  70. git clone --recursive -b 3.0 https://github.com/GodotNativeTools/godot-cpp
  71. .. 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.
  72. 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 the code we'll be showcasing here assumes the project has this layout.
  73. If you cloned the example from the link specified in
  74. the introduction, the submodules are not automatically initialized.
  75. You will need to execute the following commands:
  76. .. code-block:: none
  77. cd gdnative_cpp_example
  78. git submodule --init update --recursive
  79. This will clone these two repositories into your project folder.
  80. Building the C++ bindings
  81. -------------------------
  82. Now that we've downloaded our prerequisites, it is time to build
  83. the C++ bindings.
  84. The repository contains a copy of the metadata for the current Godot release,
  85. but if you need to build these bindings for a newer version of Godot,
  86. simply call the Godot executable:
  87. .. code-block:: none
  88. godot --gdnative-generate-json-api api.json
  89. 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.
  90. To generate and compile the bindings, use this command (replacing
  91. ``<platform>`` with ``windows``, ``x11`` or ``osx`` depending on your OS):
  92. .. code-block:: none
  93. cd godot-cpp
  94. scons platform=<platform> generate_bindings=yes
  95. cd ..
  96. This step will take a while. When it is completed, you should have static
  97. libraries that can be compiled into your project stored in ``godot-cpp/bin/``.
  98. At some point in the future, compiled binaries will be available,
  99. making this step optional.
  100. .. note:: You may need to add ``bits=64`` to the command on Windows. We're still working on better auto detection.
  101. Creating a simple plugin
  102. ------------------------
  103. Now it's time to build an actual plugin. We'll start by creating an
  104. empty Godot project in which we'll place a few files.
  105. Open Godot and create a new project. For this example, we will place it
  106. in a folder called ``demo`` inside our GDNative module's folder structure.
  107. In our demo project, we'll create a scene containing a Node called "Main"
  108. and we'll save it as ``main.tscn``. We'll come back to that later.
  109. Back in the top-level GDNative module folder, we're also going to create
  110. a subfolder called ``src`` in which we'll place our source files.
  111. You should now have ``demo``, ``godot-cpp``, ``godot_headers``,
  112. and ``src`` directories in your GDNative module.
  113. In the ``src`` folder, we'll start with creating our header file
  114. for the GDNative node we'll be creating. We will name it ``gdexample.h``:
  115. .. tabs::
  116. .. code-tab:: C++ NativeScript 1.1
  117. #ifndef GDEXAMPLE_H
  118. #define GDEXAMPLE_H
  119. #include <Godot.hpp>
  120. #include <Sprite.hpp>
  121. namespace godot {
  122. class GDExample : public Sprite {
  123. GODOT_CLASS(GDExample, Sprite)
  124. private:
  125. float time_passed;
  126. public:
  127. static void _register_methods();
  128. GDExample();
  129. ~GDExample();
  130. void _init(); // our initializer called by Godot
  131. void _process(float delta);
  132. };
  133. }
  134. #endif
  135. .. code-tab:: C++ NativeScript 1.0
  136. #ifndef GDEXAMPLE_H
  137. #define GDEXAMPLE_H
  138. #include <Godot.hpp>
  139. #include <Sprite.hpp>
  140. namespace godot {
  141. class GDExample : public godot::GodotScript<Sprite> {
  142. GODOT_CLASS(GDExample)
  143. private:
  144. float time_passed;
  145. public:
  146. static void _register_methods();
  147. GDExample();
  148. ~GDExample();
  149. void _process(float delta);
  150. };
  151. }
  152. #endif
  153. There are a few things of note to the above.
  154. We're including ``Godot.hpp`` which contains all our basic definitions.
  155. After that, we include ``Sprite.hpp`` which contains bindings
  156. to the Sprite class. We'll be extending this class in our module.
  157. We're using the namespace ``godot``, since everything in GDNative
  158. is defined within this namespace.
  159. Then we have our class definition, which inherits from our Sprite
  160. through a container class. We'll see a few side effects of this later on.
  161. The ``GODOT_CLASS`` macro sets up a few internal things for us.
  162. After that, we declare a single member variable called ``time_passed``.
  163. In the next block we're defining our methods, we obviously have
  164. our constructor and destructor defined, but there are two other
  165. functions that will likely look familiar to some, and one new method.
  166. The first is ``_register_methods``, which is a static function that Godot
  167. will call to find out which methods can be called on our NativeScript
  168. and which properties it exposes.
  169. The second is our ``_process`` function,
  170. which will work exactly the same as the ``_process`` function
  171. you're used to in GDScript.
  172. The third is our ``_init`` function which is called after Godot has properly
  173. set up our object. It has to exist even if you don't place any code in it.
  174. Let's implement our functions by creating our ``gdexample.cpp`` file:
  175. .. tabs::
  176. .. code-tab:: C++ NativeScript 1.1
  177. #include "gdexample.h"
  178. using namespace godot;
  179. void GDExample::_register_methods() {
  180. register_method("_process", &GDExample::_process);
  181. }
  182. GDExample::GDExample() {
  183. }
  184. GDExample::~GDExample() {
  185. // add your cleanup here
  186. }
  187. void GDExample::_init() {
  188. // initialize any variables here
  189. time_passed = 0.0;
  190. }
  191. void GDExample::_process(float delta) {
  192. time_passed += delta;
  193. Vector2 new_position = Vector2(10.0 + (10.0 * sin(time_passed * 2.0)), 10.0 + (10.0 * cos(time_passed * 1.5)));
  194. set_position(new_position);
  195. }
  196. .. code-tab:: C++ NativeScript 1.0
  197. #include "gdexample.h"
  198. using namespace godot;
  199. void GDExample::_register_methods() {
  200. register_method((char *)"_process", &GDExample::_process);
  201. }
  202. GDExample::GDExample() {
  203. // Initialize any variables here
  204. time_passed = 0.0;
  205. }
  206. GDExample::~GDExample() {
  207. // Add your cleanup procedure here
  208. }
  209. void GDExample::_process(float delta) {
  210. time_passed += delta;
  211. Vector2 new_position = Vector2(10.0 + (10.0 * sin(time_passed * 2.0)), 10.0 + (10.0 * cos(time_passed * 1.5)));
  212. owner->set_position(new_position);
  213. }
  214. This one should be straightforward. We're implementing each method of
  215. our class that we defined in our header file.
  216. Note that the ``register_method`` call **must** expose the ``_process`` method,
  217. otherwise Godot will not be able to use it. However, we do not have to tell Godot
  218. about our constructor, destructor and ``_init`` functions.
  219. The other method of note is our ``_process`` function, which simply keeps track
  220. of how much time has passed and calculates a new position for our sprite
  221. using a simple sine and cosine function.
  222. What stands out is calling ``owner->set_position`` to call one of the build
  223. in methods of our Sprite. This is because our class is a container class;
  224. ``owner`` points to the actual Sprite node our script relates to.
  225. In the upcoming NativeScript 1.1, ``set_position`` can be called
  226. directly on our class.
  227. There is one more C++ file we need; we'll name it ``gdlibrary.cpp``.
  228. Our GDNative plugin can contain multiple NativeScripts, each with their
  229. own header and source file like we've implemented ``GDExample`` up above.
  230. What we need now is a small bit of code that tells Godot about all the
  231. NativeScripts in our GDNative plugin.
  232. .. code:: C++
  233. #include "gdexample.h"
  234. extern "C" void GDN_EXPORT godot_gdnative_init(godot_gdnative_init_options *o) {
  235. godot::Godot::gdnative_init(o);
  236. }
  237. extern "C" void GDN_EXPORT godot_gdnative_terminate(godot_gdnative_terminate_options *o) {
  238. godot::Godot::gdnative_terminate(o);
  239. }
  240. extern "C" void GDN_EXPORT godot_nativescript_init(void *handle) {
  241. godot::Godot::nativescript_init(handle);
  242. godot::register_class<godot::GDExample>();
  243. }
  244. Note that we are not using the ``godot`` namespace here, since the
  245. three functions implemented here need to be defined without a namespace.
  246. The ``godot_gdnative_init`` and ``godot_gdnative_terminate`` functions
  247. get called respectively when Godot loads our plugin and when it unloads it.
  248. All we're doing here is parse through the functions in our bindings module
  249. to initialize them, but you might have to set up more things depending
  250. on your needs.
  251. The important function is the third function called
  252. ``godot_nativescript_init``. We first call a function in our bindings
  253. library that does its usual stuff. After that, we call the function
  254. ``register_class`` for each of our classes in our library.
  255. Compiling the plugin
  256. --------------------
  257. We cannot easily write by hand a ``SConstruct`` file that SCons would
  258. use for building. For the purpose of this example, just use
  259. :download:`this hardcoded SConstruct file <files/cpp_example/SConstruct>`
  260. we've prepared. We'll cover a more customizable, detailed example on
  261. how to use these build files in a subsequent tutorial.
  262. .. note:: This ``SConstruct`` file was written to be used with the latest
  263. ``godot-cpp`` master, you may need to make small changes using it with
  264. older versions or refer to the ``SConstruct`` file in the Godot 3.0
  265. documentation.
  266. Once you've downloaded the ``SConstruct`` file, place it in your
  267. GDNative module folder besides ``godot-cpp``, ``godot_headers``
  268. and ``demo``, then run:
  269. .. code-block:: none
  270. scons platform=<platform>
  271. You should now be able to find the module in ``demo/bin/<platform>``.
  272. .. note::
  273. Here, we've compiled both godot-cpp and our gdexample library
  274. as debug builds. For optimized builds, you should compile them using
  275. the ``target=release`` switch.
  276. Using the GDNative module
  277. -------------------------
  278. Before we jump back into Godot, we need to create two more files
  279. in ``demo/bin/``. Both can be created using the Godot editor,
  280. but it may be faster to create them directly.
  281. The first one is a file that lets Godot know what dynamic libraries
  282. should be loaded for each platform and is called ``gdexample.gdnlib``.
  283. .. code-block:: none
  284. [general]
  285. singleton=false
  286. load_once=true
  287. symbol_prefix="godot_"
  288. reloadable=false
  289. [entry]
  290. X11.64="res://bin/x11/libgdexample.so"
  291. Windows.64="res://bin/win64/libgdexample.dll"
  292. OSX.64="res://bin/osx/libgdexample.dylib"
  293. [dependencies]
  294. X11.64=[]
  295. Windows.64=[]
  296. OSX.64=[]
  297. This file contains a ``general`` section that controls how the module is loaded.
  298. It also contains a prefix section which should be left on ``godot_`` for now.
  299. If you change this, you'll need to rename various functions that are
  300. used as entry points. This was added for the iPhone platform because it doesn't
  301. allow dynamic libraries to be deployed, yet GDNative modules
  302. are linked statically.
  303. The ``entry`` section is the important bit: it tells Godot the location of
  304. the dynamic library in the project's filesystem for each supported platform.
  305. It will also result in *just* that file being exported when you export the
  306. project, which means the data pack won't contain libraries that are
  307. incompatible with the target platform.
  308. Finally, the ``dependencies`` section allows you to name additional
  309. dynamic libraries that should be included as well. This is important when
  310. your GDNative plugin implements someone else's library and requires you
  311. to supply a third-party dynamic library with your project.
  312. If you double click on the ``gdexample.gdnlib`` file within Godot,
  313. you'll see there are far more options to set:
  314. .. image:: img/gdnative_library.png
  315. The second file we need to create is a file used by each NativeScript
  316. we've added to our plugin. We'll name it ``gdexample.gdns`` for our
  317. gdexample NativeScript.
  318. .. code-block:: none
  319. [gd_resource type="NativeScript" load_steps=2 format=2]
  320. [ext_resource path="res://bin/gdexample.gdnlib" type="GDNativeLibrary" id=1]
  321. [resource]
  322. resource_name = "gdexample"
  323. class_name = "GDExample"
  324. library = ExtResource( 1 )
  325. _sections_unfolded = [ "Resource" ]
  326. This is a standard Godot resource; you could just create it directly
  327. in your scene, but saving it to a file makes it much easier to reuse it
  328. in other places. This resource points to our gdnlib file, so that Godot
  329. can know which dynamic library contains our NativeScript. It also defines
  330. the ``class_name`` which identifies the NativeScript in our plugin
  331. we want to use.
  332. Time to jump back into Godot. We load up the main scene we created way back
  333. in the beginning and now add a Sprite to our scene:
  334. .. image:: img/gdnative_cpp_nodes.png
  335. We're going to assign the Godot logo to this sprite as our texture,
  336. disable the ``centered`` property and drag our ``gdexample.gdns`` file
  337. onto the ``script`` property of the sprite:
  338. .. image:: img/gdnative_cpp_sprite.png
  339. We're finally ready to run the project:
  340. .. image:: img/gdnative_cpp_animated.gif
  341. Adding properties
  342. -----------------
  343. GDScript allows you to add properties to your script using the ``export`` keyword.
  344. In GDNative you have to register the properties and there are two ways of doing this.
  345. You can either bind directly to a member or use a setter and getter function.
  346. .. note::
  347. There is a third option, just like in GDScript you can directly implement the
  348. ``_get_property_list``, ``_get`` and ``_set`` methods of an object but that
  349. goes far beyond the scope of this tutorial.
  350. We'll examine both starting with the direct bind.
  351. Lets add a property that allows us to control the amplitude of our wave.
  352. In our ``gdexample.h`` file we simply need to add a member variable like so:
  353. .. code:: C++
  354. ...
  355. private:
  356. float time_passed;
  357. float amplitude;
  358. ...
  359. In our ``gdexample.cpp`` file we need to make a number of changes, we will only show
  360. the methods we end up changing, don't remove the lines we're omitting:
  361. .. tabs::
  362. .. code-tab:: C++ NativeScript 1.1
  363. void GDExample::_register_methods() {
  364. register_method("_process", &GDExample::_process);
  365. register_property<GDExample, float>("amplitude", &GDExample::amplitude, 10.0);
  366. }
  367. void GDExample::_init() {
  368. // initialize any variables here
  369. time_passed = 0.0;
  370. amplitude = 10.0;
  371. }
  372. void GDExample::_process(float delta) {
  373. time_passed += delta;
  374. Vector2 new_position = Vector2(
  375. amplitude + (amplitude * sin(time_passed * 2.0)),
  376. amplitude + (amplitude * cos(time_passed * 1.5))
  377. );
  378. set_position(new_position);
  379. }
  380. .. code-tab:: C++ NativeScript 1.0
  381. void GDExample::_register_methods() {
  382. register_method((char *)"_process", &GDExample::_process);
  383. register_property<GDExample, float>("amplitude", &GDExample::amplitude, 10.0);
  384. }
  385. GDExample::GDExample() {
  386. // initialize any variables here
  387. time_passed = 0.0;
  388. amplitude = 10.0;
  389. }
  390. void GDExample::_process(float delta) {
  391. time_passed += delta;
  392. Vector2 new_position = Vector2(
  393. amplitude + (amplitude * sin(time_passed * 2.0)),
  394. amplitude + (amplitude * cos(time_passed * 1.5))
  395. );
  396. owner->set_position(new_position);
  397. }
  398. Once you compile the module with these changes in place you will see that
  399. a property has been added to our interface.
  400. You can now change this property and when you run your project, you will
  401. see that our Godot icon travels along a larger figure.
  402. .. note::
  403. The ``reloadable`` property in the ``gdexample.gdnlib`` file must be set to ``true`` for the Godot editor
  404. to automatically pick up the newly added property.
  405. However, this setting should be used with care especially when tool classes are used,
  406. as the editor might hold objects then that have script instances attached to them that are managed by a GDNative library.
  407. Lets do the same but for the speed of our animation and use a setter and getter function.
  408. Our ``gdexample.h`` header file again only needs a few more lines of code:
  409. .. code:: C++
  410. ...
  411. float amplitude;
  412. float speed;
  413. ...
  414. void _process(float delta);
  415. void set_speed(float p_speed);
  416. float get_speed();
  417. ...
  418. This requires a few more changes to our ``gdexample.cpp`` file, again we're only showing the
  419. methods that have changed so don't remove anything we're omitting:
  420. .. tabs::
  421. .. code-tab:: C++ NativeScript 1.1
  422. void GDExample::_register_methods() {
  423. register_method("_process", &GDExample::_process);
  424. register_property<GDExample, float>("amplitude", &GDExample::amplitude, 10.0);
  425. register_property<GDExample, float>("speed", &GDExample::set_speed, &GDExample::get_speed, 1.0);
  426. }
  427. void GDExample::_init() {
  428. // initialize any variables here
  429. time_passed = 0.0;
  430. amplitude = 10.0;
  431. speed = 1.0;
  432. }
  433. void GDExample::_process(float delta) {
  434. time_passed += speed * delta;
  435. Vector2 new_position = Vector2(
  436. amplitude + (amplitude * sin(time_passed * 2.0)),
  437. amplitude + (amplitude * cos(time_passed * 1.5))
  438. );
  439. set_position(new_position);
  440. }
  441. void GDExample::set_speed(float p_speed) {
  442. speed = p_speed;
  443. }
  444. float GDExample::get_speed() {
  445. return speed;
  446. }
  447. .. code-tab:: C++ NativeScript 1.0
  448. void GDExample::_register_methods() {
  449. register_method((char *)"_process", &GDExample::_process);
  450. register_property<GDExample, float>("amplitude", &GDExample::amplitude, 10.0);
  451. register_property<GDExample, float>("speed", &GDExample::set_speed, &GDExample::get_speed, 1.0);
  452. }
  453. GDExample::GDExample() {
  454. // initialize any variables here
  455. time_passed = 0.0;
  456. amplitude = 10.0;
  457. speed = 1.0;
  458. }
  459. void GDExample::_process(float delta) {
  460. time_passed += speed * delta;
  461. Vector2 new_position = Vector2(
  462. amplitude + (amplitude * sin(time_passed * 2.0)),
  463. amplitude + (amplitude * cos(time_passed * 1.5))
  464. );
  465. owner->set_position(new_position);
  466. }
  467. void GDExample::set_speed(float p_speed) {
  468. speed = p_speed;
  469. }
  470. float GDExample::get_speed() {
  471. return speed;
  472. }
  473. Now when the project is compiled we'll see another property called speed.
  474. Changing its value will make the animation go faster or slower.
  475. For this example there is no obvious advantage of using a setter and getter.
  476. It is just more code to write. For a simple example as this there may be a
  477. good reason for a setter if you want to react on the variable being changed
  478. but in many cases just binding the variable will be enough.
  479. Getters and setters become far more useful in more complex scenarios
  480. where you need to make additional choices based on the state of your
  481. object.
  482. .. note::
  483. For simplicity we've left out the optional parameters in the
  484. register_property<class, type> method call. These parameters are
  485. ``rpc_mode``, ``usage``, ``hint`` and ``hint_string``. These can
  486. be used to further configure how properties are displayed and set
  487. on the Godot side.
  488. Modern C++ compilers are able to infer the class and variable type
  489. and allow you to omit the ``<GDExample, float>`` part of our
  490. ``register_property`` method. we've had mixed experiences with this
  491. however.
  492. Signals
  493. -------
  494. Last but not least, signals fully work in GDNative as well.
  495. Having your module react to a signal given out by another object requires
  496. you to call ``connect`` on that object. We can't think of a good example for
  497. our wobbling Godot icon, we would need to showcase a far more complete
  498. example.
  499. This however is the required syntax:
  500. .. tabs::
  501. .. code-tab:: C++ NativeScript 1.1
  502. some_other_node->connect("the_signal", this, "my_method");
  503. .. code-tab:: C++ NativeScript 1.0
  504. some_other_node->connect("the_signal", owner, "my_method");
  505. Note that you can only call ``my_method`` if you've previously registered
  506. it in your ``_register_methods`` method.
  507. Having your object sending out signals is far more common. For our wobbling
  508. Godot icon we'll do something silly just to show how it works. We're going
  509. to emit a signal every time a second has passed and pass the new location
  510. along.
  511. In our ``gdexample.h`` header file we just need to define a new member ``time_emit``:
  512. .. code:: C++
  513. ...
  514. float time_passed;
  515. float time_emit;
  516. float amplitude;
  517. ...
  518. The changes in ``gdexample.cpp`` are a bit more elaborate this time.
  519. First you'll need to set ``time_emit = 0.0;`` in either our ``_init`` method or
  520. in our constructor. But the other two needed changes we'll look at one by one.
  521. In our ``_register_methods`` method we need to declare our signal and we do this
  522. as follows:
  523. .. tabs::
  524. .. code-tab:: C++ NativeScript 1.1
  525. void GDExample::_register_methods() {
  526. register_method("_process", &GDExample::_process);
  527. register_property<GDExample, float>("amplitude", &GDExample::amplitude, 10.0);
  528. register_property<GDExample, float>("speed", &GDExample::set_speed, &GDExample::get_speed, 1.0);
  529. register_signal<GDExample>((char *)"position_changed", "node", GODOT_VARIANT_TYPE_OBJECT, "new_pos", GODOT_VARIANT_TYPE_VECTOR2);
  530. }
  531. .. code-tab:: C++ NativeScript 1.0
  532. void GDExample::_register_methods() {
  533. register_method((char *)"_process", &GDExample::_process);
  534. register_property<GDExample, float>("amplitude", &GDExample::amplitude, 10.0);
  535. register_property<GDExample, float>("speed", &GDExample::set_speed, &GDExample::get_speed, 1.0);
  536. Dictionary args;
  537. args[Variant("node")] = Variant(Variant::OBJECT);
  538. args[Variant("new_pos")] = Variant(Variant::VECTOR2);
  539. register_signal<GDExample>((char *)"position_changed", args);
  540. }
  541. Here we see a nice improvement in the latest version of godot-cpp where our
  542. ``register_signal`` method can be a single call first taking the signals name,
  543. then having pairs of values specificying the parameter name and type of each
  544. parameter we'll send along with this signal.
  545. For NativeScript 1.0 we first build a dictionary in which we tell Godot about
  546. the types of arguments we will pass to our signal, and then register it.
  547. Next we'll need to change our ``_process`` method:
  548. .. tabs::
  549. .. code-tab:: C++ NativeScript 1.1
  550. void GDExample::_process(float delta) {
  551. time_passed += speed * delta;
  552. Vector2 new_position = Vector2(
  553. amplitude + (amplitude * sin(time_passed * 2.0)),
  554. amplitude + (amplitude * cos(time_passed * 1.5))
  555. );
  556. set_position(new_position);
  557. time_emit += delta;
  558. if (time_emit > 1.0) {
  559. emit_signal("position_changed", this, new_position);
  560. time_emit = 0.0;
  561. }
  562. }
  563. .. code-tab:: C++ NativeScript 1.0
  564. void GDExample::_process(float delta) {
  565. time_passed += speed * delta;
  566. Vector2 new_position = Vector2(
  567. amplitude + (amplitude * sin(time_passed * 2.0)),
  568. amplitude + (amplitude * cos(time_passed * 1.5))
  569. );
  570. owner->set_position(new_position);
  571. time_emit += delta;
  572. if (time_emit > 1.0) {
  573. Array args;
  574. args.push_back(Variant(owner));
  575. args.push_back(Variant(new_position));
  576. owner->emit_signal("position_changed", args);
  577. time_emit = 0.0;
  578. }
  579. }
  580. After a second has passed we emit our signal and reset our counter.
  581. Again in the new version of godot-cpp we can add our parameter values
  582. directly to ``emit_signal``.
  583. In NativeScript 1.0 We first build an array of values and then
  584. call ``emit_signal``.
  585. Once compiled we can go into Godot and select our sprite node.
  586. On our ``Node`` tab we find our new signal and link it up by pressing connect.
  587. We've added a script on our main node and implemented our signal like this:
  588. .. code-block:: none
  589. extends Node
  590. func _on_Sprite_position_changed(node, new_pos):
  591. print("The position of " + node.name + " is now " + str(new_pos))
  592. Every second we simply output our position to the console.
  593. NativeScript 1.1 vs NativeScript 1.0
  594. ------------------------------------
  595. So far in our example above there doesn't seem to be a lot of difference
  596. between the old and new syntax. The class is defined slightly differently
  597. and we no longer use the ``owner`` member to call methods on the Godot
  598. side of our object. A lot of the improvements are hidden under the hood.
  599. This example only deals with simple variables and simple methods.
  600. Especially once you start passing references to other objects or when you
  601. start calling methods that require more complex parameters, NativeScript 1.1
  602. does start to show its benefits.
  603. Next steps
  604. ----------
  605. The above is only a simple example, but we hope it shows you the basics.
  606. You can build upon this example to create full-fledged scripts to control
  607. nodes in Godot using C++.
  608. You should be able to edit and recompile the plugin while the Godot editor
  609. remains open; just rerun the project after the library has finished building.