gdextension_cpp_example.rst 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689
  1. .. _doc_godot_cpp_getting_started:
  2. Getting started
  3. ===============
  4. Workflow overview
  5. -----------------
  6. As a GDExtension, godot-cpp is more complicated to use than :ref:`GDScript <doc_gdscript>` and :ref:`C# <doc_c_sharp>`.
  7. If you decide to work with it, here's what to expect your workflow to look like:
  8. * Create a new godot-cpp project (from the `template <https://github.com/godotengine/godot-cpp-template>`__, or from scratch, as explained below).
  9. * Develop your code with your :ref:`favorite IDE <toc-devel-configuring_an_ide>` locally.
  10. * Build and test your code with the earliest compatible Godot version.
  11. * Create builds for all platforms you want to support (e.g. using `GitHub Actions <https://github.com/godotengine/godot-cpp-template/blob/main/.github/workflows/builds.yml>`__).
  12. * Optional: Publish on the `Godot Asset Library <https://godotengine.org/asset-library/asset>`__.
  13. Example project
  14. ---------------
  15. For your first godot-cpp project, we recommend starting with this guide to understand the technology involved with
  16. godot-cpp. After you're done, you can use the `godot-cpp template <https://github.com/godotengine/godot-cpp-template>`__,
  17. which has better coverage of features, such as a GitHub action pipeline and useful ``SConstruct`` boilerplate code.
  18. However, the template does not explain itself to a high level of detail, which is why we recommend going through this
  19. guide first.
  20. Setting up the project
  21. ----------------------
  22. There are a few prerequisites you'll need:
  23. - A Godot 4 executable.
  24. - A C++ compiler.
  25. - SCons as a build tool.
  26. - A copy of the `godot-cpp repository <https://github.com/godotengine/godot-cpp>`__.
  27. See also :ref:`Configuring an IDE <toc-devel-configuring_an_ide>`
  28. and :ref:`Compiling <toc-devel-compiling>` as the build tools are identical
  29. to the ones you need to compile Godot from source.
  30. You can download the `godot-cpp repository <https://github.com/godotengine/godot-cpp>`__ from GitHub or let Git do the work for you.
  31. Note that this repository has different branches for different versions
  32. 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.
  33. .. note::
  34. To use `GDExtension <https://godotengine.org/article/introducing-gd-extensions>`__
  35. you need to use the godot-cpp branch that matches the version of Godot that you are
  36. targeting. For example, if you're targeting Godot 4.1, use the ``4.1`` branch. Throughout
  37. this tutorial we use ``4.x``, which will need to be replaced with the version of Godot you
  38. are targeting.
  39. The ``master`` branch is the development branch which is updated regularly
  40. to work with Godot's ``master`` branch.
  41. .. warning::
  42. GDExtensions targeting an earlier version of Godot should work in later
  43. minor versions, but not vice-versa. For example, a GDExtension targeting Godot 4.2
  44. should work just fine in Godot 4.3, but one targeting Godot 4.3 won't work in Godot 4.2.
  45. There is one exception to this: extensions targeting Godot 4.0 will **not** work with
  46. Godot 4.1 and later (see :ref:`updating_your_gdextension_for_godot_4_1`).
  47. If you are versioning your project using Git, it is recommended to add it as
  48. a Git submodule:
  49. .. code-block:: none
  50. mkdir gdextension_cpp_example
  51. cd gdextension_cpp_example
  52. git init
  53. git submodule add -b 4.x https://github.com/godotengine/godot-cpp
  54. cd godot-cpp
  55. git submodule update --init
  56. Alternatively, you can also clone it to the project folder:
  57. .. code-block:: none
  58. mkdir gdextension_cpp_example
  59. cd gdextension_cpp_example
  60. git clone -b 4.x https://github.com/godotengine/godot-cpp
  61. .. note::
  62. If you decide to download the repository or clone it into your folder,
  63. make sure to keep the folder layout the same as we've setup here. Much of
  64. the code we'll be showcasing here assumes the project has this layout.
  65. If you cloned the example from the link specified in the introduction, the
  66. submodules are not automatically initialized. You will need to execute the
  67. following commands:
  68. .. code-block:: none
  69. cd gdextension_cpp_example
  70. git submodule update --init
  71. This will initialize the repository in your project folder.
  72. Creating a simple plugin
  73. ------------------------
  74. Now it's time to build an actual plugin. We'll start by creating an empty Godot
  75. project in which we'll place a few files.
  76. Open Godot and create a new project. For this example, we will place it in a
  77. folder called ``demo`` inside our GDExtension's folder structure.
  78. In our demo project, we'll create a scene containing a Node called "Main" and
  79. we'll save it as ``main.tscn``. We'll come back to that later.
  80. Back in the top-level GDExtension module folder, we're also going to create a
  81. subfolder called ``src`` in which we'll place our source files.
  82. You should now have ``demo``, ``godot-cpp``, and ``src``
  83. directories in your GDExtension module.
  84. Your folder structure should now look like this:
  85. .. code-block:: none
  86. gdextension_cpp_example/
  87. |
  88. +--demo/ # game example/demo to test the extension
  89. |
  90. +--godot-cpp/ # C++ bindings
  91. |
  92. +--src/ # source code of the extension we are building
  93. In the ``src`` folder, we'll start with creating our header file for the
  94. GDExtension node we'll be creating. We will name it ``gdexample.h``:
  95. .. code-block:: cpp
  96. :caption: gdextension_cpp_example/src/gdexample.h
  97. #pragma once
  98. #include <godot_cpp/classes/sprite2d.hpp>
  99. namespace godot {
  100. class GDExample : public Sprite2D {
  101. GDCLASS(GDExample, Sprite2D)
  102. private:
  103. double time_passed;
  104. protected:
  105. static void _bind_methods();
  106. public:
  107. GDExample();
  108. ~GDExample();
  109. void _process(double delta) override;
  110. };
  111. } // namespace godot
  112. There are a few things of note to the above. We include ``sprite2d.hpp`` which
  113. contains bindings to the Sprite2D class. We'll be extending this class in our
  114. module.
  115. We're using the namespace ``godot``, since everything in GDExtension is defined
  116. within this namespace.
  117. Then we have our class definition, which inherits from our Sprite2D through a
  118. container class. We'll see a few side effects of this later on. The
  119. ``GDCLASS`` macro sets up a few internal things for us.
  120. After that, we declare a single member variable called ``time_passed``.
  121. In the next block we're defining our methods, we have our constructor
  122. and destructor defined, but there are two other functions that will likely look
  123. familiar to some, and one new method.
  124. The first is ``_bind_methods``, which is a static function that Godot will
  125. call to find out which methods can be called and which properties it exposes.
  126. The second is our ``_process`` function, which will work exactly the same
  127. as the ``_process`` function you're used to in GDScript.
  128. Let's implement our functions by creating our ``gdexample.cpp`` file:
  129. .. code-block:: cpp
  130. :caption: gdextension_cpp_example/src/gdexample.cpp
  131. #include "gdexample.h"
  132. #include <godot_cpp/core/class_db.hpp>
  133. using namespace godot;
  134. void GDExample::_bind_methods() {
  135. }
  136. GDExample::GDExample() {
  137. // Initialize any variables here.
  138. time_passed = 0.0;
  139. }
  140. GDExample::~GDExample() {
  141. // Add your cleanup here.
  142. }
  143. void GDExample::_process(double delta) {
  144. time_passed += delta;
  145. Vector2 new_position = Vector2(10.0 + (10.0 * sin(time_passed * 2.0)), 10.0 + (10.0 * cos(time_passed * 1.5)));
  146. set_position(new_position);
  147. }
  148. This one should be straightforward. We're implementing each method of our class
  149. that we defined in our header file.
  150. Note our ``_process`` function, which keeps track of how much time has passed
  151. and calculates a new position for our sprite using a sine and cosine function.
  152. There is one more C++ file we need; we'll name it ``register_types.cpp``. Our
  153. GDExtension plugin can contain multiple classes, each with their own header
  154. and source file like we've implemented ``GDExample`` up above. What we need now
  155. is a small bit of code that tells Godot about all the classes in our
  156. GDExtension plugin.
  157. .. code-block:: cpp
  158. :caption: gdextension_cpp_example/src/register_types.cpp
  159. #include "register_types.h"
  160. #include "gdexample.h"
  161. #include <gdextension_interface.h>
  162. #include <godot_cpp/core/defs.hpp>
  163. #include <godot_cpp/godot.hpp>
  164. using namespace godot;
  165. void initialize_example_module(ModuleInitializationLevel p_level) {
  166. if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
  167. return;
  168. }
  169. GDREGISTER_RUNTIME_CLASS(GDExample);
  170. }
  171. void uninitialize_example_module(ModuleInitializationLevel p_level) {
  172. if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
  173. return;
  174. }
  175. }
  176. extern "C" {
  177. // Initialization.
  178. GDExtensionBool GDE_EXPORT example_library_init(GDExtensionInterfaceGetProcAddress p_get_proc_address, const GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) {
  179. godot::GDExtensionBinding::InitObject init_obj(p_get_proc_address, p_library, r_initialization);
  180. init_obj.register_initializer(initialize_example_module);
  181. init_obj.register_terminator(uninitialize_example_module);
  182. init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SCENE);
  183. return init_obj.init();
  184. }
  185. }
  186. The ``initialize_example_module`` and ``uninitialize_example_module`` functions get
  187. called respectively when Godot loads our plugin and when it unloads it. All
  188. we're doing here is parse through the functions in our bindings module to
  189. initialize them, but you might have to set up more things depending on your
  190. needs. We call the ``GDREGISTER_RUNTIME_CLASS`` macro for each of our classes
  191. in our library. This will make them run only in game, like the default for GDScript.
  192. The important function is the third function called ``example_library_init``.
  193. We first call a function in our bindings library that creates an initialization object.
  194. This object registers the initialization and termination functions of the GDExtension.
  195. Furthermore, it sets the level of initialization (core, servers, scene, editor, level).
  196. At last, we need the header file for the ``register_types.cpp`` named
  197. ``register_types.h``.
  198. .. code-block:: cpp
  199. :caption: gdextension_cpp_example/src/register_types.h
  200. #pragma once
  201. #include <godot_cpp/core/class_db.hpp>
  202. using namespace godot;
  203. void initialize_example_module(ModuleInitializationLevel p_level);
  204. void uninitialize_example_module(ModuleInitializationLevel p_level);
  205. Compiling the plugin
  206. --------------------
  207. To compile the project we need to define how SCons using should compile it
  208. using an ``SConstruct`` file which references the one in ``godot-cpp``.
  209. Writing it from scratch is outside the scope of this tutorial, but you can
  210. :download:`the SConstruct file we prepared <files/cpp_example/SConstruct>`.
  211. We'll cover a more customizable, detailed example on how to use these
  212. build files in a subsequent tutorial.
  213. .. note::
  214. This ``SConstruct`` file was written to be used with the latest ``godot-cpp``
  215. master, you may need to make small changes using it with older versions or
  216. refer to the ``SConstruct`` file in the Godot 4.x documentation.
  217. Once you've downloaded the ``SConstruct`` file, place it in your GDExtension folder
  218. structure alongside ``godot-cpp``, ``src`` and ``demo``, then run:
  219. .. code-block:: bash
  220. scons platform=<platform>
  221. You should now be able to find the module in ``demo/bin/<platform>``.
  222. When building for iOS, package the module as a static `.xcframework`, you can use
  223. following commands to do so:
  224. ::
  225. # compile simulator and device modules
  226. scons arch=universal ios_simulator=yes platform=ios target=<target>
  227. scons arch=arm64 ios_simulator=no platform=ios target=<target>
  228. # assemble xcframeworks
  229. xcodebuild -create-xcframework -library demo/bin/libgdexample.ios.<target>.a -library demo/bin/libgdexample.ios.<target>.simulator.a -output demo/bin/libgdexample.ios.<target>.xcframework
  230. xcodebuild -create-xcframework -library godot-cpp/bin/libgodot-cpp.ios.<target>.arm64.a -library godot-cpp/bin/libgodot-cpp.ios.<target>.universal.simulator.a -output demo/bin/libgodot-cpp.ios.<target>.xcframework
  231. .. note::
  232. Here, we've compiled both godot-cpp and our gdexample library as debug
  233. builds. For optimized builds, you should compile them using the
  234. ``target=template_release`` switch.
  235. Using the GDExtension module
  236. ----------------------------
  237. Before we jump back into Godot, we need to create one more file in
  238. ``demo/bin/``.
  239. This file lets Godot know what dynamic libraries should be
  240. loaded for each platform and the entry function for the module. It is called ``gdexample.gdextension``.
  241. .. code-block:: none
  242. [configuration]
  243. entry_symbol = "example_library_init"
  244. compatibility_minimum = "4.1"
  245. reloadable = true
  246. [libraries]
  247. macos.debug = "res://bin/libgdexample.macos.template_debug.framework"
  248. macos.release = "res://bin/libgdexample.macos.template_release.framework"
  249. ios.debug = "res://bin/libgdexample.ios.template_debug.xcframework"
  250. ios.release = "res://bin/libgdexample.ios.template_release.xcframework"
  251. windows.debug.x86_32 = "res://bin/libgdexample.windows.template_debug.x86_32.dll"
  252. windows.release.x86_32 = "res://bin/libgdexample.windows.template_release.x86_32.dll"
  253. windows.debug.x86_64 = "res://bin/libgdexample.windows.template_debug.x86_64.dll"
  254. windows.release.x86_64 = "res://bin/libgdexample.windows.template_release.x86_64.dll"
  255. linux.debug.x86_64 = "res://bin/libgdexample.linux.template_debug.x86_64.so"
  256. linux.release.x86_64 = "res://bin/libgdexample.linux.template_release.x86_64.so"
  257. linux.debug.arm64 = "res://bin/libgdexample.linux.template_debug.arm64.so"
  258. linux.release.arm64 = "res://bin/libgdexample.linux.template_release.arm64.so"
  259. linux.debug.rv64 = "res://bin/libgdexample.linux.template_debug.rv64.so"
  260. linux.release.rv64 = "res://bin/libgdexample.linux.template_release.rv64.so"
  261. android.debug.x86_64 = "res://bin/libgdexample.android.template_debug.x86_64.so"
  262. android.release.x86_64 = "res://bin/libgdexample.android.template_release.x86_64.so"
  263. android.debug.arm64 = "res://bin/libgdexample.android.template_debug.arm64.so"
  264. android.release.arm64 = "res://bin/libgdexample.android.template_release.arm64.so"
  265. [dependencies]
  266. ios.debug = {
  267. "res://bin/libgodot-cpp.ios.template_debug.xcframework": ""
  268. }
  269. ios.release = {
  270. "res://bin/libgodot-cpp.ios.template_release.xcframework": ""
  271. }
  272. This file contains a ``configuration`` section that controls the entry function of the module.
  273. You should also set the minimum compatible Godot version with ``compatibility_minimum``,
  274. which prevents older version of Godot from trying to load your extension.
  275. The ``reloadable`` flag enables automatic reloading of your extension by the editor every time you recompile it,
  276. without needing to restart the editor. This only works if you compile your extension in debug mode (default).
  277. The ``libraries`` section is the important bit: it tells Godot the location of the
  278. dynamic library in the project's filesystem for each supported platform. It will
  279. also result in *just* that file being exported when you export the project,
  280. which means the data pack won't contain libraries that are incompatible with the
  281. target platform.
  282. Finally, the ``dependencies`` section allows you to name additional dynamic
  283. libraries that should be included as well. This is important when your GDExtension
  284. plugin implements someone else's library and requires you to supply a
  285. third-party dynamic library with your project.
  286. Here is another overview to check the correct file structure:
  287. .. code-block:: none
  288. gdextension_cpp_example/
  289. |
  290. +--demo/ # game example/demo to test the extension
  291. | |
  292. | +--main.tscn
  293. | |
  294. | +--bin/
  295. | |
  296. | +--gdexample.gdextension
  297. |
  298. +--godot-cpp/ # C++ bindings
  299. |
  300. +--src/ # source code of the extension we are building
  301. | |
  302. | +--register_types.cpp
  303. | +--register_types.h
  304. | +--gdexample.cpp
  305. | +--gdexample.h
  306. Time to jump back into Godot. We load up the main scene we created way back in
  307. the beginning and now add a newly available GDExample node to the scene:
  308. .. image:: img/gdextension_cpp_nodes.webp
  309. We're going to assign the Godot logo to this node as our texture, disable the
  310. ``centered`` property:
  311. .. image:: img/gdextension_cpp_sprite.webp
  312. We're finally ready to run the project:
  313. .. video:: img/gdextension_cpp_animated.webm
  314. :alt: Screen recording of a game window, with Godot logo moving in the top-left corner
  315. :autoplay:
  316. :loop:
  317. :muted:
  318. :align: default
  319. Adding properties
  320. -----------------
  321. GDScript allows you to add properties to your script using the ``export``
  322. keyword. In GDExtension you have to register the properties with a getter and
  323. setter function or directly implement the ``_get_property_list``, ``_get`` and
  324. ``_set`` methods of an object (but that goes far beyond the scope of this
  325. tutorial).
  326. Lets add a property that allows us to control the amplitude of our wave.
  327. In our ``gdexample.h`` file we need to add a member variable and getter and setter
  328. functions:
  329. .. code-block:: cpp
  330. ...
  331. private:
  332. double time_passed;
  333. double amplitude;
  334. public:
  335. void set_amplitude(const double p_amplitude);
  336. double get_amplitude() const;
  337. ...
  338. In our ``gdexample.cpp`` file we need to make a number of changes, we will only
  339. show the methods we end up changing, don't remove the lines we're omitting:
  340. .. code-block:: cpp
  341. void GDExample::_bind_methods() {
  342. ClassDB::bind_method(D_METHOD("get_amplitude"), &GDExample::get_amplitude);
  343. ClassDB::bind_method(D_METHOD("set_amplitude", "p_amplitude"), &GDExample::set_amplitude);
  344. ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "amplitude"), "set_amplitude", "get_amplitude");
  345. }
  346. GDExample::GDExample() {
  347. // Initialize any variables here.
  348. time_passed = 0.0;
  349. amplitude = 10.0;
  350. }
  351. void GDExample::_process(double delta) {
  352. time_passed += delta;
  353. Vector2 new_position = Vector2(
  354. amplitude + (amplitude * sin(time_passed * 2.0)),
  355. amplitude + (amplitude * cos(time_passed * 1.5))
  356. );
  357. set_position(new_position);
  358. }
  359. void GDExample::set_amplitude(const double p_amplitude) {
  360. amplitude = p_amplitude;
  361. }
  362. double GDExample::get_amplitude() const {
  363. return amplitude;
  364. }
  365. Once you compile the module with these changes in place, you will see that a
  366. property has been added to our interface. You can now change this property and
  367. when you run your project, you will see that our Godot icon travels along a
  368. larger figure.
  369. Let's do the same but for the speed of our animation and use a setter and getter
  370. function. Our ``gdexample.h`` header file again only needs a few more lines of
  371. code:
  372. .. code-block:: cpp
  373. ...
  374. double amplitude;
  375. double speed;
  376. ...
  377. void _process(double delta) override;
  378. void set_speed(const double p_speed);
  379. double get_speed() const;
  380. ...
  381. This requires a few more changes to our ``gdexample.cpp`` file, again we're only
  382. showing the methods that have changed so don't remove anything we're omitting:
  383. .. code-block:: cpp
  384. void GDExample::_bind_methods() {
  385. ...
  386. ClassDB::bind_method(D_METHOD("get_speed"), &GDExample::get_speed);
  387. ClassDB::bind_method(D_METHOD("set_speed", "p_speed"), &GDExample::set_speed);
  388. ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed", PROPERTY_HINT_RANGE, "0,20,0.01"), "set_speed", "get_speed");
  389. }
  390. GDExample::GDExample() {
  391. time_passed = 0.0;
  392. amplitude = 10.0;
  393. speed = 1.0;
  394. }
  395. void GDExample::_process(double delta) {
  396. time_passed += speed * delta;
  397. Vector2 new_position = Vector2(
  398. amplitude + (amplitude * sin(time_passed * 2.0)),
  399. amplitude + (amplitude * cos(time_passed * 1.5))
  400. );
  401. set_position(new_position);
  402. }
  403. ...
  404. void GDExample::set_speed(const double p_speed) {
  405. speed = p_speed;
  406. }
  407. double GDExample::get_speed() const {
  408. return speed;
  409. }
  410. Now when the project is compiled, we'll see another property called speed.
  411. Changing its value will make the animation go faster or slower.
  412. Furthermore, we added a property range which describes in which range the value can be.
  413. The first two arguments are the minimum and maximum value and the third is the step size.
  414. .. note::
  415. For simplicity, we've only used the hint_range of the property method.
  416. There are a lot more options to choose from. These can be used to
  417. further configure how properties are displayed and set on the Godot side.
  418. Signals
  419. -------
  420. Last but not least, signals fully work in GDExtension as well. Having your extension
  421. react to a signal given out by another object requires you to call ``connect``
  422. on that object. We can't think of a good example for our wobbling Godot icon, we
  423. would need to showcase a far more complete example.
  424. This is the required syntax:
  425. .. code-block:: cpp
  426. some_other_node->connect("the_signal", Callable(this, "my_method"));
  427. To connect our signal ``the_signal`` from some other node with our method
  428. ``my_method``, we need to provide the ``connect`` method with the name of the signal
  429. and a ``Callable``. The ``Callable`` holds information about an object on which a method
  430. can be called. In our case, it associates our current object instance ``this`` with the
  431. method ``my_method`` of the object. Then the ``connect`` method will add this to the
  432. observers of ``the_signal``. Whenever ``the_signal`` is now emitted, Godot knows which
  433. method of which object it needs to call.
  434. Note that you can only call ``my_method`` if you've previously registered it in
  435. your ``_bind_methods`` method. Otherwise Godot will not know about the existence
  436. of ``my_method``.
  437. To learn more about ``Callable``, check out the class reference here: :ref:`Callable <class_Callable>`.
  438. Having your object sending out signals is more common. For our wobbling
  439. Godot icon, we'll do something silly just to show how it works. We're going to
  440. emit a signal every time a second has passed and pass the new location along.
  441. In our ``gdexample.h`` header file, we need to define a new member ``time_emit``:
  442. .. code-block:: cpp
  443. ...
  444. double time_passed;
  445. double time_emit;
  446. double amplitude;
  447. ...
  448. This time, the changes in ``gdexample.cpp`` are more elaborate. First,
  449. you'll need to set ``time_emit = 0.0;`` in either our ``_init`` method or in our
  450. constructor. We'll look at the other 2 needed changes one by one.
  451. In our ``_bind_methods`` method, we need to declare our signal. This is done
  452. as follows:
  453. .. code-block:: cpp
  454. void GDExample::_bind_methods() {
  455. ...
  456. ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed", PROPERTY_HINT_RANGE, "0,20,0.01"), "set_speed", "get_speed");
  457. ADD_SIGNAL(MethodInfo("position_changed", PropertyInfo(Variant::OBJECT, "node"), PropertyInfo(Variant::VECTOR2, "new_pos")));
  458. }
  459. Here, our ``ADD_SIGNAL`` macro can be a single call with a ``MethodInfo`` argument.
  460. ``MethodInfo``'s first parameter will be the signal's name, and its remaining parameters
  461. are ``PropertyInfo`` types which describe the essentials of each of the method's parameters.
  462. ``PropertyInfo`` parameters are defined with the data type of the parameter, and then the name
  463. that the parameter will have by default.
  464. So here, we add a signal, with a ``MethodInfo`` which names the signal "position_changed". The
  465. ``PropertyInfo`` parameters describe two essential arguments, one of type ``Object``, the other
  466. of type ``Vector2``, respectively named "node" and "new_pos".
  467. Next, we'll need to change our ``_process`` method:
  468. .. code-block:: cpp
  469. void GDExample::_process(double delta) {
  470. time_passed += speed * delta;
  471. Vector2 new_position = Vector2(
  472. amplitude + (amplitude * sin(time_passed * 2.0)),
  473. amplitude + (amplitude * cos(time_passed * 1.5))
  474. );
  475. set_position(new_position);
  476. time_emit += delta;
  477. if (time_emit > 1.0) {
  478. emit_signal("position_changed", this, new_position);
  479. time_emit = 0.0;
  480. }
  481. }
  482. After a second has passed, we emit our signal and reset our counter. We can add
  483. our parameter values directly to ``emit_signal``.
  484. Once the GDExtension library is compiled, we can go into Godot and select our sprite
  485. node. In the **Node** dock, we can find our new signal and link it up by pressing
  486. the **Connect** button or double-clicking the signal. We've added a script on
  487. our main node and implemented our signal like this:
  488. .. code-block:: gdscript
  489. extends Node
  490. func _on_Sprite2D_position_changed(node, new_pos):
  491. print("The position of " + node.get_class() + " is now " + str(new_pos))
  492. Every second, we output our position to the console.
  493. Next steps
  494. ----------
  495. We hope the above example showed you the basics. You can build upon this example to create full-fledged scripts
  496. to control nodes in Godot using C++!
  497. Instead of basing your project off the above example setup, we recommend to restart now by cloning the
  498. `godot-cpp template <https://github.com/godotengine/godot-cpp-template>`__, and base your project off of that.
  499. It has better coverage of features, such as a GitHub build action and additional useful ``SConstruct`` boilerplate.