123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- Custom modules in C++
- =====================
- Modules
- -------
- Godot allows extending the engine in a modular way. New modules can be
- created and then enabled/disabled. This allows for adding new engine
- functionality at every level without modifying the core, which can be
- split for use and reuse in different modules.
- Modules are located in them modules/ subdirectory of the build system.
- By default, two modules exist, GDScript (which, yes it's not part of the
- core engine), and the GridMap. As many new modules as desired can be
- created and combined, and the SCons build system will take care of it
- transparently.
- What for?
- ---------
- While it's recommended that most of a game is written in scripting (as
- it is an enormous time saver), it's perfectly possible to use C++
- instead. Adding C++ modules can be useful in the following scenarios:
- - Binding an external library to Godot (like Bullet, Physx, FMOD, etc).
- - Optimize critical parts of a game.
- - Adding new functionality to the engine and/or editor.
- - Porting an existing game.
- - Write a whole, new game in C++ because you can't live without C++.
- Creating a new module
- ---------------------
- Before creating a module, make sure to download the source code of Godot
- and manage to compile it. There are tutorials in the wiki for this.
- To create a new module, the first step is creating a directory inside
- modules. If you want to maintain the module separately, you can checkout
- a different VCS into modules and use it.
- The example module will be called \\"sumator\\", and is placed inside
- the Godot source tree (C:\\\\godot refers to wherever the Godot sources
- are located):
- ::
- c:\\godot> cd modules
- c:\\godot\\modules> mkdir sumator
- c:\\godot\\modules> cd sumator
- c:\\godot\\modules\\sumator>
- Inside we will create a simple sumator class:
- | <pre class=\\"cpp\\">
- | /\* sumator.h \*/
- | #ifndef SUMATOR\_H
- | #define SUMATOR\_H
- #include "reference.h"
- | class Sumator : public Reference {
- | OBJ\_TYPE(Sumator,Reference);
- int count;
- | protected:
- | static void \_bind\_methods();
- | public:
- | void add(int value);
- | void reset();
- | int get\_total() const;
- | Sumator();
- | };
- #endif
- .. raw:: html
- </pre>
- And then the cpp file.
- | <pre class=\\"cpp\\">
- | /\* sumator.cpp \*/
- #include "sumator.h"
- void Sumator::add(int value) {
- | count+=value;
- | }
- void Sumator::reset() {
- | count=0;
- | }
- int Sumator::get\_total() const {
- | return count;
- | }
- void Sumator::\_bind\_methods() {
- | ObjectTypeDB::bind\_method("add",&Sumator::add);
- | ObjectTypeDB::bind\_method("reset",&Sumator::reset);
- | ObjectTypeDB::bind\_method("get\_total",&Sumator::get\_total);
- | }
- | Sumator::Sumator() {
- | count=0;
- | }
- .. raw:: html
- </pre>
- Then, the new class needs to be registered somehow, so two more files
- need to be created:
- ::
- register_types.h
- register_types.cpp
- With the following contents
- | <pre class=\\"cpp\\">
- | /\* register\_types.h \*/
- | void register\_sumator\_types();
- | void unregister\_sumator\_types();
- | /\* yes, the word in the middle must be the same as the module folder
- name \*/
- .. raw:: html
- </pre>
- | <pre class=\\"cpp\\">
- | /\* register\_types.cpp \*/
- | #include "register\_types.h"
- | #include "object\_type\_db.h"
- | #include "sumator.h"
- void register\_sumator\_types() {
- | ObjectTypeDB::register\_type<Sumator>();
- | }
- | void unregister\_sumator\_types() {
- | //nothing to do here
- | }
- .. raw:: html
- </pre>
- Next, we need to create a SCsub so the build system compiles this
- module:
- <pre class=\\"python\\">
- #. SCsub
- Import('env')
- env.add\_source\_files(env.modules\_sources,"\*.cpp") # just add
- all cpp files to the build
- .. raw:: html
- </pre>
- And finally, the configuration file for the module, this is a simple
- python script that must be named 'config.py'
- <pre class=\\"python\\">
- #. config.py
- | def can\_build(platform):
- | return True
- | def configure(env):
- | pass
- .. raw:: html
- </pre>
- The module is asked if it's ok to build for the specific platform (in
- this case, True means it will build for every platform).
- The second function allows to customize the build process for the
- module, like adding special compiler flags, options etc. (This can be
- done in SCSub, but configure(env) is called at a previous stage). If
- unsure, just ignore this.
- And that's it. Hope it was not too complex! Your module should look like
- this:
- ::
- godot/modules/sumator/config.py
- godot/modules/sumator/sumator.h
- godot/modules/sumator/sumator.cpp
- godot/modules/sumator/register_types.h
- godot/modules/sumator/register_types.cpp
- godot/modules/sumator/SCsub
- You can then zip it and share the module with everyone else. When
- building for every platform (instructions in the previous section), your
- module will be included.
- Using the module
- ----------------
- Using your newly created module is very easy, from any script you can
- do:
- | <pre class=\\"python\\">
- | var s = Sumator.new()
- | s.add(10)
- | s.add(20)
- | s.add(30)
- | print( s.get\_total() )
- | s.reset()
- .. raw:: html
- </pre>
- And the output will be ``60``.
- Summing up
- ----------
- As you see, it's really easy to develop Godot in C++. Just write your
- stuff normally and remember to:
- - use ``OBJ_TYPE`` macro for inheritance, so Godot can wrap it
- - use ``_bind_methods`` to bind your functions to scripting, and to
- allow them to work as callbacks for signals.
- But this is not all, depending what you do, you will be greeted with
- some surprises.
- - If you inherit from [[API:Node]] (or any derived node type, such as
- Sprite), your new class will appear in the editor, in the inheritance
- tree in the \\"Add Node\\" dialog.
- - If you inherit from [[API:Resource]], it will appear int the resource
- list, and all the exposed properties can be serialized when
- saved/loaded.
- - By this same logic, you can extend the Editor and almost any area of
- the engine.
|