gdscript_advanced.rst 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. .. _doc_gdscript_more_efficiently:
  2. GDScript: An introduction to dynamic languages
  3. ==============================================
  4. About
  5. -----
  6. This tutorial aims to be a quick reference for how to use GDScript more
  7. efficiently. It focuses on common cases specific to the language, but
  8. also covers a lot of information on dynamically typed languages.
  9. It's meant to be especially useful for programmers with little or no previous
  10. experience with dynamically typed languages.
  11. Dynamic nature
  12. --------------
  13. Pros & cons of dynamic typing
  14. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  15. GDScript is a Dynamically Typed language. As such, its main advantages
  16. are that:
  17. - The language is easy to get started with.
  18. - Most code can be written and changed quickly and without hassle.
  19. - The code is easy to read (little clutter).
  20. - No compilation is required to test.
  21. - Runtime is tiny.
  22. - It has duck-typing and polymorphism by nature.
  23. While the main disadvantages are:
  24. - Less performance than statically typed languages.
  25. - More difficult to refactor (symbols can't be traced).
  26. - Some errors that would typically be detected at compile time in
  27. statically typed languages only appear while running the code
  28. (because expression parsing is more strict).
  29. - Less flexibility for code-completion (some variable types are only
  30. known at runtime).
  31. This, translated to reality, means that Godot used with GDScript is a combination
  32. designed to create games quickly and efficiently. For games that are very
  33. computationally intensive and can't benefit from the engine built-in
  34. tools (such as the Vector types, Physics Engine, Math library, etc), the
  35. possibility of using C++ is present too. This allows you to still create most of the
  36. game in GDScript and add small bits of C++ in the areas that need
  37. a performance boost.
  38. Variables & assignment
  39. ~~~~~~~~~~~~~~~~~~~~~~
  40. All variables in a dynamically typed language are "variant"-like. This
  41. means that their type is not fixed, and is only modified through
  42. assignment. Example:
  43. Static:
  44. .. code-block:: cpp
  45. int a; // Value uninitialized.
  46. a = 5; // This is valid.
  47. a = "Hi!"; // This is invalid.
  48. Dynamic:
  49. ::
  50. var a # 'null' by default.
  51. a = 5 # Valid, 'a' becomes an integer.
  52. a = "Hi!" # Valid, 'a' changed to a string.
  53. As function arguments:
  54. ~~~~~~~~~~~~~~~~~~~~~~
  55. Functions are of dynamic nature too, which means they can be called with
  56. different arguments, for example:
  57. Static:
  58. .. code-block:: cpp
  59. void print_value(int value) {
  60. printf("value is %i\n", value);
  61. }
  62. [..]
  63. print_value(55); // Valid.
  64. print_value("Hello"); // Invalid.
  65. Dynamic:
  66. ::
  67. func print_value(value):
  68. print(value)
  69. [..]
  70. print_value(55) # Valid.
  71. print_value("Hello") # Valid.
  72. Pointers & referencing:
  73. ~~~~~~~~~~~~~~~~~~~~~~~
  74. In static languages, such as C or C++ (and to some extent Java and C#),
  75. there is a distinction between a variable and a pointer/reference to a
  76. variable. The latter allows the object to be modified by other functions
  77. by passing a reference to the original one.
  78. In C# or Java, everything not a built-in type (int, float, sometimes
  79. String) is always a pointer or a reference. References are also
  80. garbage-collected automatically, which means they are erased when no
  81. longer used. Dynamically typed languages tend to use this memory model,
  82. too. Some Examples:
  83. - C++:
  84. .. code-block:: cpp
  85. void use_class(SomeClass *instance) {
  86. instance->use();
  87. }
  88. void do_something() {
  89. SomeClass *instance = new SomeClass; // Created as pointer.
  90. use_class(instance); // Passed as pointer.
  91. delete instance; // Otherwise it will leak memory.
  92. }
  93. - Java:
  94. .. code-block:: java
  95. @Override
  96. public final void use_class(SomeClass instance) {
  97. instance.use();
  98. }
  99. public final void do_something() {
  100. SomeClass instance = new SomeClass(); // Created as reference.
  101. use_class(instance); // Passed as reference.
  102. // Garbage collector will get rid of it when not in
  103. // use and freeze your game randomly for a second.
  104. }
  105. - GDScript:
  106. ::
  107. func use_class(instance): # Does not care about class type
  108. instance.use() # Will work with any class that has a ".use()" method.
  109. func do_something():
  110. var instance = SomeClass.new() # Created as reference.
  111. use_class(instance) # Passed as reference.
  112. # Will be unreferenced and deleted.
  113. In GDScript, only base types (int, float, string and the vector types)
  114. are passed by value to functions (value is copied). Everything else
  115. (instances, arrays, dictionaries, etc) is passed as reference. Classes
  116. that inherit :ref:`class_RefCounted` (the default if nothing is specified)
  117. will be freed when not used, but manual memory management is allowed too
  118. if inheriting manually from :ref:`class_Object`.
  119. Arrays
  120. ------
  121. Arrays in dynamically typed languages can contain many different mixed
  122. datatypes inside and are always dynamic (can be resized at any time).
  123. Compare for example arrays in statically typed languages:
  124. .. code-block:: cpp
  125. int *array = new int[4]; // Create array.
  126. array[0] = 10; // Initialize manually.
  127. array[1] = 20; // Can't mix types.
  128. array[2] = 40;
  129. array[3] = 60;
  130. // Can't resize.
  131. use_array(array); // Passed as pointer.
  132. delete[] array; // Must be freed.
  133. // or
  134. std::vector<int> array;
  135. array.resize(4);
  136. array[0] = 10; // Initialize manually.
  137. array[1] = 20; // Can't mix types.
  138. array[2] = 40;
  139. array[3] = 60;
  140. array.resize(3); // Can be resized.
  141. use_array(array); // Passed reference or value.
  142. // Freed when stack ends.
  143. And in GDScript:
  144. ::
  145. var array = [10, "hello", 40, 60] # You can mix types.
  146. array.resize(3) # Can be resized.
  147. use_array(array) # Passed as reference.
  148. # Freed when no longer in use.
  149. In dynamically typed languages, arrays can also double as other
  150. datatypes, such as lists:
  151. ::
  152. var array = []
  153. array.append(4)
  154. array.append(5)
  155. array.pop_front()
  156. Or unordered sets:
  157. ::
  158. var a = 20
  159. if a in [10, 20, 30]:
  160. print("We have a winner!")
  161. Dictionaries
  162. ------------
  163. Dictionaries are a powerful tool in dynamically typed languages. In
  164. GDScript, untyped dictionaries can be used for many cases where a statically
  165. typed language would tend to use another data structure.
  166. Dictionaries can map any value to any other value with complete
  167. disregard for the datatype used as either key or value. Contrary to
  168. popular belief, they are efficient because they can be implemented
  169. with hash tables. They are, in fact, so efficient that some languages
  170. will go as far as implementing arrays as dictionaries.
  171. Example of Dictionary:
  172. ::
  173. var d = {"name": "John", "age": 22}
  174. print("Name: ", d["name"], " Age: ", d["age"])
  175. Dictionaries are also dynamic, keys can be added or removed at any point
  176. at little cost:
  177. ::
  178. d["mother"] = "Rebecca" # Addition.
  179. d["age"] = 11 # Modification.
  180. d.erase("name") # Removal.
  181. In most cases, two-dimensional arrays can often be implemented more
  182. easily with dictionaries. Here's a battleship game example:
  183. ::
  184. # Battleship Game
  185. const SHIP = 0
  186. const SHIP_HIT = 1
  187. const WATER_HIT = 2
  188. var board = {}
  189. func initialize():
  190. board[Vector2(1, 1)] = SHIP
  191. board[Vector2(1, 2)] = SHIP
  192. board[Vector2(1, 3)] = SHIP
  193. func missile(pos):
  194. if pos in board: # Something at that position.
  195. if board[pos] == SHIP: # There was a ship! hit it.
  196. board[pos] = SHIP_HIT
  197. else:
  198. print("Already hit here!") # Hey dude you already hit here.
  199. else: # Nothing, mark as water.
  200. board[pos] = WATER_HIT
  201. func game():
  202. initialize()
  203. missile(Vector2(1, 1))
  204. missile(Vector2(5, 8))
  205. missile(Vector2(2, 3))
  206. Dictionaries can also be used as data markup or quick structures. While
  207. GDScript's dictionaries resemble python dictionaries, it also supports Lua
  208. style syntax and indexing, which makes it useful for writing initial
  209. states and quick structs:
  210. ::
  211. # Same example, lua-style support.
  212. # This syntax is a lot more readable and usable.
  213. # Like any GDScript identifier, keys written in this form cannot start
  214. # with a digit.
  215. var d = {
  216. name = "John",
  217. age = 22
  218. }
  219. print("Name: ", d.name, " Age: ", d.age) # Used "." based indexing.
  220. # Indexing
  221. d["mother"] = "Rebecca"
  222. d.mother = "Caroline" # This would work too to create a new key.
  223. For & while
  224. -----------
  225. Iterating using the C-style for loop in C-derived languages can be quite complex:
  226. .. code-block:: cpp
  227. const char** strings = new const char*[50];
  228. [..]
  229. for (int i = 0; i < 50; i++) {
  230. printf("Value: %c Index: %d\n", strings[i], i);
  231. }
  232. // Even in STL:
  233. std::list<std::string> strings;
  234. [..]
  235. for (std::string::const_iterator it = strings.begin(); it != strings.end(); it++) {
  236. std::cout << *it << std::endl;
  237. }
  238. Because of this, GDScript makes the opinionated decision to have a for-in loop over iterables instead:
  239. ::
  240. for s in strings:
  241. print(s)
  242. Container datatypes (arrays and dictionaries) are iterable. Dictionaries
  243. allow iterating the keys:
  244. ::
  245. for key in dict:
  246. print(key, " -> ", dict[key])
  247. Iterating with indices is also possible:
  248. ::
  249. for i in range(strings.size()):
  250. print(strings[i])
  251. The range() function can take 3 arguments:
  252. ::
  253. range(n) # Will count from 0 to n in steps of 1. The parameter n is exclusive.
  254. range(b, n) # Will count from b to n in steps of 1. The parameters b is inclusive. The parameter n is exclusive.
  255. range(b, n, s) # Will count from b to n, in steps of s. The parameters b is inclusive. The parameter n is exclusive.
  256. Some examples involving C-style for loops:
  257. .. code-block:: cpp
  258. for (int i = 0; i < 10; i++) {}
  259. for (int i = 5; i < 10; i++) {}
  260. for (int i = 5; i < 10; i += 2) {}
  261. Translate to:
  262. ::
  263. for i in range(10):
  264. pass
  265. for i in range(5, 10):
  266. pass
  267. for i in range(5, 10, 2):
  268. pass
  269. And backwards looping done through a negative counter:
  270. ::
  271. for (int i = 10; i > 0; i--) {}
  272. Becomes:
  273. ::
  274. for i in range(10, 0, -1):
  275. pass
  276. While
  277. -----
  278. while() loops are the same everywhere:
  279. ::
  280. var i = 0
  281. while i < strings.size():
  282. print(strings[i])
  283. i += 1
  284. Custom iterators
  285. ----------------
  286. You can create custom iterators in case the default ones don't quite meet your
  287. needs by overriding the Variant class's ``_iter_init``, ``_iter_next``, and ``_iter_get``
  288. functions in your script. An example implementation of a forward iterator follows:
  289. ::
  290. class ForwardIterator:
  291. var start
  292. var current
  293. var end
  294. var increment
  295. func _init(start, stop, increment):
  296. self.start = start
  297. self.current = start
  298. self.end = stop
  299. self.increment = increment
  300. func should_continue():
  301. return (current < end)
  302. func _iter_init(arg):
  303. current = start
  304. return should_continue()
  305. func _iter_next(arg):
  306. current += increment
  307. return should_continue()
  308. func _iter_get(arg):
  309. return current
  310. And it can be used like any other iterator:
  311. ::
  312. var itr = ForwardIterator.new(0, 6, 2)
  313. for i in itr:
  314. print(i) # Will print 0, 2, and 4.
  315. Make sure to reset the state of the iterator in ``_iter_init``, otherwise nested
  316. for-loops that use custom iterators will not work as expected.
  317. Duck typing
  318. -----------
  319. One of the most difficult concepts to grasp when moving from a
  320. statically typed language to a dynamic one is duck typing. Duck typing
  321. makes overall code design much simpler and straightforward to write, but
  322. it's not obvious how it works.
  323. As an example, imagine a situation where a big rock is falling down a
  324. tunnel, smashing everything on its way. The code for the rock, in a
  325. statically typed language would be something like:
  326. .. code-block:: cpp
  327. void BigRollingRock::on_object_hit(Smashable *entity) {
  328. entity->smash();
  329. }
  330. This way, everything that can be smashed by a rock would have to
  331. inherit Smashable. If a character, enemy, piece of furniture, small rock
  332. were all smashable, they would need to inherit from the class Smashable,
  333. possibly requiring multiple inheritance. If multiple inheritance was
  334. undesired, then they would have to inherit a common class like Entity.
  335. Yet, it would not be very elegant to add a virtual method ``smash()`` to
  336. Entity only if a few of them can be smashed.
  337. With dynamically typed languages, this is not a problem. Duck typing
  338. makes sure you only have to define a ``smash()`` function where required
  339. and that's it. No need to consider inheritance, base classes, etc.
  340. ::
  341. func _on_object_hit(object):
  342. object.smash()
  343. And that's it. If the object that hit the big rock has a smash() method,
  344. it will be called. No need for inheritance or polymorphism. Dynamically
  345. typed languages only care about the instance having the desired method
  346. or member, not what it inherits or the class type. The definition of
  347. Duck Typing should make this clearer:
  348. *"When I see a bird that walks like a duck and swims like a duck and
  349. quacks like a duck, I call that bird a duck"*
  350. In this case, it translates to:
  351. *"If the object can be smashed, don't care what it is, just smash it."*
  352. Yes, we should call it Hulk typing instead.
  353. It's possible that the object being hit doesn't have a smash() function.
  354. Some dynamically typed languages simply ignore a method call when it
  355. doesn't exist, but GDScript is stricter, so checking if the function
  356. exists is desirable:
  357. ::
  358. func _on_object_hit(object):
  359. if object.has_method("smash"):
  360. object.smash()
  361. Then, define that method and anything the rock touches can be smashed.