├── FUNDING.yml ├── LICENSE ├── LICENSE.md ├── README.md ├── announcement.md ├── classdb_and_reflection.md ├── gdscript_to_cpp ├── episodes │ ├── episode_1.md │ ├── episode_2.md │ ├── episode_3.md │ ├── episode_4.md │ ├── episode_5.md │ ├── episode_Data_Structures.md │ ├── episode_Functions.md │ ├── episode_Inheritance.md │ ├── episode_Strings_and_Comparisons.md │ ├── episode_Unions_and_Variant.md │ └── img │ │ ├── calculate_integer_size_biggest.png │ │ └── player_cpp.png └── gdscript_to_cpp.md ├── interfaces_in_gdscript.md └── repo_organization.md /FUNDING.yml: -------------------------------------------------------------------------------- 1 | # repo: willnationsdev/godot-source-walkthrough 2 | # filename: FUNDING.yml 3 | 4 | github: willnationsdev -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Will Nations 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deconstructing Godot 2 | 3 | A gradual introduction to Godot Engine's source code for those with some GDScript experience and little to no C++ experience. This repository is a complement to a YouTube series available [here](https://www.youtube.com/playlist?list=PLthxCU-NcfYtKogfNjR-6ds73klIOIbWc). 4 | 5 | If you would like to suggest a topic, please [open an Issue](https://github.com/willnationsdev/deconstructing-godot/issues/new). 6 | 7 | If you are a GDScript user and are uncomfortable with C++, you may want to first [learn C++ using your knowledge of GDScript](gdscript_to_cpp/gdscript_to_cpp.md) (WIP). A supplemental video series on the topic can be found [here]() (TODO). 8 | 9 | If you found the content educational, please consider becoming my sponsor using the button above. I spend dozens of hours preparing the lessons through research, write ups, recording videos, and managing the channel. Regardless, it's all worth it if it helps enlighten viewers to the wonders of Godot! 10 | 11 | ## Topics 12 | 13 | This is a tentative ordered list of topics. As lessons progress, it may become necessary to cover additional content within or between topics in order to properly cover the material. 14 | 15 | 1. [Repository Organization](repo_organization.md) 16 | 1. ClassDB and Reflection 17 | 1. Object 18 | 1. Node and Notifications 19 | 1. Scripting 20 | 1. Variant 21 | 1. Servers and RIDOwner 22 | 1. MainLoop, SceneTree, and Node Again 23 | 1. Main and Entry Points 24 | 1. Loop Iteration 25 | 1. Memory Management (`/u/attrezzarturo` on Reddit) 26 | 1. Signals (`/u/golddotasksquestions` on Reddit) 27 | 1. Viewports (`/u/golddotasksquestions` on Reddit) 28 | 1. Input Handling 29 | 1. PackedScene and TSCN File Format (`/u/attrezzarturo` on Reddit) 30 | 1. Editor 31 | 1. EditorPlugins 32 | 1. ScriptEditor (`Cologne?` on YouTube) 33 | 1. Mutex, Semaphore, and Thread (`/u/G-Brain` on Reddit) 34 | 1. GDScript (`Mateusz Kozicki` on YouTube) 35 | 1. GodotSharp (`/u/attrezzarturo` on Reddit) 36 | 1. Modules and Thirdparty Integration (`/u/Awxen` on Reddit) 37 | 1. Finding Issue, Solving, and Submitting PR (`SuperSatanicSaint` on YouTube) 38 | -------------------------------------------------------------------------------- /announcement.md: -------------------------------------------------------------------------------- 1 | Name: Will Nations 2 | Username: willnationsdev 3 | 4 | Goal: Video walkthrough of engine source code 5 | 6 | Reasons: Topics: 7 | - Severely underdocumented. - Repo Org. - Servers - Variant - Main loop 8 | - "Development" docs => veteran developers. - Object - Script - Reflection - Editor 9 | - Also useful for beginners. 10 | - Dev docs + beginner info = distracted docs. 11 | - ^Quality docs -> Time 12 | - Nervous? May not bother. 13 | - Other topics have a plethora of video tutorials: 14 | - How to use Godot. 15 | - How to create tools with Godot. 16 | - How to use git with GitHub. 17 | - How to build Godot Engine source code. 18 | - How to create C++ modules. 19 | 20 | Qualifications: 21 | - 8 years of programming experience, 4/8 in university. 22 | - intermittent use of C++ throughout. 23 | - 80 merged pull requests since May 6, 2017; 3 currently open. 24 | - godotengine/godot: 69 25 | - godotengine/godot-docs: 11 26 | -------------------------------------------------------------------------------- /classdb_and_reflection.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willnationsdev/deconstructing-godot/35dee549c59a89e480d9a5ab895a1e912cb2278f/classdb_and_reflection.md -------------------------------------------------------------------------------- /gdscript_to_cpp/episodes/episode_1.md: -------------------------------------------------------------------------------- 1 | # GDScript to C++ Episode 1: Classes and Access Modifiers 2 | 3 | - Course Learning: 4 | - C++ concepts/syntax 5 | - Basic program memory structure 6 | 7 | - Course Requirements: 8 | - GDScript features and syntax 9 | 10 | ## Key Principles: 11 | 12 | 1. C++ thinks *everything* is a *number*. 13 | 1. C++ needs to know *exactly* how those numbers are *arranged and used* ahead of time. 14 | 1. C++ is *dumb*. It trusts you to painstakingly build whatever you want with almost no supervision. 15 | 16 | ## Comments 17 | 18 | C++: 19 | 20 | ```cpp 21 | // Comments use double-slashes 22 | int x; // a comment after a statement 23 | /* This is a 24 | multiline 25 | comment */ 26 | ``` 27 | 28 | GDScript: 29 | 30 | ```gdscript 31 | # Comments use pound 32 | var x # a comment after a statement 33 | """ 34 | No multiline comment syntax. 35 | Use docstrings instead! 36 | """ 37 | ``` 38 | 39 | ## Class Declaration 40 | 41 | Declaration = something exists (any language) 42 | 43 | - GDScript: 44 | - File == class, implicit declaration 45 | 46 | ```gdscript 47 | # some_class.gd (even without this comment) 48 | ``` 49 | 50 | - Must extend an engine `Object` class. 51 | 52 | How To... 53 | 54 | ```gdscript 55 | extends Node # Engine class (basetype). 56 | extends "my_node.gd" # Script file path (path->load->basetype). 57 | extends MyNode # Global script class (name->path->load->basetype). 58 | 59 | extends Array # Error! Array is not an Object! 60 | ``` 61 | 62 | No `extends` == `Reference`. Identical types below. 63 | 64 | ```gdscript 65 | # ref1.gd 66 | 67 | # ref2.gd 68 | extends Reference 69 | ``` 70 | 71 | - C++: 72 | - File != class, explicit declaration 73 | - N top-level classes per file 74 | - Independently inheritable 75 | 76 | Syntax: ` ` 77 | 78 | ```cpp 79 | // some_class.h 80 | class SomeClass { 81 | 82 | }; 83 | class AnotherClass { 84 | 85 | }; 86 | ``` 87 | 88 | > Usually, `{ ... }` OR `;`, not both. Classes are special. [See more](https://stackoverflow.com/questions/1783465/why-must-i-put-a-semicolon-at-the-end-of-class-declaration-in-c/1783509). 89 | 90 | ## Access Modifiers And Basic Inheritance 91 | 92 | All programming languages have access levels. 93 | 94 | "Access Level" == can do `obj.`. 95 | 96 | Types: `public`, `protected`, `private`. 97 | 98 | Convention: non-`public` content has `_` prefix. 99 | 100 | - GDScript: 101 | 102 | - `public`: all content accessible (default) (no keyword, assumed). 103 | 104 | Naming convention communicates intent. 105 | 106 | ```gdscript 107 | # some_class.gd 108 | var _x: int # "private" or "protected", but really public 109 | var z: int # public 110 | ``` 111 | 112 | - C++: 113 | 114 | - `private`: inaccessible (default) 115 | - `protected`: inherited classes only 116 | - `public`: all accessible 117 | 118 | Syntax: ``. Align keyword with class declaration. Affected content indented on newlines. 119 | 120 | ```cpp 121 | // some_class.h 122 | class SomeClass { 123 | private: 124 | int _x; // only accessible in SomeClass 125 | protected: 126 | int _y; // only accessible in SomeClass and its derived classes 127 | public: 128 | int z; // accessible from any class 129 | private: // can re-declare sections for dependencies 130 | int _a = z; 131 | 132 | protected: int b; // BAD, no newline 133 | 134 | int c; // BAD, content not indented 135 | 136 | public: // BAD, modifier not de-dented 137 | }; 138 | ``` 139 | 140 | Classes default to `private` access if you omit an access modifier. 141 | 142 | ```cpp 143 | // some_class.h 144 | class SomeClass { 145 | int _x; // private 146 | }; 147 | ``` 148 | 149 | ## C++ Inheritance With Access Modifiers 150 | 151 | ```cpp 152 | class BaseClass { 153 | public: 154 | int x; 155 | }; 156 | class DerivedClass : public BaseClass { 157 | 158 | }; 159 | ``` 160 | 161 | - C++ `:` == GDScript `extends`. 162 | - inherit typename (not file) 163 | - Inheritance access modifiers: Imposes limits on inheritance of base class. 164 | - `public`: No change to `BaseClass` in `DerivedClass`. 165 | - `protected`: `BaseClass`'s `public` members -> `protected` members. 166 | - `private`: `BaseClass`'s `public` and `protected` members -> `private` members. 167 | - If you omit a modifier, it defaults to `private`. 168 | 169 | ```cpp 170 | class Base { 171 | private: 172 | int _x; 173 | protected: 174 | int _y; 175 | public: 176 | int z; 177 | }; 178 | class Private : private Base {}; // _x/_y/z private 179 | class Protected : protected Base {}; // _x private, _y/z protected 180 | class Public : public Base {}; // same as Base 181 | ``` 182 | 183 | C++ *also* has a `struct` keyword. `struct` == `class`, but default is `public`. 184 | 185 | ```cpp 186 | class BaseClass { 187 | public: 188 | int x; 189 | } 190 | class DerivedClass : public BaseClass { 191 | 192 | } 193 | // equal to: 194 | struct BaseClass { 195 | int x; 196 | }; 197 | struct DerivedClass : BaseClass { 198 | 199 | } 200 | ``` 201 | 202 | > Note: In other languages, `struct` is usually something else. 203 | 204 | ## Multiple Classes Per File 205 | 206 | - GDScript: 207 | 208 | - Always 1 top-level class. 209 | - Supports inner classes ("class constants" via `class` keyword). 210 | 211 | ```gdscript 212 | # some_class.gd 213 | extends Reference 214 | class MyInnerClass: 215 | extends Node 216 | 217 | # usage 218 | const SomeClass = preload("some_class.gd") 219 | var my_class = SomeClass.MyInnerClass.new() 220 | ``` 221 | 222 | - C++: 223 | - Supports inner classes. 224 | 225 | Example: require custom data structures for class 226 | 227 | ```cpp 228 | // `/scene/resources/tile_set.h` 229 | class TileSet : public Resource { 230 | public: 231 | // Belongs to TileSet, but... 232 | // - TileSetEditorPlugin creates them *for* TileSet 233 | // - Passes to TileSet to create internal TileData instances. 234 | // - TileMap accesses them for rendering calculations. 235 | struct ShapeData { 236 | // dimensions, position, etc. 237 | }; 238 | private: 239 | // Managed internally by TileSet. Holds all data for a tile. 240 | struct TileData { 241 | // ShapeData array 242 | }; 243 | }; 244 | ``` 245 | 246 | - Multiple classes? Be careful, ~ "bad practice". Allowances... 247 | 248 | - Use one and not others? No. Interconnected classes. Use one == all. 249 | 250 | ```cpp 251 | // `/core/script_language.h` 252 | class ScriptServer { 253 | // ScriptLanguage array 254 | }; 255 | class Script : public Resource { 256 | // ScriptLanguage instance 257 | // ScriptInstance instance 258 | }; 259 | class ScriptInstance { 260 | // Object instance 261 | // Script instance 262 | }; 263 | class ScriptLanguage { 264 | // Can generate Script template 265 | // Can debug ScriptInstance 266 | }; 267 | ``` 268 | 269 | - Most features in base class with minor changes in derived class. 270 | 271 | ```cpp 272 | // `/scene/gui/popup.h` 273 | class Popup : public Window { 274 | }; 275 | 276 | class PopupPanel : public Popup { 277 | // Has a Panel. 278 | // Overrides only 3 methods 279 | }; 280 | ``` 281 | -------------------------------------------------------------------------------- /gdscript_to_cpp/episodes/episode_2.md: -------------------------------------------------------------------------------- 1 | # GDScript to C++ Episode 2: Memory and Integrals 2 | 3 | Programs write data to memory addresses. 4 | 5 | ```cpp 6 | int x; // arbitrary memory address, e.g. 450130 7 | ``` 8 | 9 | How to reference? 10 | 11 | Map symbol to location via "symbol table". 12 | 13 | Symbol tables record variable locations for later reference. 14 | 15 | In GDScript, this would be like a Dictionary of strings mapped to integers of array indices. 16 | 17 | ```gdscript 18 | var symbols = {} 19 | var values = PoolByteArray() 20 | 21 | # int x = 2; // C++ 22 | symbols['x'] = 450130 23 | values[450130] = 0 24 | values[450131] = 0 25 | values[450132] = 0 26 | values[450133] = 2 27 | ``` 28 | 29 | But, *how* do we write data? 30 | 31 | **Data Type** determines read/write algorithm. 32 | 33 | ## Data Type: Byte Size & Arrangement 34 | 35 | *How many bytes ("byte size")?* 36 | 37 | Get size with `sizeof(type)` operator. 38 | 39 | ```cpp 40 | // `int` is 4 bytes. 41 | sizeof(int) == 4; // true 42 | ``` 43 | 44 | Program views memory as sequentially ordered: 45 | 46 | ```cpp 47 | int x; // 450130-450133 48 | int y; // 450134-450137 (+ 4) 49 | ``` 50 | 51 | Ways to express integer value: 52 | 53 | ```cpp 54 | // decimal 55 | // Syntax: None 56 | // Values: 0-9 57 | // 1 byte: N/A 58 | int x = 1; 59 | 60 | // binary 61 | // Syntax: `b` suffix 62 | // Values: 0-1 63 | // 1 byte: 8 digits 64 | int x = 10110110111100001111111101010101b; 65 | 66 | // octal 67 | // Syntax: `0` prefix 68 | // Values: 0-7 69 | // 1 byte: 4 digits 70 | int x = 00123456701234567; 71 | 72 | // hexadecimal 73 | // Syntax: `0x` prefix 74 | // Values: 0-9, A-F (0-15) 75 | // 1 byte: 2 digits 76 | int x = 0x02468ACE; 77 | ``` 78 | 79 | *How are the bits arranged?* 80 | 81 | ```cpp 82 | // `int` bit arrangement? "Two's Complement" 83 | // 1. Leading bit == sign. 84 | // 2. Remaining bits == value. 85 | int sx = 0; // 0x00000000 86 | int sy = 1; // 0x00000001 87 | int sz = -1; // 0xFFFFFFFF 88 | 89 | // Negated value == flip bits + 1 90 | 91 | // pos -> neg 92 | // -0x00000001 + 1 93 | // 0xFFFFFFFE + 1 94 | // 0xFFFFFFFF 95 | 96 | // neg -> pos 97 | // -0xFFFFFFFF + 1 98 | // 0x00000000 + 1 99 | // 0x00000001 100 | ``` 101 | 102 | ## Data Types: Interpreting Bits 103 | 104 | Data type controls data *interpretation*. 105 | 106 | "casting" == converting type A to type B. 107 | 108 | In GDScript: 109 | 110 | ```gdscript 111 | var x = "1" 112 | x = int(x) # cast value to int 113 | x = str(x) # cast value back to string 114 | x = str(int("1")) # nested casts 115 | ``` 116 | 117 | In C++, same, but the data type controls interpretation of *bits*. 118 | 119 | ```cpp 120 | unsigned int ux = 0; // 0x00000000 121 | unsigned int uy = 1; // 0x00000001 122 | unsigned int uz = -1; // 0xFFFFFFFF, becomes 4294967295 123 | ``` 124 | 125 | > Note: `int` is `signed int` by default. Literals default to `int`. 126 | 127 | ```cpp 128 | // unsigned int <- signed int 129 | unsigned int uz = -1; 130 | ``` 131 | 132 | Static Cast: *compile-time* conversion. The code *won't compile* if incompatible. 133 | 134 | Implicit static cast: 135 | 136 | ```cpp 137 | // unsigned int <- signed int 138 | unsigned int uz = -1; 139 | ``` 140 | 141 | Explicit static cast: 142 | 143 | ```cpp 144 | // unsigned int <- (unsigned int <- signed int) 145 | unsigned int uz = (unsigned int) -1; 146 | ``` 147 | 148 | Notice: 149 | 150 | - GDScript: Calls global function and passes expression as parameter. 151 | - C++: Wrap the *type* in parentheses. Order of operations applies type to expression. 152 | 153 | Wrap in parentheses to nest casts. 154 | 155 | ```cpp 156 | int nested = (int) ((unsigned int) -1); 157 | int nested = (int) 4294967295; 158 | int nested = -1; 159 | ``` 160 | 161 | Other ways to manipulate data type? 162 | 163 | ## Data Types: Byte Size Variation 164 | 165 | Changing byte size... 166 | 167 | ```cpp 168 | char c; // 1-byte signed integer (>= 8 bits) 169 | short s; // 2-byte signed integer (>= 16 bits) 170 | int x; // 4-byte signed integer (~32 bits, >= 16 bits) 171 | long x2; // 4-byte signed integer (>= 32 bits) 172 | long long y; // 8-byte signed integer (>= 64 bits) 173 | ``` 174 | 175 | Exact size depends on compiler implementation. 176 | 177 | > [See more about int sizes per platform](https://stackoverflow.com/a/589685). 178 | > 179 | > [See more about all types' size variance](https://en.cppreference.com/w/cpp/language/types). 180 | 181 | Using sizes in code: always use `sizeof(type)`, never a literal. 182 | 183 | GDScript == only 64-bit signed integers. Why? 184 | 185 | ![Don't need to calculate integer size if you always use the biggest one](img/calculate_integer_size_biggest.png) 186 | 187 | So, how does byte size affect casting? 188 | 189 | ```cpp 190 | // size: small -> big 191 | char c = 1; // 0x01 192 | int x = c; // 0x00000001, zero-filled 193 | 194 | // size: big -> small 195 | int x = 256; // 0x00000100 196 | char c = x; // 0x00, truncated: 0x000001|00 197 | ``` 198 | 199 | How does the byte size reality affect data? Underflow and overflow: 200 | 201 | ```cpp 202 | // Underflow 203 | unsigned int x = 0; // 0x00000000 204 | x = x - 1; // 0xFFFFFFFF 205 | 206 | // Overflow 207 | int y = INT_MAX; // ~ 32k or ~ 2b 208 | y = y + 1; // ~ -32k or ~ -2b 209 | ``` 210 | 211 | ## Typedef 212 | 213 | In GDScript, you can load a "class" into a given name. 214 | 215 | You can then also rename that class by defining another constant with the same value. 216 | 217 | ```gdscript 218 | const MyClass = preload("my_class.gd") 219 | const SameClass = MyClass 220 | ``` 221 | 222 | In C++, you can similarly define an alias for a typename using the `typedef` keyword. 223 | 224 | ```cpp 225 | // Syntax: typedef 226 | class A {}; 227 | typedef A AA; 228 | 229 | A a; 230 | AA aa; // same type as `a` 231 | ``` 232 | 233 | Typedefs are used to define concrete sizes for integral values on various platforms. 234 | 235 | ```cpp 236 | int8_t // signed 237 | int16_t 238 | int32_t 239 | int64_t 240 | uint8_t // unsigned 241 | uint16_t 242 | uint32_t 243 | uint64_t 244 | 245 | size_t // unsigned int on native platform 246 | ``` 247 | 248 | ## Enum 249 | 250 | Enums are finite lists of numeric values. 251 | 252 | In GDScript, an `enum` defines a Dictionary constant with `string:int` keys. 253 | 254 | ```gdscript 255 | enum Suit { 256 | Spades, # int: 0 257 | Clubs, # int: 1 258 | Hearts, # int: 2 259 | Diamonds # int: 3 260 | } 261 | 262 | const SPADES: int = Suit.Spades # works! 263 | var keys: Array = Suit.keys() 264 | var spades_key: string = keys[0] # works! 265 | var size = Suit.size() 266 | ``` 267 | 268 | In C++, `enum` = type declaration for 1+ integral values. 269 | 270 | ```cpp 271 | enum Suit { 272 | Spades, // 0 273 | Clubs, // 1 274 | Hearts, // 2 275 | Diamonds, // 3 276 | SUIT_SIZE // 4, last record used for size 277 | }; // note: quotes and semi-colon 278 | 279 | Suit s = Spades; // same as `s = 0;` 280 | s = 1000; // C++ doesn't block other integral values! 281 | 282 | int size = Suit.size(); // Error! No member `size()` 283 | int size = SUIT_SIZE; // 4 284 | ``` -------------------------------------------------------------------------------- /gdscript_to_cpp/episodes/episode_3.md: -------------------------------------------------------------------------------- 1 | # GDScript to C++ Episode 3: Primitives and Pointers 2 | 3 | "Primitive", i.e. built-in, data types. 4 | 5 | ## Char 6 | 7 | Integral values that represent visual characters. E.g. `0x68 == 'h'` 8 | 9 | How do you know `0x68` should represent `'h'`? It's all an interpretation via "character encodings" (ASCII, UTF-8, etc.). 10 | 11 | Syntax: 12 | 13 | ```cpp 14 | // single quotes, one letter only 15 | char h = 'h'; // 0x68 16 | char zero = '0'; // 0x30 17 | char null = '\0' // 0x00, a.k.a. "null terminator" 18 | ``` 19 | 20 | > See more about how to [configure your compiler's character encoding](https://stackoverflow.com/questions/9739070/char-encoding). 21 | 22 | ## C-Strings 23 | 24 | A sequence of chars that ends with a "null terminator". 25 | 26 | ```cpp 27 | "hello" 28 | 'h', 'e', 'l', 'l', 'o' ('\0') 29 | 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x00 // ASCII codes 30 | 31 | // In this example... 32 | // size = 5 bytes 33 | // capacity = 6 or more bytes 34 | ``` 35 | 36 | > Note: C-strings are *not* objects with methods. They are *primitives* like an int, float, or bool. 37 | > 38 | > GDScript/Python/C#/etc. implicitly convert c-string literals to String objects. "hello" -> String("hello") 39 | 40 | Can also represent numbers, visually, with character encodings. 41 | 42 | ```cpp 43 | // 1000 44 | '1', '0', '0', '0' ('\0') 45 | 0x31, 0x30, 0x30, 0x30, 0x00 46 | 47 | // vs. int 48 | short x = 1000; 49 | 50 | // 0x3130303000, 5 bytes, c-string, text 51 | // 0x03E8, 2 bytes, short, binary 52 | ``` 53 | 54 | This is why binary is smaller than text even before compression algorithms. 55 | 56 | ## Float/Double 57 | 58 | Used for large, small, or partial values. 59 | 60 | Store number with scientific notation. 61 | 62 | ```cpp 63 | // value sign significand exponent 64 | -3.14 == -1 * 314 * 10^-2 65 | ``` 66 | 67 | Actually uses base 2, not base 10. 68 | 69 | Bit Distrubution: 70 | 71 | |Type |Sign|Exponent|Significand|Total 72 | |--------|----|--------|-----------|----| 73 | |`float` | 1|8|23|32| 74 | |`double`| 1|11|52|64| 75 | 76 | > [See more about floating-point precision format.](https://floating-point-gui.de/formats/fp/) Too complex for detailing here. 77 | 78 | Note the *massive* range difference compared to integers: 79 | 80 | |Type |Bits|Range| 81 | |----------|----|-----| 82 | |`int32_t` | 32|3.3\*10^-4 - 3.3\*10^4 (32,700) 83 | |`float` | 32|1.2\*10^-38 - 3.4\*10^38 (a lot) 84 | |`int64_t` | 64|2.1\*10^-9 - 2.1\*10^9 (2 billion) 85 | |`double` | 64|2.2\*10^-308 - 1.8\*10^308 (a lot, a lot) 86 | 87 | Exponent flags for special numberline values: 88 | 89 | > Exponent: 0x00... == +0 or -0 90 | > 91 | > Exponent: 0xFF... == +INF, -INF, NaN 92 | 93 | The cost? Loss of bit precision. 94 | 95 | Can directly compare integers reliably. 96 | `1 + 2 = 3 == 3` 97 | 98 | Float/Double are inherently imprecise. 99 | `1.0 + 2.0 = 3.00000000000000004 != 3.0` 100 | 101 | Arithmetic -> truncation/overflow/underflow. [Compare 2 values against a threshold value (the "epsilon")](https://godotengine.org/qa/16522/problem-comparing-floats), e.g. `abs(x)-abs(y) < 0.0001` 102 | 103 | ## References 104 | 105 | References are a compile-time search-and-replace mechanism. 106 | 107 | Use `&` on a data type to declare it. 108 | 109 | ```cpp 110 | // address value 111 | 2; // ------, 0x00000002: literal 112 | int a = 2; // 450130, 0x00000002: init literal 113 | int b = a; // 450134, 0x00000002: copy value 114 | int &c = a; // ------, ----------: a compile-time reference 115 | int d = c; // 450138, 0x00000002: copy value @ `a` 116 | ``` 117 | 118 | The value *must* exist ahead of time. A reference-typed symbol must know how to replace itself with some *concrete addressable value*. 119 | 120 | ```cpp 121 | int &x = 100; // Error! 100 is not an addressable expression. 122 | int &y; // Error! Declaration does not reference anything. 123 | ``` 124 | 125 | References cannot be mutated themselves. 126 | 127 | ```cpp 128 | int a = 2; 129 | int b = 5; 130 | int &c = a; // Define `c` referencing `a`. 131 | 132 | // Set `a` to value of `b`: 5 133 | // Does NOT mutate `c` to reference `b` instead. 134 | c = b; 135 | ``` 136 | 137 | Similar to an OS "hard link". Two files linked to same data. 138 | 139 | No equivalent in GDScript. 140 | 141 | > "pass by value" and "pass by reference" = different, but related, concept. 142 | 143 | ## Pointers 144 | 145 | Pointer = integral values storing a memory address to a specific data type. 146 | 147 | Pointers are *technically* `uint32_t` or `uint64_y` depending on the architecture. 148 | 149 | ### **Pointer Syntax** 150 | 151 | ```cpp 152 | int x = 2; // 450130, value = 2 153 | int *y = &x; // 450134, value = 450130 154 | ``` 155 | 156 | `*` = pointer (incomplete type). 157 | 158 | `int*` = pointer to an int (complete type). 159 | 160 | `&` on *expression* (`&(expr)`), not *declaration* (`type&`) = `address_of` operator. 161 | 162 | Cannot cast between *primitive* pointer types. 163 | 164 | ```cpp 165 | int x = 2; 166 | float *y = &x; // Error! Cannot convert `int*` to `float*` 167 | int *xp = &x; // Works! 168 | float *fp = xp; // Error! Cannot convert `int*` to `float*` 169 | ``` 170 | 171 | > There *are* ways to manually copy memory from one data type to another, but this results in [undefined behavior](https://stackoverflow.com/questions/14730896/where-does-the-c-standard-describe-the-casting-of-pointers-to-primitives), so don't do it. 172 | 173 | Can nest pointers: 174 | 175 | ```cpp 176 | int x = 2; 177 | int *y = &x; // can only point to an `int` 178 | int **z = &y; // can only point to an `int*` 179 | ``` 180 | 181 | Placement of asterisk is driven by convention. 182 | 183 | ```cpp 184 | int *y = &x; 185 | int* y = &x; // ~equivalent 186 | ``` 187 | 188 | Multi-variable declarations in C++ exist. 189 | 190 | ```cpp 191 | int x, y, z; // declare 3 uninitialized variables 192 | ``` 193 | 194 | Placement of asterisk affects data type in multi-variable declarations. 195 | 196 | ```cpp 197 | int* x, y; // x = int*, y = int 198 | int *x, *y; // x = int*, y = int* 199 | int* x,* y; // same, but poor syntax 200 | ``` 201 | 202 | ### **Pointer vs. Reference** 203 | 204 | Unlike references, they are variables with memory and a distinct value. Therefore you can... 205 | 206 | ```cpp 207 | int x; 208 | int a; 209 | int *z; // Declare with no initialization 210 | z = &x; // Initialize later 211 | z = &a; // Mutate value (change what it points to) 212 | ``` 213 | 214 | Access value: 215 | 216 | Reference = use directly. 217 | 218 | Pointer = *dereference* pointer with `*` operator applied to expression. 219 | 220 | ```cpp 221 | int x = 2; // 450130, value = 2 222 | int &y = x; // ------, --------- 223 | int z = y; // 450134, value = 2, value copied from `x` 224 | int *a = &x; // 450138, value = 450130 225 | int b = *a; // 450146, value = 2, load from 450130 (no idea what `x` is) 226 | ``` 227 | 228 | ### **Pointer Arithmetic** 229 | 230 | Pointers are *integral* values, so you can perform arithmetic with them. 231 | 232 | ```cpp 233 | char *s = "hello"; 234 | char h = *(s+sizeof(char)*0); 235 | char e = *(s+sizeof(char)*1); 236 | char l = *(s+sizeof(char)*2); 237 | char l = *(s+sizeof(char)*3); 238 | char o = *(s+sizeof(char)*4); 239 | ``` 240 | 241 | Pointers have a keyword expression for the 0 address: 242 | 243 | ```cpp 244 | int *x = nullptr; // value = 0x0000000000000000 (64-bit) 245 | int *y = 0; // signed int implicit cast to int*, zero-filled. 246 | ``` 247 | 248 | > Equivalent to GDScript's `null`. 249 | 250 | Because pointer values are mutable via arithmetic/assignment, they are potentially unsafe (can access incorrect memory, get runtime exception). Therefore... 251 | 252 | Reference values are **always safe**. 253 | 254 | Pointer values are **always potentially unsafe**. 255 | 256 | - pointer is mutated to be null. 257 | 258 | ```cpp 259 | int *xp = nullptr; 260 | ``` 261 | 262 | - pointer is mutated to point to other non-null, but invalid location. 263 | 264 | ```cpp 265 | int *xp = 2; 266 | ``` 267 | 268 | - the memory pointed to has been freed (learn about this later). 269 | 270 | ```cpp 271 | int *xp; 272 | { 273 | int x = 2; 274 | xp = &x; 275 | } 276 | int y = *xp; // `x` has been unloaded 277 | ``` 278 | 279 | Dereferencing a pointer in any of these scenarios creates a runtime exception that crashes the program. 280 | 281 | ### **Pointer Operators: `.` / `->` / `*`** 282 | 283 | Different usage with classes. 284 | 285 | ```cpp 286 | // Define class 287 | struct SomeClass { 288 | int x = 2; 289 | }; 290 | 291 | // Create local instance of class called `sc`. 292 | SomeClass sc; 293 | 294 | // `.` operator to get property/method of instance. 295 | int y = sc.x; // value = 2 296 | 297 | SomeClass *ptr = ≻ 298 | 299 | // Order of operations! *(expr) and &(expr) have low priority! 300 | int c = *ptr.x // Error! Cannot apply `.` to pointer. Use `->` instead. 301 | int c = *ptr->x // Error! Cannot apply `*` to non-pointer type (int). 302 | int c = (*ptr).x // Works! 303 | int c = ptr->x; // Same! 304 | 305 | // How does the compiler know the stored address is legit? Could be `nullptr`. 306 | SomeClass &sc_ref = ptr; // Error! Can't convert SomeClass* to SomeClass&. 307 | SomeClass &sc_ref = *ptr; // Safe! 308 | SomeClass* &scp_ref = ptr; // Safe! But for pointer. 309 | 310 | // Dereferencing `nullptr` is bad! 311 | ptr = nullptr; 312 | int d = *ptr; // Error! Segmentation fault. Cannot access. 313 | int d = (*ptr).x; // Error! Segmentation fault. Cannot access. 314 | int d = ptr->x; // Error! Segmentation fault. Cannot access. 315 | int d = sc_ref.x // 100% safe 316 | ``` 317 | 318 | ### Bool 319 | 320 | In GDScript, many non-zero things will implicitly cast to a `false` bool, including... 321 | 322 | - An empty Data Structure: 323 | - `[]` 324 | - `{}` 325 | - `PoolByteArray()` 326 | - A zero-filled numeric structure... 327 | - `Vector2()` 328 | - `Vector3()` 329 | - `Color(0)` 330 | - `Color()` is actually `Color(0, 0, 0, 1)`, so `true`. 331 | - An empty string: `""` 332 | 333 | These are called `falsy` values. Not truly `false`, but conceptually "empty" in practice. Common in dynamically-typed languages (JS, PHP, GDScript). 334 | 335 | ```gdscript 336 | # Implicitly casts to bool with `false` value 337 | var arr = [] 338 | if not arr: 339 | print("arr is empty") 340 | ``` 341 | 342 | However, their type information is retained if compared to other types. 343 | 344 | ```gdscript 345 | var arr = [] 346 | var dict = {} 347 | 348 | if not arr and arr == dict: 349 | # This does NOT work. 350 | # An empty Array is not equal to an empty Dictionary 351 | print("Both are empty") 352 | 353 | if not arr and bool(arr) == bool(dict): 354 | # This DOES work 355 | # The boolean representations of these two are equal 356 | print("Both are empty") 357 | ``` 358 | 359 | In C++, `false` is `0x00`, i.e. all zero bits. `true` is any non-zero number, including negatives. 360 | 361 | And in C++, *everything* is a number, so each data type has its own `0` value. 362 | 363 | |Type|Value| 364 | |----|-----| 365 | |`bool`|`false` 366 | |`int`|`0` 367 | |`char`|`'\0'` 368 | |`float`/`double`|`0.0` 369 | |`pointer (*)`|`nullptr` or `NULL` before C++11 370 | |`reference (&)`| N/A 371 | 372 | C++ Classes, by default, have little-to-no integration with primitives. 373 | 374 | ```cpp 375 | // Create local instances of objects. 376 | Array arr; 377 | Dictionary dict; 378 | PoolByteArray pbarr; 379 | Vector2 v2; 380 | Vector3 v3; 381 | Color c; 382 | 383 | // Errors everywhere! 384 | // None of these know how to implicitly cast to bool. 385 | // Need to explicitly teach each type how to do it. 386 | bool anyNonEmpty = arr || dict || pbarr || v2 || v3 || c; 387 | 388 | // No errors. 389 | // Classes have methods to return size. 390 | // Structs are taught how to compare field-by-field. 391 | bool anyNonEmpty = arr.size() || dict.size() || pbarr.size() || 392 | v2 == Vector2(0, 0) || 393 | v3 == Vector3(0, 0, 0) || 394 | C == Color(0); 395 | 396 | // This works because if sizes are 0, then they are == `false`, 0x00. 397 | ``` 398 | 399 | `0x00` strictness means C++ behavior can be unexpected compared to dynamic languages. 400 | 401 | ```cpp 402 | int x = 0; 403 | int *xptr = &x; 404 | 405 | (bool)*xptr; // zero value, therefore `false` 406 | (bool)xptr; // non-zero memory address, therefore `true` 407 | 408 | char *s = ""; // an empty c-string 409 | 410 | (bool)*s; // deref and cast. Value @ s == '\0'. 0x00. false 411 | (bool)s; // s == non-zero memory address of literal. true 412 | 413 | class A {}; 414 | A a; 415 | A *ap = &a; 416 | (bool)a; // Error! `A` does not know how to cast to bool. 417 | (bool)ap; // non-zero memory address. therefore `true` 418 | ``` 419 | -------------------------------------------------------------------------------- /gdscript_to_cpp/episodes/episode_4.md: -------------------------------------------------------------------------------- 1 | # GDScript to C++ Episode 4: Scopes and Statics 2 | 3 | "scope" == layer of symbols. 4 | 5 | Types of scopes: 6 | 7 | - global: symbols are universally available everywhere 8 | - class: symbols persist globally within a class. Outside the class, symbols must be accessed *through* the class. 9 | - block: symbols created and persist within the block 10 | - also known as "local" scope. 11 | - function: a type of block scope + predefined symbols for parameters 12 | 13 | ## GDScript 14 | 15 | ### **Global Scope** 16 | 17 | Engine Symbols: API docs symbols defined by engine binary. 18 | 19 | ```gdscript 20 | # fps_label.gd 21 | tool 22 | extends Label # 'Label' = engine *class* symbol 23 | func _physics_process(p_delta): 24 | # 'Engine' = engine singleton *instance* symbol 25 | text = str(Engine.get_frames_per_second()) 26 | ``` 27 | 28 | [Autoload](https://docs.godotengine.org/en/stable/getting_started/step_by_step/singletons_autoload.html): "singletons" defined by ProjectSettings > Autoloads. 29 | 30 | ![Autoload GUI with name mapped to Node/PackedScene resource path.](https://docs.godotengine.org/en/stable/_images/autoload_example.png) 31 | 32 | How it appears in your `project.godot` file: 33 | 34 | > The `*` marks whether the autoload is enabled or not. 35 | 36 | ```ini 37 | [autoload] 38 | 39 | TestNode2D="*res://Node2D.gd" 40 | ``` 41 | 42 | [Script Classes](https://docs.godotengine.org/en/stable/getting_started/step_by_step/scripting_continued.html#register-scripts-as-classes): User-defined names for scripts. 43 | 44 | ```gdscript 45 | # player.gd 46 | extends KinematicBody2D 47 | class_name Player # `class_name` keyword to define global name. 48 | ``` 49 | 50 | You can also define names for GDNative classes on the NativeScript resouce: 51 | 52 | ![A NativeScript resource with the `script_class_name` property set to `PlayerCpp`.](img/player_cpp.png) 53 | 54 | How it appears in your `project.godot` file: 55 | 56 | ```ini 57 | _global_script_classes=[ { 58 | "base": "KinematicBody2D", 59 | "class": "Player", 60 | "language": "GDScript", 61 | "path": "res://player.gd" 62 | }, { 63 | "base": "", 64 | "class": "PlayerCpp", 65 | "language": "NativeScript", 66 | "path": "res://player_cpp.gdns" 67 | } ] 68 | _global_script_class_icons={ 69 | "Player": "", 70 | "PlayerCpp": "" 71 | } 72 | ``` 73 | 74 | You can fetch these values at runtime with... 75 | 76 | ```gdscript 77 | var script_class_list = ProjectSettings.get_setting("_global_script_classes") 78 | var script_class_map = {} 79 | for a_dict in script_class_list: 80 | script_class_map[a_dict["class"]] = load(a_dict["path"]) 81 | 82 | var player = script_class_map["Player"].new() 83 | ``` 84 | 85 | GDScript generates global variables for each of these. 86 | 87 | More script class support is planned in the future (Godot 4.0+). 88 | 89 | ### **Class Scope** 90 | 91 | Created with `class` keyword, a class name, and a colon (`:`) with indents. 92 | 93 | ```gdscript 94 | # player.gd 95 | extends KinematicBody2D 96 | class_name Player 97 | 98 | var data # class scope 99 | 100 | func print_data(): 101 | print(data) # prints the data from Player 102 | 103 | class Helper: 104 | extends Reference 105 | 106 | var data # class scope, a different 'data' 107 | 108 | # has no awareness of Player.data 109 | 110 | func print_data(): 111 | print(data) # prints the data from Helper 112 | ``` 113 | 114 | ### **Block Scope** 115 | 116 | Created with any *other* case that uses a colon (`:`) with indents. 117 | 118 | ```gdscript 119 | if true: 120 | # new block via conditional 121 | pass 122 | 123 | match self.get_class(): 124 | # new block via match 125 | pass 126 | 127 | for i in 10: 128 | # new block via loop 129 | pass 130 | 131 | func _ready(): 132 | # new block via function 133 | pass 134 | ``` 135 | 136 | Unlike class scope, block scopes form a tree of nested symbols that can conflict with one another. 137 | 138 | ```gdscript 139 | # the_class.gd 140 | extends Node 141 | 142 | var data = "test" # class scope: `the_class.gd` 143 | 144 | func _ready(): # `the_class.gd` > `_ready` 145 | 146 | var data = "hi" # Error! Conflicts with `data` in `the_class.gd` 147 | var x = 2 # Safe! New symbol `x` 148 | 149 | if true: # `the_class.gd` > `_ready` > _ 150 | var x = 0 # Error! Conflicts with `x` in previous scope `_ready` 151 | var y = 0 # Safe! 152 | 153 | print(data) # Safe! Go up tree, find `data` at `the_class.gd`. 154 | print(x) # Safe! Go up tree, find `x` at `_ready`. 155 | print(y) # Safe! find `y` locally. 156 | 157 | # `y` is unloaded 158 | 159 | if true: # different: `the_class.gd` > `_ready` > _ 160 | print(data) # Safe! 161 | print(x) # Safe! 162 | print(y) # Error! `y` symbol doesn't exist! 163 | 164 | # `x` symbol unloaded 165 | # `data` symbol persists 166 | 167 | func _process(p_delta): # `the_class.gd` > `_process` 168 | # `p_delta` symbol defined 169 | 170 | print(data) # Safe! 171 | print(p_delta) # Safe! 172 | 173 | # `p_delta` symbol unloaded 174 | ``` 175 | 176 | ## C++ 177 | 178 | ### **Global vs. `{}` Scope** 179 | 180 | By default, in global scope. 181 | 182 | New scopes only require `{}`. No conditional/loop/etc. needed. 183 | 184 | ```cpp 185 | bool x = true; 186 | { 187 | bool y = true; 188 | 189 | // both exist 190 | } 191 | // `y` is unloaded 192 | ``` 193 | 194 | C++ entry point: global `main` function (covering function syntax later) 195 | 196 | ```cpp 197 | 198 | bool x = true; // global variable 199 | 200 | int main() { 201 | x; // Safe! Global variable `x` 202 | 203 | int y = 10; // block scope `y` 204 | 205 | return 0; 206 | } 207 | // `y` is unloaded 208 | ``` 209 | 210 | All C++ control flow (conditionals/switches/loops/functions) make use of curly braces and work the same way. 211 | 212 | ### Shadowing 213 | 214 | In GDScript, when we redeclared variables in a nested block, we got name conflicts. 215 | 216 | In C++, this doesn't happen. Nested symbol duplication results in *shadowing* that hides the original symbol. 217 | 218 | ```cpp 219 | bool x = true; 220 | { 221 | int x = 2; // Works! `bool x` doesn't exist now! 222 | 223 | // all references to `x` now get `x` from local scope. 224 | int sum = x + x; // 4 225 | } 226 | { 227 | bool x = false; // Works! Data type doesn't matter. 228 | } 229 | int x = 2; // Error! Redeclaring `x` in same scope. 230 | ``` 231 | 232 | > Some languages, like F# or Rust, do support this. 233 | > ```fsharp 234 | > // F# 235 | > let x = 10 // x = 10 236 | > let x = x + 10 // x = 20 237 | > let x = x + x // x = 40 238 | > ``` 239 | 240 | ### **Declarations and Definitions** 241 | 242 | In C++, there's a difference between *declaring* that a symbol exists vs. *defining* what that symbol is. 243 | 244 | ```cpp 245 | // Can declare type with a definition (all at once) 246 | struct Vector2 { 247 | float x = 0.0f; 248 | float y = 0.0f; 249 | }; 250 | 251 | // Can separate declaration and definition 252 | struct Vector3; 253 | struct Vector3 { 254 | float x = 0.0f; 255 | float y = 0.0f; 256 | float z = 0.0f; 257 | }; 258 | ``` 259 | 260 | Why do this? 261 | 262 | C++ ~= C with classes. 263 | 264 | A *procedural* language + Object-Orientation. Types defined one after another, in order, not all at once. 265 | 266 | ```cpp 267 | class Node { 268 | SceneTree *_tree; // Error! `SceneTree` not defined 269 | }; 270 | class SceneTree { 271 | Node *_root; // Error! `Node` not defined (because of error above) 272 | }; 273 | ``` 274 | 275 | How to fix? Use *forward declarations*. 276 | 277 | ```cpp 278 | class SceneTree; 279 | 280 | class Node { 281 | SceneTree *_tree; // SceneTree exists! Figure out details later. 282 | }; 283 | class SceneTree { 284 | Node *_root; // Node exists! 285 | }; 286 | ``` 287 | 288 | > Note: C#/Java are fully Object-Oriented and will automagically figure out dependencies to load things in the proper order. 289 | 290 | ### **Static And The Scope Operator (`::`)** 291 | 292 | How do we answer the question, "How many instances of a class have we made?" 293 | 294 | One answer: use a `static` variable. 295 | 296 | "Static" means a *class* owns a symbol, not *instances* of the class. All instances *share* access to something belonging to the class. 297 | 298 | ```cpp 299 | struct Counter { 300 | static int count; // variable declaration 301 | Counter() { count += 1; } // constructor increases num by 1 302 | }; 303 | 304 | int Counter::count = 0; // variable definition, initialization 305 | 306 | int main() { 307 | // Counter::count == 0 308 | Counter c; // Counter::count == 1 309 | Counter c2; // Counter::count == 2 310 | 311 | int count = c.count // Error! `c` has no `count` member. 312 | int count = Counter.count // Error! Cannot use `.` with data type. 313 | int count = Counter::count; // Works! 314 | 315 | return 0; 316 | } 317 | ``` 318 | 319 | - Add `static` keyword before data type in declaration. 320 | 321 | - Use constructor function which gets called during instantiation (cover more later). 322 | 323 | - Use the scope operator (`::`) to access `static` declarations. 324 | 325 | The static member variable must be *defined* (initialized) outside of the class definition. 326 | 327 | Pay special attention to our *definition* of the `count` member variable. 328 | 329 | ```cpp 330 | int Counter::count = 0; 331 | ``` 332 | 333 | This is *no different* than initializing a typical variable. 334 | 335 | ```cpp 336 | int count = 0; 337 | ``` 338 | 339 | The syntax has *not* changed. 340 | 341 | ```xml 342 | 343 | ``` 344 | 345 | By default, in the global *namespace*. 346 | 347 | A `namespace` is a kind of named permanent scope for symbols. If you declare something inside a namespace, the symbol persists even after you leave the namespace, but you will need to scope into the namespace to be able to access it. 348 | 349 | The symbol we want, `count`, is part of the `Counter` class, so we must enter its space with `::` before the symbol becomes visible to use from the global namespace. 350 | 351 | But, why must we define it separately? 352 | 353 | ```cpp 354 | struct Counter { 355 | static int count; // declare 356 | // ... 357 | }; 358 | int Counter::count = 0; // define 359 | ``` 360 | 361 | When `Counter` is created, so is `count`. 362 | 363 | `Counter` is defined in the global namespace. So too must `count` be so defined. 364 | 365 | It just so happens that `count` belongs to `Counter`, not the global namespace, hence the `Counter::count`. 366 | 367 | Can also access global namespace manually using the scope operator (`::`) with no prefix. 368 | 369 | ```cpp 370 | int count = 10; 371 | struct Counter { 372 | static int count; 373 | Counter() { count += ::count; } 374 | }; 375 | int Counter::count = 0; 376 | ``` 377 | 378 | Every new instance of `Counter` now increases `Counter::count` by `10`. 379 | 380 | It's even possible to create your own namespaces manually. 381 | 382 | ```cpp 383 | int global_int = 10; 384 | 385 | namespace data { 386 | namespace integers { 387 | namespace stuff { 388 | int x = 5; 389 | } 390 | } 391 | int y = 200; 392 | int z = 100; 393 | } 394 | global_int += 5; // 15 395 | data::integers::stuff::x += 20; // 25 396 | 397 | // Too long. Let's make an alias: 398 | namespace dis = data::integers::stuff; 399 | int sum = dis::x + global_int; // 40 400 | 401 | // Getting tired of writing new aliases all the time... 402 | using data; 403 | int y_and_z = y + z; // 300 404 | ``` 405 | 406 | > See more about differences between [static class members and namespaces](https://stackoverflow.com/questions/1434937/namespace-functions-versus-static-methods-on-a-class). Note that [templates also come into play](https://stackoverflow.com/questions/14361408/using-a-namespace-in-place-of-a-static-class-in-c) (we'll cover those later). 407 | 408 | ### Statics in GDScript 409 | 410 | Here's a thought exercise... 411 | 412 | Godot specifically *does not support* static data in scripting for thread-safety reasons. 413 | 414 | *However*, Godot's scripted classes != C++ classes. They are `Script` resource *instances*. 415 | 416 | That's why GDScript lets you alias them with variables. They are *values*. 417 | 418 | ```gdscript 419 | const SomeClass = preload("some_class.gd") 420 | const MyAlias = SomeClass # can assign "class" to a different variable 421 | ``` 422 | 423 | All Godot `Object` types, including `Resource` and `Script`, support runtime metadata read/write with `set_meta(key, value)` and `get_meta(key)`. 424 | 425 | You can combine this with script classes for pseudo-static data. 426 | 427 | ```gdscript 428 | # static.gd 429 | extends Reference 430 | class_name Static 431 | 432 | # some_class.gd 433 | extends Node 434 | func _ready(): 435 | Static.set_meta("some_data", { x: 1, y: 2}) 436 | 437 | # another_class.gd 438 | extends Node 439 | func _ready(): 440 | var data = Static.get_meta("some_data") 441 | if data: 442 | print(Vector2(data.x, data.y)) 443 | ``` 444 | 445 | However, this is similar to creating an Autoload: 446 | 447 | ```gdscript 448 | # static.gd, autoload name "Static" 449 | extends Node 450 | var meta = {} 451 | 452 | # some_class.gd 453 | extends Node 454 | func _ready(): 455 | Static.meta.some_data = { x: 1, y: 2 } 456 | 457 | # another_class.gd 458 | extends Node 459 | func _ready(): 460 | var data = Static.meta.some_data 461 | if data: 462 | print(Vector2(data.x, data.y)) 463 | ``` 464 | 465 | Which should you choose? Well, Autoloads store data on a Node instance, not a resource's metadata, so you have access to more features: 466 | 467 | - non-static members, methods, and signals 468 | - `setget` keyword 469 | - statically-typed data (metadata is inherently untyped) 470 | - `get_tree()`, the SceneTree and all that entails... 471 | - the Node tree 472 | - Node groups 473 | - delta-time 474 | - input events 475 | - data serialization support (saving/loading) 476 | 477 | So, while pseudo-static data is *possible* in GDScript, it's just not preferable to the alternative. 478 | 479 | ### More Statics: Functions and Classes 480 | 481 | GDScript does, however, support static *functions*. 482 | 483 | ```gdscript 484 | extends Reference 485 | class_name Util 486 | 487 | static func get_author() -> String: 488 | return "willnationsdev" 489 | ``` 490 | 491 | No need to create a Util instance. 492 | 493 | ```gdscript 494 | var util = Util.new() # why bother? 495 | var name = Util.get_author() # can directly call on Script 496 | ``` 497 | 498 | C++ supports the same (again, we'll cover functions in more detail later). 499 | 500 | ```cpp 501 | struct Util { 502 | static const char* get_author() { 503 | return "willnationsdev"; 504 | } 505 | } 506 | Util util; 507 | const char* name = util.get_author(); // Error! get_author is static! 508 | const char* name = Util::get_author(); // Works! 509 | ``` 510 | 511 | However, it's frustrating that people can even make a Util instance. Let's prevent that. 512 | 513 | ```cpp 514 | static struct Util { 515 | // same... 516 | } 517 | Util util; // Error! Static class cannot be instantiated! 518 | ``` 519 | 520 | Booyah. 521 | 522 | ### To Be Continued 523 | 524 | Unfortunately, that is not the end of scopes in C++. When we learn Inheritance, there will be yet more to discover (`this`, `Base1::x` vs. `Base2::x`), but alas, those are for another day. 525 | -------------------------------------------------------------------------------- /gdscript_to_cpp/episodes/episode_5.md: -------------------------------------------------------------------------------- 1 | # GDScript to C++ Episode 5: Control Flow 2 | 3 | ## Conditionals 4 | 5 | In GDScript: 6 | 7 | ```gdscript 8 | var x := 0 9 | if x == 10: 10 | # do A 11 | elif x == 15: 12 | # do B 13 | elif x: # implicitly cast to bool. 0 -> false. 14 | # do C 15 | else: 16 | # do D 17 | ``` 18 | 19 | In C++: 20 | 21 | ```cpp 22 | int x = 0; 23 | if (x == 10) { 24 | // do A 25 | } else if (x == 15) { 26 | // do B 27 | } else if (x) { // implicitly cast to bool. 0 -> false. 28 | // do C 29 | } else { 30 | // do D 31 | } 32 | ``` 33 | 34 | - `elif` -> `else if` 35 | - Parentheses (`()`) around expressions 36 | - For blocks, curly brances (`{}`) are required. C++ does not rely on indentation. 37 | 38 | Another supported style (standard for C#, Java, etc.): 39 | 40 | ```cpp 41 | if (...) 42 | { 43 | // do A 44 | } 45 | else if (...) 46 | { 47 | // do B 48 | } 49 | else 50 | { 51 | // do C 52 | } 53 | ``` 54 | 55 | Coding convention decides. 56 | 57 | Syntax also supports just statements, no `{}` blocks. 58 | 59 | ```cpp 60 | if (true) 61 | print_line("hello"); 62 | ``` 63 | 64 | However, these are often considered a code smell. 65 | 66 | ```cpp 67 | if (false) 68 | print_line("hello "); 69 | print_line("world!"); 70 | // same as 71 | if (false) 72 | print_line("hello "); 73 | print_line("world!"); 74 | // same as 75 | if (false) { 76 | print_line("hello "); 77 | } 78 | print_line("world!"); 79 | ``` 80 | 81 | Also, if have `{}` already, no need to *add* them for later edits. 82 | 83 | Statements (`;`) force a single line of code. Blocks (`{}`) give flexibility for 0+ lines of code. 84 | 85 | > So, why then do class declarations need `{}` *and* `;`? 86 | > 87 | > Actually, they can post-declare instance symbols. 88 | > 89 | > ```cpp 90 | > class A {} a; 91 | > // equal to... 92 | > class A {}; 93 | > A a; 94 | > ``` 95 | 96 | 🤮 Blegh! Who's gonna pay attention to that? 97 | 98 | Can also inline statements. Even more nasty. 99 | 100 | ```cpp 101 | if (some_test()) do_something(); 102 | else if (1 == 2) do_something_else(); 103 | else otherwise_do_this(); 104 | ``` 105 | 106 | > How to check if pointer is valid? Now we know! 107 | > 108 | > ```cpp 109 | > Node *child = get_node("Child"); 110 | > if (child) { 111 | > // child is true 112 | > // child is non-zero 113 | > // child != 0 114 | > // child != nullptr 115 | > print_line(child->get_name()); // Safe! Prints "Child" 116 | > } 117 | > ``` 118 | 119 | Main Differences Recap: 120 | 121 | - C++: `else if` 122 | 123 | GDScript: `elif` 124 | 125 | - C++: `()` required for expression. 126 | 127 | GDScript: `()` optional/unconventional. 128 | 129 | - C++: `{}` recommended for block. No `{}` = only 1 statement (`;`) (BAD). 130 | 131 | GDScript: indent after colon (`:`) required. Always a block. Block ends with dedent. 132 | 133 | ## Ternary Operator 134 | 135 | Both languages also support ternary operators. 136 | 137 | GDScript: 138 | 139 | ```gdscript 140 | # if else 141 | # cases can have different types 142 | print("true" if x == y else ["true"]) 143 | ``` 144 | 145 | C++: 146 | 147 | ```cpp 148 | // ? : 149 | // Cases required to be the same type 150 | print_line(x == y ? "true" : "false") 151 | ``` 152 | 153 | Also, it is possible to [nest ternary operators](https://stackoverflow.com/questions/18237432/how-to-rewrite-complicated-lines-of-c-code-nested-ternary-operator). 154 | 155 | ```cpp 156 | good = m_seedsfilter==0 ? true : 157 | m_seedsfilter==1 ? newClusters(Sp) : 158 | newSeed(Sp); 159 | ``` 160 | 161 | This one is relatively clean and simple. Might be able to get away with it. 162 | 163 | But please, don't be this person ([source](https://www.geeksforgeeks.org/c-nested-ternary-operator/)): 164 | 165 | ```cpp 166 | int a = 2 > 3 ? 2 : 3 > 4 ? 3 : 4; 167 | ``` 168 | 169 | Usually Godot devs don't like nested ternaries (for readability). 170 | 171 | ## Switch 172 | 173 | Compare many values against the same expression. 174 | 175 | GDScript: 176 | 177 | ```gdscript 178 | var value = 179 | match value: 180 | 181 | # Match multiple things with one block. 182 | [], {}, PoolByteArray(), PoolIntArray(): 183 | print("value is some empty container") 184 | 185 | 15: 186 | print("value is `int(15)`") 187 | 188 | "hello": 189 | 190 | print("value is `str('hello')`") 191 | 192 | # `_` matches all remaining cases. 193 | _: 194 | print("value was something else") 195 | ``` 196 | 197 | In GDScript, you can even explicitly check for different data types, not just different values. 198 | 199 | ```gdscript 200 | var value = 201 | match typeof(value): 202 | TYPE_NIL: 203 | pass # logic if null 204 | TYPE_ARRAY: 205 | pass # logic if [ ... ] 206 | TYPE_DICTIONARY: 207 | pass # logic if { ... } 208 | _: 209 | pass # etc. 210 | ``` 211 | 212 | C++: 213 | 214 | The `expression` must be an *integral* value. 215 | 216 | ```cpp 217 | int value = ; 218 | // Supported: bool, char, short, int, long, long long 219 | // Not supported: float, class/struct instance, * 220 | // Can cast pointers to integral...but why? Either nullptr or some address. 221 | int outside = 0; 222 | 223 | switch (value) { 224 | case 0: 225 | // `value` is `0` 226 | 227 | int local_var = 1; // Error! Jump to case label crosses init of var. 228 | 229 | // explicitly terminate block 230 | break; 231 | 232 | // Can mutate declarations outside of switch block. 233 | // "fallthrough" / "cascade" mechanic if no `break` 234 | case 1: // `value` is `1` 235 | outside += 1; 236 | case 2: // `value` is `1` or `2` 237 | outside += 1; 238 | case 3: // `value` is `1`, `2`, or `3` 239 | outside += 1 240 | 241 | break; 242 | 243 | default: { 244 | 245 | int local_var = 5; // safe! new scope 246 | outside = local_var; 247 | 248 | } break; 249 | } 250 | ``` 251 | 252 | ## Loops: While 253 | 254 | Repeatedly execute a block. Evaluate a bool expression to determine (re)entry. 255 | 256 | GDScript: 257 | 258 | ```gdscript 259 | while true: 260 | print("hi") # infinite loop 261 | ``` 262 | 263 | State management occurs separately. 264 | 265 | ```gdscript 266 | var i = 0 # set iterator 267 | var size = 10 # set "base case" 268 | while i < 10: # eval itr. At base case to quit? 269 | var x = i # logic body 270 | i += 1 # advance towards base case 271 | ``` 272 | 273 | Equivalent in C++ with identical caveats of if statements: 274 | 275 | - Require `()` around expression. 276 | - Replace `:` indented block with `{}`. 277 | - Can replace `{}` with single statement `;` (not recommended). 278 | 279 | ```cpp 280 | while (true) { 281 | print_line("hi"); // Godot print, infinite loop 282 | } 283 | 284 | // State management 285 | int i = 0; // set iterator 286 | int size = 10; // set "base case" 287 | while (i < size) { // eval itr. At base case to quit? 288 | int x = i; // logic body 289 | i++; // advance towards base case 290 | } 291 | ``` 292 | 293 | > The `++` operator is new. That's the "post-increment" operator. 294 | > It returns the current value and then adds 1 to the variable. 295 | > 296 | > ```cpp 297 | > int x = 5; 298 | > int a = x++; // 5 299 | > int b = x++; // 6 300 | > // x = 7 301 | > ``` 302 | > 303 | > There's also the "pre-increment", e.g. `++x`, that increases by 1 and *then* returns. 304 | > Decrement versions also exist: `x--` and `--x` 305 | > 306 | > C++ is the "next iteration" of `c` -> `c++` 307 | > 308 | > C# is the "next iteration" of `c++` -> `c++++` -> `c#` (4 plus signs) 309 | 310 | ## Loops: Do-While 311 | 312 | Need to change to "do logic, advance, THEN eval itr?" 313 | 314 | Do-While Loop: 315 | 316 | ```cpp 317 | do { 318 | int x = i; // logic body 319 | i++; // advance towards base case 320 | } while (i < size); // eval itr. At base to quit? 321 | ``` 322 | 323 | `;` after while eval because must conclude statement. Didn't already end with curly braces. 324 | 325 | ## Loops: For 326 | 327 | C++ also has a `for` loop. Bottles up state management into local/consistent format: 328 | 329 | ```cpp 330 | // syntax: 331 | // for (initializers...; eval expression; advance) { 332 | // logic body 333 | // } 334 | // initializers: Executed once at start. 335 | // Symbols locally scoped. 336 | // eval expr : executed before every body exec. 337 | // : only enter body if `true`. 338 | // advance : executed at end of every body exec. 339 | 340 | // Example: 341 | for (int i = 0, int size = 10; i < size; i++) { 342 | int x = i; 343 | } 344 | // `i` and `size` are scoped to for loop. Don't exist. 345 | 346 | // More commonly seen like this: 347 | for (int i = 0; i < 10; i++) { 348 | 349 | } 350 | 351 | // Equivalent to a `while(true) {}` loop 352 | for (; true;) { 353 | 354 | } 355 | ``` 356 | 357 | GDScript also has a `for` loop. 358 | 359 | ```gdscript 360 | for i in 3: 361 | print(i) # prints 0, 1, 2 362 | ``` 363 | 364 | However, the number is actually a shortcut for `range(3)`. 365 | 366 | ```gdscript 367 | for i in 3: 368 | print(i) 369 | # same as 370 | for i in range(3): 371 | print(i) 372 | # same as 373 | for i in [0, 1, 2]: 374 | print(i) 375 | ``` 376 | 377 | As such, GDScript's `for` loop is actually a `for-in` loop, aka a `foreach` loop in C#/PHP/others. 378 | 379 | It iterates through every element of a collection with no state management. 380 | 381 | ```gdscript 382 | var numbers = [0, 1, 2, 3] 383 | for i in numbers: 384 | print(i) 385 | # equivalent 386 | for i in 4: # implicit array expansion, 4 elements 387 | print(i) 388 | ``` 389 | 390 | C++11 added "range-based for loops". Collection class must support it. 391 | 392 | As of writing, Godot's collections **do not** support them. But if they did... 393 | 394 | ```cpp 395 | Array arr; 396 | for (Variant elem : arr) { 397 | 398 | } 399 | ``` 400 | 401 | Instead, you have to use a for loop: 402 | 403 | ```cpp 404 | Array arr; 405 | for (int i = 0; i < arr.size(); i++) { 406 | 407 | } 408 | ``` -------------------------------------------------------------------------------- /gdscript_to_cpp/episodes/episode_Data_Structures.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willnationsdev/deconstructing-godot/35dee549c59a89e480d9a5ab895a1e912cb2278f/gdscript_to_cpp/episodes/episode_Data_Structures.md -------------------------------------------------------------------------------- /gdscript_to_cpp/episodes/episode_Functions.md: -------------------------------------------------------------------------------- 1 | # GDScript to C++ Episode 5: Functions 2 | 3 | ## Functions (Basic Syntax) 4 | 5 | > A `function` is an input/output mechanism that abstracts a set of instructions. 6 | > 7 | > A `method` is a function that belongs to a `class`. 8 | 9 | GDScript methods have optional static typing. 10 | 11 | ```gdscript 12 | # dynamic 13 | func add(left, right): 14 | return left + right 15 | 16 | # static 17 | func add(left: int, right: int) -> int: 18 | return left + right 19 | 20 | # no return value 21 | func do_nothing(): 22 | pass 23 | 24 | func _ready(): 25 | var x = add(3, 4) # 7 26 | var y = do_nothing() # null 27 | ``` 28 | 29 | In C++, statically typed. Not optional addendum at end of info. *Start* with the data type. 30 | 31 | ```cpp 32 | int add(int left, int right) { 33 | return left + right; 34 | } 35 | 36 | // no return value, void 'type' 37 | void do_nothing() { 38 | } 39 | 40 | // usage: 41 | int x = add(3, 4); // 7 42 | int x = do_nothing(); // Error! Cannot assign `void` 43 | void x = do_nothing(); // Error! `void` not a type. 44 | do_nothing(); // Correct 45 | ``` 46 | 47 | ### **Aside: Error Enums** 48 | 49 | Since I'm showing `main()`... 50 | 51 | `0` = `false`, else `true`. 52 | 53 | ```cpp 54 | bool success = do_something(); 55 | ``` 56 | 57 | If `false`...*what* went wrong? Need more info. 58 | 59 | 1 success case, many error cases. Return `int`? `0` for success, else error. 60 | 61 | Human-readable error names -> `enum`. 62 | 63 | ```cpp 64 | enum Error { 65 | OK, // 0 66 | ERR_BAD_PARAM, // 1 67 | ERR_CANNOT_OPEN_FILE, // 2 68 | ERR_MISSSPELLLING, // 3 69 | ERR_FML_WHY_THIS_NO_WORK, // 4 70 | ERR_ID_10_T // 5 71 | } 72 | 73 | int main() { 74 | // try to open file. If it fails... 75 | return ERR_CANNOT_OPEN_FILE; 76 | // else... 77 | return OK; 78 | } 79 | ``` 80 | 81 | You can see Godot's `Error` enum defined in the `@GlobalScope` API docs. 82 | 83 | This can be confusing, even in GDScript, when things like `File.open` return an `Error`: 84 | 85 | ```gdscript 86 | var f = File.new() 87 | # if 0, i.e. OK, will NOT enter the if statement. 88 | if f.open("data.txt", File.READ): 89 | print("Operation was 'true'. So...it worked, right? NOPE") 90 | 91 | var result = f.open("data.txt", File.READ) 92 | if result: # works, but might be confusing 93 | printerr("Something went wrong") 94 | 95 | var err = f.open("data.txt", File.READ) 96 | if err != OK: 97 | printerr("Result was not OK, therefore a non-zero int Error was returned.") 98 | printerr("Error: %d" % err) 99 | ``` 100 | 101 | Moving on... 102 | -------------------------------------------------------------------------------- /gdscript_to_cpp/episodes/episode_Inheritance.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willnationsdev/deconstructing-godot/35dee549c59a89e480d9a5ab895a1e912cb2278f/gdscript_to_cpp/episodes/episode_Inheritance.md -------------------------------------------------------------------------------- /gdscript_to_cpp/episodes/episode_Strings_and_Comparisons.md: -------------------------------------------------------------------------------- 1 | # GDScript to C++ Episode 6: Strings and Comparisons 2 | 3 | ## Object Comparisons 4 | 5 | In GDScript, you can compare objects. 6 | 7 | ```gdscript 8 | var obj1 = Object.new() 9 | var obj2 = Object.new() 10 | if obj1 == obj2: 11 | pass # always false. But why? 12 | ``` 13 | 14 | Because the Variant class, when dealing with Objects, deals with an `Object*` internally. 15 | 16 | Similar to the C++ code: 17 | 18 | ```cpp 19 | Object *obj1 = memnew(Object); // Object instance at memory address 450130 20 | Object *obj2 = memnew(Object); // Object instance at memory address 624095 21 | if (obj1 == obj2) { 22 | // always false. 450130 != 624095 23 | } 24 | // Error! No operator overload `==` for types Object and Object. 25 | if (*obj == *obj2) { 26 | } 27 | ``` 28 | 29 | But...there *are* non-primitive types that compare safely in GDScript. 30 | 31 | ```gdscript 32 | var a1 = [1, 2, 3] 33 | var a2 = [1, 2, 3] 34 | var d1 = { x: 1, y: 2 } 35 | var d2 = { x: 1, y: 2 } 36 | if a1 = a2: 37 | print("a1 and a2 have the same content") // Works! 38 | if d1 = d2: 39 | print("d1 and d2 have the same content") // Works! 40 | ``` 41 | 42 | What's the difference here? 43 | 44 | Reminder: C++ is *dumb*. 45 | 46 | ```cpp 47 | // I know nothing. What even is I? Self do wat? 48 | class Object {}; 49 | ``` 50 | 51 | You know how in GDScript, you can override methods? 52 | 53 | ```gdscript 54 | # base.gd 55 | 56 | 57 | func print_name(): 58 | print("base") 59 | 60 | # derived.gd 61 | extends "base.gd" 62 | 63 | 64 | func print_name(): 65 | print("derived") 66 | 67 | # my_node.gd 68 | extends Node 69 | 70 | 71 | func _ready(): 72 | var base = load("base.gd").new() 73 | base.print_name() # prints "base" 74 | 75 | var derived = load("derived.gd").new() 76 | derived.print_name() # prints "derived" 77 | ``` 78 | 79 | **What if** GDScript had a method to compare Objects? 80 | 81 | What if this were a kind of engine notification that you could override like `_ready()`? 82 | 83 | ```gdscript 84 | # reference_vector2.gd 85 | extends Reference 86 | 87 | 88 | var x := 0.0 89 | var y := 0.0 90 | 91 | 92 | func _equals(v1, v2) -> bool: 93 | return v1.x == v2.x and v1.y == v2.y 94 | ``` 95 | 96 | C++ supports this with many predefined `operator()` functions: 97 | 98 | (again, cover functions later) 99 | 100 | ```cpp 101 | bool Array::operator==(const Array &otherArray) const { 102 | // `==` operator belonging to Array class 103 | // Comparing against some other Array called `otherArray` 104 | 105 | // Add logic to manually compare content, not memory address 106 | } 107 | ``` 108 | 109 | The `Variant` class then does something like this in GDScript: 110 | 111 | ```gdscript 112 | func _equals(other) -> bool: 113 | match typeof(other): 114 | TYPE_ARRAY: 115 | return (self as Array) == (other as Array) 116 | TYPE_DICTIONARY: 117 | return (self as Dictionary) == (other as Dictionary) 118 | # etc. 119 | ``` 120 | 121 | That *forces* a call to the type-specific `operator==` implementation. 122 | 123 | So, why is there a difference? 124 | 125 | `Object` is too general-purpose. Use truest comparison (instances). 126 | 127 | `Array` and `Dictionary` are collections. Use convenient comparison (content). 128 | 129 | ## String Comparisons 130 | 131 | Strings are more complicated. Every string is a c-string that is a pointer to some sequence of characters in memory. 132 | 133 | `const` keyword is a type qualifier that means the variable cannot be mutated. It is read-only. 134 | 135 | A `const char*` is a *completely different data type* than a `char*`. 136 | 137 | Despite this, assignment (`=`) still works (will cover more later). 138 | 139 | String literal = `const char*` since value cannot change. 140 | 141 | ```cpp 142 | // Cover this later. Gives access to `strcmp()` function. 143 | #include 144 | 145 | const char *s1 = "hello"; 146 | const char *s2 = "hello"; 147 | const char *s3 = s1; 148 | 149 | // const char * == int 150 | // Error! Cannot compare pointer with int. 151 | "2" == 2; 152 | 153 | // (long long <- const char*) == int 154 | // 450130 == 2 155 | (long long)"2" == 2; 156 | 157 | // const char* == const char* 158 | // Literals directly written into compiled binary. 159 | // Each literal address is different: false 160 | "2" == "2"; 161 | 162 | // Comparing *addresses*. Not same c-string: false 163 | s1 == s2; 164 | 165 | // Comparing *addresses*. Same: true 166 | s1 == s3; 167 | 168 | // s1 first char 'h'. s2 first char 'h'. 169 | // 'h' == 'h' -> 0x68 == 0x68: true 170 | *s1 == *s2; 171 | 172 | // strcmp; Compares char at each index until \0. 173 | // Returns 0 if same: true 174 | int result = strcmp(s1, s2); 175 | if (result < 0) { 176 | // s1 has earlier char with lesser numeric value 177 | } else if (result > 0) { 178 | // s1 has earlier char with greater numeric value 179 | } else if (result == 0) { 180 | // s1 and s2 have equal char values all the way through. 181 | } 182 | ``` -------------------------------------------------------------------------------- /gdscript_to_cpp/episodes/episode_Unions_and_Variant.md: -------------------------------------------------------------------------------- 1 | # GDScript to C++ Episode N: Unions and Variant 2 | 3 | ## Union 4 | 5 | How does GDScript's dynamic typing work? 6 | 7 | C++: 8 | 9 | ```cpp 10 | // Does not change type of `x` to `bool`. 11 | // Performs `bool` to `int` cast. 12 | int x = 2; 13 | x = true; // 1, still an `int` 14 | x = false; // 0, still an `int` 15 | ``` 16 | 17 | GDScript: 18 | 19 | ```gdscript 20 | var x = 2 21 | x = true # `x` is now a bool 22 | ``` 23 | 24 | In C++, this behavior is accomplished using a `union`. 25 | 26 | ```cpp 27 | struct BoolAndYup { 28 | bool b; // 1 byte 29 | char y; // 1 byte 30 | char u; // 1 byte 31 | char p; // 1 byte 32 | }; 33 | 34 | // Combines each field into same byte region. 35 | union MyUnion { 36 | int as_int; // 4 bytes 37 | BoolAndYup as_bay; // 4 bytes 38 | float as_float; // 4 bytes 39 | }; 40 | 41 | // 4 bytes 42 | MyUnion mu; 43 | mu.as_int; // interpret bytes as int 44 | mu.as_float; // interpret bytes as float 45 | mu.as_bay; // interpret bytes as BoolAndYup 46 | ``` 47 | 48 | Can't tell what type `mu` is at runtime...hmmm. 49 | 50 | Use an enum! 51 | 52 | ```cpp 53 | enum MyUnionType { 54 | Int, 55 | Float, 56 | Bay 57 | } 58 | 59 | // Make the following change to MyUnion 60 | struct MyUnionData { 61 | int as_int; // 4 bytes 62 | BoolAndYup as_bay; // 4 bytes 63 | float as_float; // 4 bytes 64 | }; 65 | 66 | union MyUnion { 67 | MyUnionData data; // 4 bytes 68 | MyUnionType type; // 4 bytes 69 | }; 70 | 71 | // use as int 72 | mu.data.as_int = 2; 73 | mu.type = Int; 74 | 75 | mu.type == Int; // true 76 | ``` 77 | 78 | Now we can check what "type" it is based on the enum, and access the correct field. -------------------------------------------------------------------------------- /gdscript_to_cpp/episodes/img/calculate_integer_size_biggest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willnationsdev/deconstructing-godot/35dee549c59a89e480d9a5ab895a1e912cb2278f/gdscript_to_cpp/episodes/img/calculate_integer_size_biggest.png -------------------------------------------------------------------------------- /gdscript_to_cpp/episodes/img/player_cpp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willnationsdev/deconstructing-godot/35dee549c59a89e480d9a5ab895a1e912cb2278f/gdscript_to_cpp/episodes/img/player_cpp.png -------------------------------------------------------------------------------- /gdscript_to_cpp/gdscript_to_cpp.md: -------------------------------------------------------------------------------- 1 | # Comparing C++ and GDScript Syntax 2 | 3 | This document contains my full notes on each topic. As episodes release, a subset of this document will be converted into a video-friendly format for presentation and review. You can think of this as a Work-In-Progress until individual "complete" episodes are published with their supplemental video material in the `/gdscript_to-cpp/episodes/` folder. 4 | 5 | - Course Learning: 6 | - C++ concepts/syntax 7 | - Basic program memory structure 8 | 9 | - Course Requirements: 10 | - GDScript features and syntax 11 | 12 | ## Key Principles: 13 | 14 | 1. C++ thinks *everything* is a *number*. 15 | 1. C++ needs to know *exactly* how those numbers are *arranged and used* ahead of time. 16 | 1. C++ is *dumb*. It trusts you to painstakingly build whatever you want with almost no supervision. 17 | 18 | ## Comments 19 | 20 | C++: 21 | 22 | ```cpp 23 | // Comments use double-slashes 24 | int x; // a comment after a statement 25 | /* This is a 26 | multiline 27 | comment */ 28 | ``` 29 | 30 | GDScript: 31 | 32 | ```gdscript 33 | # Comments use pound 34 | var x # a comment after a statement 35 | """ 36 | A multiline comment syntax doesn't exist. 37 | Use docstrings instead! 38 | """ 39 | ``` 40 | 41 | ## Class declaration 42 | 43 | In GDScript, the starting point of knowledge is class declarations. Every `.gd` file declares the existence of a class, even if it is empty (inheritance defaults to `Reference`). 44 | 45 | In C++, it isn't enough to have a file. You must explicitly declare the existence of the class using the `class` keyword, followed by its name, the block of code associated with the class, and a terminating semicolon. 46 | 47 | ```cpp 48 | // some_class.h 49 | class SomeClass { 50 | 51 | }; 52 | ``` 53 | 54 | Notice the lack of inheritance. Unlike GDScript, C++ classes can exist independently. 55 | 56 | > Usually, a declaration (property, method, control flow, whatever) will use `{ ... }` OR `;`, but not both. Classes are special. [See more](https://stackoverflow.com/questions/1783465/why-must-i-put-a-semicolon-at-the-end-of-class-declaration-in-c/1783509). 57 | 58 | ## Access Modifiers And Basic Inheritance 59 | 60 | In C++, external classes can only access properties and methods (aka members) under certain conditions. By default, members are hidden under a `private` access modifier. To expose members, the class must explicitly specify an alternative access modifier. `protected` permits only inherited contexts. `public` permits all contexts. 61 | 62 | By convention, non-public properties and methods are prefixed with an underscore. 63 | 64 | ```cpp 65 | // some_class.h 66 | class SomeClass { 67 | private: 68 | int _x; // only accessible in SomeClass 69 | protected: 70 | int _y; // only accessible in SomeClass and its derived classes 71 | public: 72 | int z; // acessible from any class 73 | }; 74 | ``` 75 | 76 | ```gdscript 77 | # some_class.gd 78 | # Everything is public. Uses conventions to communicate intended access. 79 | var _x: int 80 | var z: int 81 | ``` 82 | 83 | In GDScript, every class must extend an existing engine class. It can be done in one of 3 ways: 84 | 85 | ```gdscript 86 | extends Node # an engine class 87 | extends "my_node.gd" # a file path to another script 88 | extends MyNode # the name of a global script class 89 | ``` 90 | 91 | In every case, the inheriting class gains unrestricted access to all of the base class's content. 92 | 93 | Here's an example of inheritance in C++: 94 | 95 | ```cpp 96 | class BaseClass { 97 | public: 98 | int x; 99 | }; 100 | class DerivedClass : public BaseClass { 101 | 102 | }; 103 | ``` 104 | 105 | The `:` after the class name is C++'s `extends` syntax. 106 | 107 | The `BaseClass` is the class name to be inherited. 108 | 109 | Inheriting classes apply an access modifier to their base class. This imposes a limitation on the access levels inherited by the base class. 110 | 111 | `public` inheritance makes no change to `BaseClass` in `DerivedClass`. *Most of the time*, this is what you will see. 112 | 113 | `protected` inheritance converts all of `BaseClass`'s `public` members to `protected` members. 114 | 115 | `private` inheritance converts all of `BaseClass`'s `public` and `protected` members to `private` members. 116 | 117 | If a modifier is omitted, it defaults to `private`. 118 | 119 | C++ *also* has a `struct` keyword. 120 | 121 | ```cpp 122 | struct BaseClass { 123 | int x; 124 | }; 125 | struct DerivedClass : BaseClass { 126 | 127 | } 128 | ``` 129 | 130 | The only difference between a `class` and a `struct` is the default access level which is `public` rather than `private`. Therefore, the two previous code segments are functionally equivalent. 131 | 132 | For more examples, visit [this StackOverflow page](https://stackoverflow.com/questions/860339/difference-between-private-public-and-protected-inheritance). 133 | 134 | ## Symbols: Variables as Memory Locations 135 | 136 | A "symbol" is a string of text within a language's source code that identifies a language entity (something the language tracks). 137 | 138 | ```gdscript 139 | extends Node 140 | var x = 0 # `x` is a symbol 141 | ``` 142 | 143 | All languages have the concept of a "symbol table". It tracks each symbol's memory location. 144 | 145 | A language's internal symbol table might look something like a string-to-int Dictionary: 146 | 147 | ```gdscript 148 | var symbols = {} 149 | 150 | # `var x = 10` 151 | 152 | symbols["x"] = 10484892920 153 | ``` 154 | 155 | However, for simplicity, most memory address information is hidden in GDScript. 156 | 157 | ## Dynamic Variant vs Static Data Types 158 | 159 | When a program creates a variable, it needs to know how many bytes each variable is. When declaring variables, the program writes their values into memory sequentially, beside one another. However, how it does so is determined by data types. 160 | 161 | Data types have a *byte size* which can affect the byte offset between variables. 162 | 163 | Data types tell the computer *how* to write their data to memory. 164 | 165 | ### GDScript 166 | 167 | Now, GDScript is dynamic. How does it achieve this? It is built on Godot's Variant. Variant can store a subset of data types. The largest of these is 16 bytes. It combines these 16 bytes with a 4-byte enum to keep track of a data type. With these combined 20 bytes, it has some tricks available to it: 168 | 169 | - It stores a *size* of 20 bytes for everything, even if the data needs less than that. No need to calculate sizes at compile time. 170 | - It freely *interprets* data types on a whim based on the enum value. 171 | - `int(5)` to `bool(1)`? 172 | 1. 4-byte `TYPE_INT` -> `TYPE_BOOL`. 173 | 2. 16-byte 0x0000000000000005 -> 16-byte 0x0000000000000001. 174 | 175 | > See [@GlobalScope docs](https://docs.godotengine.org/en/latest/classes/class_@globalscope.html) for the `Variant.Type` enum to see all available types. 176 | 177 | ### C++ Data Types 178 | 179 | C++ is a natively-compiled, statically-typed language. Because it is compiled ahead of execution for a native target, it must know the exact structure of everything ahead of time. How? 180 | 181 | C++ only comprehends numbers but applies them in many ways... 182 | 183 | C++ qualifies numbers: 184 | 185 | - sizes (usually 8, 16, 32, 64) 186 | - signage 187 | - byte size qualifiers (`short`, `long`) 188 | - mutability (default true, `const` false) 189 | - reference to existing number (`&`)? 190 | - memory address (`*`)? 191 | 192 | C++ interprets numbers (a "data type"): 193 | 194 | > Note: Byte sizes are not final! Can be adjusted with size qualifiers and may be compiler dependent. 195 | 196 | > C++ believes that *every* type can be boolean (is it zero?). There are many values of 0x0000 which can be expressed as different data types. See the 'False' sections below. 197 | 198 | - void: `void` (0 bytes) 199 | - Nothing/Unknown. 200 | - boolean: `bool` (1 byte) 201 | - Truth-ness. 202 | - True: `true` 203 | - False: `false` 204 | - integer: `int` (4 bytes) 205 | - Positive or negative whole numbers. 206 | - True: `1000`, `-3` 207 | - False: `0` 208 | - character: `char` (1 byte) 209 | - Letters to be displayed **or** *small* positive or negative whole numbers. 210 | - True: `'a'`, `'\n'` 211 | - False: `'\0'` ("null terminator") 212 | - floating-point: `float` (4 bytes) 213 | - Imprecise representations of fractions and decimals. Leave a margin of error in comparisons for consistency. 214 | - True: `3.14`, `-0.0000001` 215 | - False: `0.0` 216 | - pointer: `*` (4 bytes x32 | 8 bytes x64) 217 | - Stores a memory address to a specific type 218 | - True: `504891358` 219 | - False: `NULL` or, after C++11, `nullptr` 220 | 221 | > See the [C++ reference](https://en.cppreference.com/w/cpp/language/types) for a more detailed breakdown type representations. 222 | 223 | Computers consider data types with distinct qualifiers to be *completely different data types*. 224 | 225 | A function marks the starting memory location of executable instructions. It has a *number*. 226 | 227 | A class or struct is a named, sequential list of varying types of numbers. 228 | 229 | Inheritance is more or less a named, sequential list of classes. 230 | 231 | > C++ supports *multiple inheritance*. This can lead to inheriting duplicate classes. See the [Diamond Problem](https://www.geeksforgeeks.org/multiple-inheritance-in-c/) for more information. 232 | 233 | ### C++ Example 234 | 235 | ```cpp 236 | struct VerifiablePoint { 237 | bool isVerified; 238 | int x; 239 | int y; 240 | } 241 | ``` 242 | 243 | Depending on the compiler, an instance of `VerifiablePoint` in memory could look like this: 244 | 245 | ```cpp 246 | VerifiablePoint p; 247 | p.isVerified = false 248 | p.x = 10 249 | p.y = 4 250 | 251 | // memory : value 252 | // ----------------- 253 | // 00000000 : 0x00 (1 byte) 254 | // 00000001 : 0x0000000A (4 bytes) 255 | // 00000005 : 0x00000004 (4 bytes) 256 | // 00000009 : 0x???????? (? bytes) 257 | 258 | // linearly 259 | // 000000000A00000004 260 | 261 | // symbol table (as Dictionary) 262 | // ---------------------------- 263 | // symbols['p'] = { 264 | // 'address': 00000000, 265 | // 'type': VerifiablePoint 266 | // } 267 | ``` 268 | 269 | ## Values vs. References 270 | 271 | In GDScript, most all data is "passed by value". These variables make a copy during assignment. 272 | 273 | ```gdscript 274 | var v1 = Vector2() 275 | var v2 = v1 # copied! 276 | v1.x = 10 277 | # v2.x is still 0 278 | ``` 279 | 280 | However, every Object, Array, and Dictionary is "passed by reference". These variables create a shared "reference" to the same data during assignment. 281 | 282 | ```gdscript 283 | var n1 = Node.new() 284 | var n2 = n1 # referenced! 285 | n1.name = "MyNode" 286 | # n2.name is also "MyNode" now 287 | ``` 288 | 289 | In C++, the distinction between a value and a reference is not based on the data type, but rather the syntax. Furthermore, different data types are responsible for handling references versus values. 290 | 291 | ```cpp 292 | class SomeClass {}; 293 | 294 | SomeClass s1; // data type is SomeClass, a value 295 | SomeClass &s2 = s1; // data type is SomeClass&, a reference 296 | ``` 297 | 298 | The `&` modifies the type to be a reference to a SomeClass instance. C++ allows you to create these references for *any* data type, including integers. 299 | 300 | ```cpp 301 | int x = 0; 302 | int &y = x; // references x directly 303 | ``` 304 | 305 | `&` creates a reference to an *existing* value. It does not store the value's memory address, but it also does not work with literals which have no memory address. 306 | 307 | ```cpp 308 | int &x = 0; // error! References must be assigned an addressable value 309 | ``` 310 | 311 | References are *constant*. You can't make them reference something else once they've been initialized! Why is that? Because of the Stack... 312 | 313 | ```cpp 314 | int x = 0; 315 | int y = 0; 316 | int &z = x; 317 | z = &y; // error! References cannot be reassigned. 318 | ``` 319 | 320 | ## The Stack 321 | 322 | Whenever you use a function (`void func() { ... }`) or control flow (`if/else/for/do/while/switch/case { ... }`) 323 | 324 | ```cpp 325 | { 326 | 327 | } 328 | ``` 329 | 330 | 331 | 332 | Whenever you enter a new block of code, the computer sets aside a region of memory for you to use in that block called the Stack. As we discussed earlier, every GDScript variable is 20 bytes, so... 333 | 334 | ```gdscript 335 | var x = 1 336 | var y = 16 337 | var z = 256 338 | ``` 339 | 340 | ...looks like this in the Stack: 341 | 342 | ``` 343 | 184728300: 0x00001 344 | 184728320: 0x00010 345 | 184728340: 0x00100 346 | ``` 347 | 348 | The compiler knows that every GDScript variable is 20 bytes. Therefore, it always knows at which memory address to write the next variable's data.. 349 | 350 | Once you've established that a reference is refering to a symbol's memory address, it won't allow you to reset it to look at a different location, lest you change it and corrupt memory. 351 | 352 | The most important thing about memory, however, is how it gets reused! 353 | 354 | Say you define some variables in a block of code. When the block ends and you start a new block, your new segment of the Stack may overlap with the previous block's. The data written in memory for the old variables *may still be there*. 355 | 356 | In GDScript, everything is initialized for you, setting the old data to a default value. 357 | 358 | ```gdscript 359 | var x # always defaults to null 360 | var y: int # always defaults to 0 361 | ``` 362 | 363 | In C++, uninitialized variables will contain arbitrary trash from previous contexts. C++ will attempt to interpret those bits as if they were the variable's type, no matter what data type they were originally part of. 364 | 365 | ```cpp 366 | int x; // value is ?????. Was it an object? Who cares? Now it's an `int`. 367 | int y = 0; // value is 0 368 | ``` 369 | 370 | Therefore, for safety in C++, you must always initialize your data manually. 371 | 372 | ## Arrays 373 | 374 | In GDScript, `Array`s are a built-in class with their own methods. They can dynamically resize themselves to grow or shrink as needed. They can also store multiple data types. 375 | 376 | ```gdscript 377 | var arr := [] # Assignment using Array literal. 378 | var arr2 := Array() # Assignment using Array constructor. 379 | if arr == arr2: # They know how to compare against each other. 380 | print(arr.size()) # size() returns 0 381 | 382 | arr.append(10) # now size() returns 1 383 | 384 | arr.append("hello") # now contains integers AND strings 385 | 386 | ``` 387 | 388 | Not so in C++. Arrays are a primitive (non-class) data type. More importantly, the Stack needs to know, at compile time, where it needs to write the next variable's data. This means you have to declare ahead of time how much data is needed for every variable. 389 | 390 | In order to know the size of the array, you need to know the size of its elements. So, every element must be the same data type and there must be a fixed total capacity for the array. 391 | 392 | ```cpp 393 | // sizeof(int) == 4 394 | // capacity of array is 10 395 | // 4 bytes * 10 elements = 40 total bytes 396 | // Therefore, the 5 in `x` is written 40 bytes ahead of `arr`. 397 | int arr[10]; // type = `int[]`; capacity = 10; size = 0; 398 | arr[0] = 3; // size = 1 399 | int x = 5; 400 | ``` 401 | 402 | Unlike an `Array`, C++ arrays are given existing memory on the Stack. 403 | 404 | If you attempt to access data outside the bounds of the array, it doesn't loop around. Instead, accessing memory that doesn't belong to you will result in a fatal crash called a "segmentation fault". 405 | 406 | GDScript produces a runtime script error if you try to access a too-high index. But, a too-low index is interpreted as an intent to count backwards from the end. 407 | 408 | ```gdscript 409 | var arr := [4, 5, 6] 410 | arr[0] # 4 411 | arr[3] # error! 412 | arr[-1] # 6 413 | ``` 414 | 415 | ```cpp 416 | int arr[3]; 417 | arr[-1]; // crash 418 | arr[0]; // safe 419 | arr[1]; // safe 420 | arr[2]; // safe 421 | arr[3]; // crash 422 | ``` 423 | 424 | Because the exact size must be known at compile time, only literals and constants may be used to define the length of an array. 425 | 426 | ```cpp 427 | const int CAPACITY = 10; // `const int`. Immutable value (value is constant). 428 | int capacity = 10; // `int`. Mutable value (value can change). 429 | 430 | int arr[10]; // literal, compiles. 431 | int arr[CAPACITY]; // variable with immutable data type, compiles. 432 | int arr[capacity]; // variable with mutable data type, does not compile. 433 | ``` 434 | 435 | But wait! That can't be all there is, right? GDScript's `Array` can change its capacity. Why is that? Because of the Heap... 436 | 437 | ## Heap, and Pointers (TODO) 438 | 439 | The Heap is a region of memory that exists elsewhere in the computer. Where *exactly* the memory is generally unknown since the operating system micromanages it. An app can request memory from the Heap whenever it wants to at runtime. 440 | 441 | The Heap is not tied to a particular block of code. The memory will persist between code blocks until we manually free the memory. 442 | 443 | The good news? You can request a variable amount of data. Also, the memory is not part of a block, so the Stack can't remove it. 444 | 445 | The bad news? 446 | 447 | 448 | 449 | 450 | > Note: there is some ambiguity surrounding the term "reference". 451 | > - is a reference (reference) 452 | > - references (reference or pointer) 453 | > - pass by reference (reference or pointer) 454 | 455 | 456 | 457 | 458 | The `*` means we have a `uint64_t` (an unsigned 64-bit integer) which stores a memory address for a `SomeClass` instance. 459 | 460 | 461 | C++ calls these data types "pointers" 462 | 463 | ## Method Definitions (Basic) (TODO) (MOVE) 464 | 465 | In GDScript, a return value's data type and the parameters' data types are optional. In C++, they are required. Because they are required, they go before a parameter's symbol, not after. 466 | 467 | ```cpp 468 | class SomeClass { 469 | 470 | void print_hello() { 471 | print_line("Hello World!"); 472 | } 473 | 474 | int add(int a, int b) { 475 | return a + b; 476 | } 477 | }; 478 | ``` 479 | 480 | ```gdscript 481 | # some_class.gd 482 | func print_hello() -> void: 483 | print("Hello World!") 484 | 485 | 486 | func add(a: int, b: int) -> int: 487 | return a + b 488 | ``` 489 | 490 | ## Declarations vs Definitions 491 | 492 | In GDScript, every symbol is both a declaration that *a thing exists* and a definition of *what that thing is*. 493 | 494 | ```gdscript 495 | # node_a.gd, file exists (declaration), its content details definition 496 | extends Node 497 | 498 | # node_b.gd, file exists (declaration), its content details definition 499 | extends Node 500 | ``` 501 | 502 | But C++ is ultimately a procedural language. Definitions occur in order. 503 | 504 | ```cpp 505 | class A { 506 | B b; // error! Do not recognize class 'B'. 507 | } 508 | 509 | class B { 510 | A a; 511 | }; 512 | ``` 513 | 514 | The compiler will need to know how many bytes an instance of A uses. So it looks up the size of B. But if we haven't arrived at B's declaration, then we don't know what B is. 515 | 516 | Let's first "declare" that these types exist using a "forward declaration". Then we can "define" what they are later. This will tell the compiler to worry about how big they are until after it has catalogued the size of everything else. 517 | 518 | ```cpp 519 | // forward declarations 520 | class A; 521 | class B; 522 | 523 | class A { 524 | B b; 525 | } 526 | 527 | class B { 528 | A a; 529 | }; 530 | ``` 531 | 532 | This is how C++ handles circular dependency issues which GDScript 1.0 in Godot 3.x struggles with. 533 | 534 | ## Scopes 535 | 536 | A "scope" is a region of code where certain symbols exist. 537 | 538 | ### Local Scope 539 | 540 | Local variables only exist in a specific block and its nested blocks. This can often make the terms `scope` and `block` interchangeable *within local scopes*. 541 | 542 | C++ can create a new scope any time it wants with curly braces. 543 | 544 | ```cpp 545 | { 546 | // `x` symbol does not exist 547 | int x = 10; 548 | // `x` symbol now exists 549 | { 550 | int y = x; 551 | // `y` symbol now exists 552 | } 553 | // `y` symbol no longer exists 554 | } 555 | // `x` symbol no longer exists 556 | ``` 557 | 558 | GDScript uses indents to define new local scopes. It cannot create them directly. You must declare a method or use control flow to establish a new scope. 559 | 560 | ```gdscript 561 | func do(): 562 | # `x` symbol does not exist 563 | var x = 10 564 | # `x` symbol now exists 565 | if true: 566 | var y = x 567 | # `y` symbol now exists 568 | # `y` symbol no longer exists 569 | # `x` symbol no longer exists 570 | ``` 571 | 572 | ### Class Scope (TODO) 573 | 574 | Symbols which are available throughout a class. 575 | 576 | ```cpp 577 | class SomeClass { 578 | 579 | }; 580 | ``` 581 | 582 | ```gdscript 583 | var x = 10 584 | func do_one(): 585 | x += 5 # refers to `x` property 586 | func do_two(): 587 | x += 10 # also refers to `x` property 588 | ``` 589 | 590 | ### Global Scope 591 | 592 | Symbols which are available everywhere. 593 | 594 | GDScript does not give users write access to its global scope, but it does create a few read-only variables for users. 595 | 596 | - `GDNativeClass`, e.g. `Node`, `Resource`, `Object` 597 | - `Object` itself doesn't have a `.new()` method. GDScript creates fake classes with `.new()` which creates instances for users. 598 | - Engine Singletons, e.g. `Engine`, `OS`, etc. 599 | - Autoload Singletons (Node-extending scripts or scenes you configure in ProjectSettings) 600 | - Script Classes (scripts using the `class_name` keyword) 601 | 602 | In C++, everything is in global scope by default. To avoid putting things in global scope, one must wrap them in different scope. (Note: we'll go over function syntax later). 603 | 604 | C++ has a special term for the collection of symbols present certain scopes: a "namespace". 605 | 606 | ```cpp 607 | // A C++ function with a global variable. 608 | int x = 0; 609 | void do_nothing() { 610 | return 0; 611 | } 612 | ``` 613 | 614 | If a symbol occupies the global namespace, then C++ will not allow something else to use that symbol. This can quickly become a problem, so you should try to avoid it as much as possible. 615 | 616 | To not pollute the global namespace, we must move the global variable inside the function. 617 | 618 | ```cpp 619 | // A C++ function with a local variable. 620 | void do_nothing() { 621 | int x = 0; 622 | } 623 | ``` 624 | 625 | Uh oh! The `do_nothing` function is still in the global namespace. Put it in a class! 626 | 627 | ```cpp 628 | // A C++ class with a member function, i.e. a method. 629 | class SomeClass { 630 | public: 631 | void do_nothing() { 632 | int x = 0; 633 | } 634 | }; 635 | ``` 636 | 637 | That's better. But now `SomeClass` is in the global namespace. Can't we do something? 638 | 639 | Thankfully, C++ lets you create namespaces too. 640 | 641 | ```cpp 642 | // A C++ function with a local variable 643 | namespace Some { 644 | class SomeClass { 645 | public: 646 | void do_nothing() { 647 | int x = 0; 648 | } 649 | }; 650 | } 651 | ``` 652 | 653 | Now, let's access our `SomeClass`. 654 | 655 | ```cpp 656 | namespace Some { 657 | // ... 658 | } 659 | 660 | SomeClass some; // error! Do not recognize identifier 'SomeClass'. 661 | ``` 662 | 663 | C++ gives us an error saying it doesn't know of a `SomeClass` class. This is because we are doing so outside of the namespace. Our mention of `SomeClass` tries to find it in the global namespace. To look inside the `Some` namespace, we must use the `::` "scope operator". 664 | 665 | ```cpp 666 | Some::SomeClass some; 667 | ``` 668 | 669 | This is analogous to trying to access an inner class from outside of a GDScript. 670 | 671 | ```gdscript 672 | # list.gd 673 | class Element: 674 | pass 675 | 676 | # some_class.gd 677 | const List = preload("list.gd") 678 | var element = Element.new() # error! Do not recognize 'Element'. 679 | var element = List.Element.new() # works! 680 | ``` 681 | 682 | ## Static (TODO) 683 | 684 | You use the scope operator whenever you must access something in a "static" context. That is, a context belonging to a namespace or class. 685 | 686 | ## What's an API? Source Files vs. Header Files 687 | 688 | There's another reason that C++ might use declarations in place of definitions. 689 | 690 | The bigger an application gets, the longer you have to wait for C++ code to compile in order to test your code. But what if a change doesn't affect other parts of your code? 691 | 692 | ```cpp 693 | // number.cpp 694 | 695 | int get_number() { 696 | return 5; 697 | } 698 | 699 | // double.cpp 700 | #include "number.cpp" 701 | int double_number() { 702 | return 2 * get_number(); 703 | } 704 | ``` 705 | 706 | > We'll get to `#include` later. For now, know that it copy/pastes the other file's contents into the current file. 707 | 708 | If you compile the `double.cpp` file, it will have both the `get_number` and `double_number` functions. 709 | 710 | If you change `get_number` to return 10 instead of 5, the compiler *still* recompiles the entire file, including the `double_number` function. But, `double_number`'s logic is completely unchanged. Can we avoid that? 711 | 712 | Languages expose a collection of "language entities": 713 | 714 | - global variables and functions 715 | - namespaces 716 | - classes 717 | - properties (class variables) 718 | - methods (class functions) 719 | 720 | The sum of all language entities which enable a programmer to use a piece of software are called the Application Programmer Interface or API. 721 | 722 | When it comes to functions in an API, there is a big distinction between declarations and definitions. If the function signature is unchanged, then changing the implementation of that function's definition has no effect on the API. Therefore, only the implementation needs to be recompiled. 723 | 724 | ```cpp 725 | // number.h 726 | int get_number(); // forward declare that we want this function here in memory. 727 | 728 | // number.cpp 729 | #include "number.h" 730 | int get_number() { // define what the function should do 731 | return 10; 732 | } 733 | 734 | // double.cpp 735 | #include "number.h" 736 | int double_number() { 737 | return 2 * get_number(); // still references same function start in memory. 738 | } 739 | ``` 740 | 741 | When you call a function, the CPU must jump to that location in memory and begin executing the logic there. But if the memory address doesn't need to recompile, then the things *referencing* that function's memory address also do not need to recompile. 742 | 743 | `double.cpp` only includes the `.h` header file containing the declarations. As a result, so long as those don't change, recompiling `double.cpp` is unnecessary. When executing `double_number`, the compiler will still need to 744 | 745 | When you do the same thing for classes, you must combine header file and source file separation with the lessons you learned about scope access. 746 | 747 | ```cpp 748 | // number.h 749 | class Number { 750 | public: 751 | int get_value(); 752 | } 753 | 754 | // number.cpp 755 | #include "number.h" 756 | int Number::get_value() { // symbol 'get_value' belongs to the 'Number' scope 757 | return 10; 758 | } 759 | 760 | // double.cpp 761 | #include "number.h" 762 | int double_number(Number n) { 763 | return 2 * n.get_value(); 764 | } 765 | ``` 766 | 767 | ## Virtuals, Abstract Classes, and Overrides (TODO) 768 | 769 | ```cpp 770 | 771 | ``` 772 | 773 | ```gdscript 774 | 775 | ``` 776 | 777 | ## Function Overloads (TODO) 778 | 779 | ```cpp 780 | 781 | ``` 782 | 783 | ```gdscript 784 | 785 | ``` 786 | 787 | ## Control Flow: If/Else (TODO) 788 | 789 | ## Control Flow: Switch/Case (TODO) 790 | 791 | ## Control Flow: While/Do-While Loop (TODO) 792 | 793 | ## Control Flow: For Loop (Array) (TODO) 794 | 795 | ```cpp 796 | 797 | ``` 798 | 799 | ```gdscript 800 | 801 | ``` 802 | 803 | ## Control Flow: For Loop (Vector) (TODO) 804 | 805 | ```cpp 806 | 807 | ``` 808 | 809 | ```gdscript 810 | 811 | ``` 812 | 813 | ## ControlFlow: For Loop (List) (TODO) 814 | 815 | ```cpp 816 | 817 | ``` 818 | 819 | ```gdscript 820 | 821 | ``` 822 | 823 | (WIP, section below is obsolete. Keeping temporarily for reference) 824 | 825 | ```cpp 826 | // some_class.h 827 | class SomeClass { 828 | public: 829 | virtual ISomeType *get_value() const = 0; 830 | virtual ISomeType *get_value() const override { return nullptr; } 831 | }; 832 | 833 | // class declaration 834 | class SomeClass { ... }; 835 | 836 | // "access modifier": whether other classes can access the variable/method. 837 | class SomeClass { 838 | private: 839 | int _x; // only available inside class. GDScript just uses `_` convention. 840 | protected: 841 | int _y; // only available in this or extended classes. 842 | public: 843 | int z; // available everywhere. This is the only option in GDScript. 844 | }; 845 | 846 | // basic function signature: 847 | // ( param1, param2); 848 | // ReturnType: ISomeType * 849 | // MethodName: get_value 850 | // ParameterList: () 851 | ISomeType *get_value(); 852 | 853 | // advanced function signature: 854 | // `virtual`: can be overridden by a derived class. Always in GDScript. 855 | // `*`: handling a data type by reference. Similar to Object/Array/Dictionary. 856 | // `const`: This function makes no changes to the Object it belongs to. 857 | // `= 0`: There is no implementation of this function. Class is abstract. Cannot instantiate. 858 | virtual ISomeType *get_value() const = 0; 859 | 860 | // advanced function signature (continued): 861 | // `virtual`: part of an overridden method hierarchy. Always in GDScript. 862 | // `override`: this method IS overriding an inherited method. 863 | // `nullptr`: This is GDScript's `null`. The `ptr` stands for "pointer". 864 | virtual ISomeType *get_value() const override { return nullptr; } 865 | ``` 866 | 867 | Now, for the actual example. 868 | 869 | ```cpp 870 | // iparentable.h 871 | class IParentable { 872 | public: 873 | virtual IParentable *get_parent() const = 0; 874 | virtual void get_children(List *r_children) const = 0; 875 | }; 876 | 877 | // parentable_object.h 878 | #include "iparentable.h" 879 | class ParentableObject : public Object, public IParentable { 880 | // 881 | public: 882 | virtual IParentable *get_parent() const override { return nullptr; } 883 | virtual void get_children(List *r_children) const override {} 884 | }; 885 | 886 | // parentable_resource.h 887 | #include "iparentable.h" 888 | class ParentableResource : public Resource, public IParentable { 889 | IParentable *_parent; 890 | List _children; 891 | public: 892 | virtual IParentable *get_parent() const override { 893 | return _parent; 894 | } 895 | virtual void get_children(List *r_children) const override { 896 | for (const List::Element *E = _children.front(); E; E = E->next()) { 897 | r_children->push_back(E->get()); 898 | } 899 | } 900 | }; 901 | // # list.gd 902 | // class_name List 903 | // class Element: 904 | // extends Reference 905 | // for (starting condition; iteration condition; iteration operation) { 906 | 907 | // } 908 | // for elem in list.children: 909 | 910 | // uses_awesome_parent.h 911 | class UsesAwesomeParent : public Node { 912 | public: 913 | void my_func() { 914 | Node *n = get_node("/root/DataStoreSingleton"); 915 | if (!n) { 916 | return; 917 | } 918 | 919 | DataStore *dataStore = Object::cast_to(n); 920 | if (!dataStore) { 921 | return; 922 | } 923 | 924 | IParentable *data = Object::cast_to(dataStore->get_data()); 925 | if (!data) { 926 | return; 927 | } 928 | 929 | IParentable *p = data->get_parent(); 930 | 931 | List c; 932 | data->get_children(&c); 933 | } 934 | }; 935 | ``` 936 | 937 | Note that, with C++, the relationship with the interface must be explicit. Just because the `Node` class has `get_parent` and `get_children` methods doesn't mean it conforms to the `IParentable` interface. You would need to modify the definition of the `Node` class to explicitly have it implement the `IParentable` interface. 938 | 939 | In contrast, because GDScript is duck-typed, it would allow a `Node` to be used in place of a `ParentableObject` / `ParentableResource` for these purposes just fine. 940 | 941 | Note though that, in practice, making nodes an `IParentable` or using `IParentable`s where a `Node` is expected would be problematic. After all, `Node` can do a lot more, so things expecting a `Node` would want more from an `IParentable`. However, the idea of exposing a subset of class features via an interface is useful in contexts where the code *only cares* about *that interface* and no other features. 942 | 943 | To have a truly extensible codebase, you'd have to redesign `Node` so that each of its various features were bound to an interface which any given class could implement. Why doesn't Godot do this? Because breaking down `Node`'s features to such a degree of precision would add unnecessary complication to the engine's design. 944 | -------------------------------------------------------------------------------- /interfaces_in_gdscript.md: -------------------------------------------------------------------------------- 1 | # Interfaces In GDScript 2 | 3 | ## **OBSOLETE: Will be merged into gdscript_to_cpp.md later.** 4 | 5 | A practical explanation of interfaces for beginners. 6 | 7 | ## Concepts 8 | 9 | What is an interface? 10 | 11 | It's a contract where a class agrees to define a set of function signatures. 12 | 13 | What is a function signature? 14 | 15 | It's the combination of the function's... 16 | 17 | - name 18 | - return data type 19 | - number of parameters 20 | - parameter data types 21 | 22 | ## Purpose 23 | 24 | The reason you would want to rely on interfaces in software architecture is because it keeps your code "loosely coupled" to other parts of the codebase. This makes it easier to adapt to changes in requirements or usage. Your code can change shape without breaking the program and without creating bugs. 25 | 26 | This means you can make changes faster. Iteration increases and you save time and money. It also makes it easier to work *with* your code so that others feel more comfortable joining your team. Not driving yourself insane is another plus. 27 | 28 | ## Duck-Typed Interfaces In GDScript 29 | 30 | Let's say we want to store data for our game. We like the tree structure of nodes to organize our data, but Nodes are big. They use more memory than Objects and Resources. Can we add a Node-like structure to other types? 31 | 32 | Godot Engine supports a similar idea with its `Tree` class and its internal `TreeItem` Object types. It isn't an interface, but it *is* a non-Node Object that supports a hierarchical structure. 33 | 34 | For our case, we could have an IParentable interface that defines the methods below: 35 | 36 | ```gdscript 37 | func get_parent() -> Object: 38 | pass 39 | func get_children() -> Array: 40 | pass 41 | ``` 42 | 43 | We have a "set of function signatures" that must be defined in a class. 44 | 45 | We've detailed the names they must have, what parameters they must accept, and what data type they must return. 46 | 47 | Note that the sample is just a pair of methods. It is *not* an actual script file. 48 | 49 | Now for concrete implementations of the interface, they just have to implement those same methods. 50 | 51 | ```gdscript 52 | # duck-typed interface. Works off function names. 53 | # The existence of the interface is implied by the functions' use. 54 | 55 | # parentable_object.gd 56 | extends Object 57 | 58 | func get_parent() -> Object: 59 | return null 60 | 61 | 62 | func get_children() -> Array: 63 | return [] 64 | 65 | # parentable_resource.gd 66 | extends Resource 67 | 68 | export var _parent: Object = null 69 | export var _children := [] 70 | 71 | func get_parent() -> Object: 72 | return _parent 73 | 74 | 75 | func get_children() -> Array: 76 | return _children 77 | 78 | # uses_parentable.gd 79 | extends Node 80 | 81 | func my_func() -> void: 82 | var data = DataStoreSingleton.get_data() 83 | 84 | # BAD - we've filtered out the Object version! 85 | if data is Resource: 86 | var p = data.get_parent() 87 | var c = data.get_children() 88 | 89 | # Note: cannot verify signature, only name. 90 | var is_iparentable = (data.has_method("get_parent") 91 | and data.has_method("get_children")) 92 | 93 | # If error, silently fails, but continues 94 | if is_iparentable: 95 | var p = data.get_parent() 96 | var c = data.get_children() 97 | 98 | # If error, loudly fails, but continues 99 | if is_iparentable: 100 | var p = data.get_parent() 101 | var c = data.get_children() 102 | else: 103 | push_error("'data' is does not implement the IParentable interface") 104 | 105 | # If error, loudly fails and crashes 106 | var p = data.get_parent() 107 | var c = data.get_children() 108 | ``` 109 | 110 | ## Conclusion 111 | 112 | GDScript has different degrees to which it can satisfy an interface. However, nothing is guaranteed at parse-time. You are limited to basic inheritance with static typing or checking method names. 113 | -------------------------------------------------------------------------------- /repo_organization.md: -------------------------------------------------------------------------------- 1 | # Godot Repository Organization 2 | 3 | A summary of the overall structure of the source code. 4 | 5 | ## High-Level Overview 6 | 7 | As a sequence of digestible chunks, the directories are organized like this: 8 | 9 | - "Project": 10 | - `/`: Build config. C++ config. Git config. 11 | - `/tests`: Unit tests. 12 | - `/debug`: Logs. 13 | - `/doc`: XML API docs. 14 | - `/logs`: More logs. 15 | - `/misc`: Tons of random junk. 16 | - `/misc/ci`: Continuous Integration config 17 | - `/misc/dist`: Distribution-specific files. HTML wrappers. Some icons. 18 | - `/misc/hooks`: Git hooks. Automates script exec before/after git operations. 19 | - `/misc/scons`: Godot-specific scons dependencies. 20 | - `/misc/scripts`: Helper scripts for the Godot project. 21 | - "Core": 22 | - `/thirdparty`: FOSS libraries that Godot uses. 23 | - Gives Godot access to work made by others. 24 | - `/drivers`: Godot-specific wrappers for `/thirdparty` and system stuff. 25 | - Gives Godot access to hardware on a platform. 26 | - `/core`: main data structures, libraries, and interfaces. 27 | - Gives Godot a foundation of common features for other sections. 28 | - Defines core OS interface. 29 | - `/platform`: Defines per-platform OS impls and entry points. 30 | - Scons builds engine for each platform based on these dir names. 31 | - Any shared platform code is in `/drivers` (unix OS). 32 | - `/servers`: Low-level, high-performance interfaces and impls, threaded. 33 | - Has rendering, physics, audio, window mgmt, nav, camera, XR. 34 | - `/scene`: High-level game framework using `/core` and `/servers`. 35 | - Has SceneTree, Node/Node2D/Spatial, etc. Configures low-level ops. 36 | - `/main`: Common platform ops. Setup. Start. Iteration. Cleanup. 37 | - Also handles cmdline args 38 | - "Editor": 39 | - `/editor`: A C++-only Godot "game" with elevated privileges (tool mode). 40 | - Must only be dependent on "Core". No reference to `/modules`. 41 | - "Modules": 42 | - `/modules`: Optional features appended to Godot Engine and/or Editor. 43 | - If a module needs Editor, wrap in `#ifdef TOOLS_ENABLED`. 44 | - If a module needs module, refactor to submodules (e.g. gdnative). 45 | 46 | ## 80% Accurate Dependency Tree 47 | 48 | Dependencies between sections exist, but the code is similar to this: 49 | 50 | - "Project": 51 | - `/` 52 | - "Core": 53 | - `/main` 54 | - `/core` 55 | - `/scene` 56 | - `/platform` 57 | - `/drivers` 58 | - `/thirdparty` 59 | - `/servers` 60 | - `/drivers` 61 | - "Editor": 62 | - `/editor` 63 | - "Core" 64 | - "Modules": 65 | - `/modules` 66 | - "Core" 67 | - "Editor" 68 | - `/thirdparty` 69 | 70 | ## Low-Level Breakdown 71 | 72 | A detailed summary of how each directory relates to the project. 73 | 74 | - `/core`: 75 | - Description: 76 | - Basic data structures and algorithms. 77 | - Defines the core API for every Godot concept. 78 | - Low-level interfaces for use in other parts of Godot. 79 | - Variant 80 | - "Built-In" data types, e.g. Transform, String, Callable 81 | - Object, Reference, and Resource 82 | - ClassDB, [Property|Method|Signal]Info (Reflection system) 83 | - Scripting 84 | - Networking 85 | - IO 86 | - Core Engine Singletons 87 | - Dependencies: 88 | - `/server`: just RenderingServer for debugging 89 | - `/scene`: Nodes and Resources via forward declarations 90 | - Used By: 91 | Everything except `/thirdparty`. 92 | - `/platform`: 93 | - Description: 94 | - Defines OS singleton implementations. 95 | - Defines entry points for each platform. Uses a common Main class. 96 | - Most OS-specific logic is handled here. Exception listed in Used By. 97 | - Dependencies: 98 | - `/core`: basic dependencies 99 | - `/drivers`: OS library dependencies 100 | - `/servers`: audio/rendering/window integrations 101 | - Used By: 102 | - `/servers`: concrete OS-specific DisplayServer impls 103 | - `/modules`: optional features: module interface, submodule impls 104 | - `/drivers`: 105 | - Description: 106 | - Defines wrappers for local APIs that may be shared between platforms. 107 | - Dependencies: 108 | - `/core`: Basic dependencies 109 | - `/servers`: Vulkan uses DisplayServer info 110 | - extern local OS dependencies 111 | - Used By: 112 | - `/platform`: OS library dependencies 113 | - `/editor`: 114 | - Description: 115 | - Defines the Godot Editor and its various subsystems. 116 | - Defines C++ EditorPlugin tools for anything in core, scene, etc. 117 | - Dependencies: 118 | - `/core`: Basic dependencies, UndoRedo 119 | - `/scene`: SceneTree, Node, Control, PackedScene, other nodes/resources 120 | - `/servers`: config, res mgmt, preview, window mgmt, debugging, settings 121 | - Used By: 122 | - `/modules`: EditorPlugins, protected by #ifdef TOOLS_ENABLED 123 | - `/main`: 124 | - Description: 125 | - Defines the Main class. Boots up engine. Handles cmdline args. 126 | - Dependencies: 127 | - `/core`: Basic dependencies, type registration) 128 | - `/drivers`: type registration 129 | - `/modules`: type registration 130 | - `/platform`: type registration 131 | - `/scene`: SceneTree, Window, PackedScene, type registration 132 | - `/servers`: initialization, type registration 133 | - `/editor`: project manager, editor, docs generation 134 | - `/tests`: run unit tests upon request 135 | - Used By: 136 | None 137 | - `/scene`: 138 | - Description: 139 | - Defines all objects/nodes/resources that are not required by /core. 140 | - Usage in other spaces is pretty self-explanatory. 141 | - Dependencies: 142 | - `/core`: Basic dependencies 143 | - `/servers`: access low-level APIs 144 | - Used By: 145 | - `/core`: Resource, Variant, other helpers with forward declarations 146 | - `/servers`: various Resources 147 | - `/editor`: tons of nodes/resources/etc. 148 | - `/modules`: tons of nodes/resources/etc. 149 | - `/servers`: 150 | - Description: 151 | - Defines low-level Server interfaces. 152 | - Defines dependent Resources in some cases. 153 | - Defines concrete implementations of Server interfaces. 154 | - If multiple, either context-specific and auto-selected (2D/3D) or users are given the option to choose (e.g. Vulkan/GLES3). 155 | - Dependencies: 156 | - `/core`: basic dependencies 157 | - `/scene`: dependent resource types 158 | - Used By: 159 | - `/core`: grant friend access, window mgmt 160 | - `/drivers`: loosely used in wrapper code, e.g. DisplayServer::WindowID 161 | - `/editor`: config, res mgmt, preview, window mgmt, debugging, settings, etc. 162 | - `/main`: initialization, monitors, cmdline args config 163 | - `/scene`: usage in nodes/resources, etc. 164 | - `/modules`: usage in nodes/resources 165 | - Also platform-specific implementations for optional features 166 | - An increasing trend to use modules for implementations of Server 167 | interfaces? 168 | - Implementation of GdNavigationServer 169 | - Implementation of XRInterface for mobile and gdnative 170 | - `/thirdparty`: 171 | - Description: 172 | Directly imports the source code of third-party libraries. 173 | - Dependencies: 174 | None 175 | - Used By: 176 | - `/modules`: integration 177 | - `/drivers`: integration 178 | - `/modules`: 179 | - Description: 180 | Defines optional features which can easily be added or removed from 181 | both the engine and the editor during compilation. 182 | - Dependencies: 183 | Everything 184 | - Used By: 185 | None --------------------------------------------------------------------------------