godot_interfaces.rst 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. .. _doc_godot_interfaces:
  2. Godot interfaces
  3. ================
  4. Often one needs scripts that rely on other objects for features. There
  5. are 2 parts to this process:
  6. 1. Acquiring a reference to the object that presumably has the features.
  7. 2. Accessing the data or logic from the object.
  8. The rest of this tutorial outlines the various ways of doing all this.
  9. Acquiring object references
  10. ---------------------------
  11. For all :ref:`Object <class_Object>`\s, the most basic way of referencing them
  12. is to get a reference to an existing object from another acquired instance.
  13. .. tabs::
  14. .. code-tab:: gdscript GDScript
  15. var obj = node.object # Property access.
  16. var obj = node.get_object() # Method access.
  17. .. code-tab:: csharp
  18. GodotObject obj = node.Object; // Property access.
  19. GodotObject obj = node.GetObject(); // Method access.
  20. The same principle applies for :ref:`RefCounted <class_RefCounted>` objects.
  21. While users often access :ref:`Node <class_Node>` and
  22. :ref:`Resource <class_Resource>` this way, alternative measures are available.
  23. Instead of property or method access, one can get Resources by load
  24. access.
  25. .. tabs::
  26. .. code-tab:: gdscript GDScript
  27. var preres = preload(path) # Load resource during scene load
  28. var res = load(path) # Load resource when program reaches statement
  29. # Note that users load scenes and scripts, by convention, with PascalCase
  30. # names (like typenames), often into constants.
  31. const MyScene : = preload("my_scene.tscn") as PackedScene # Static load
  32. const MyScript : = preload("my_script.gd") as Script
  33. # This type's value varies, i.e. it is a variable, so it uses snake_case.
  34. export(Script) var script_type: Script
  35. # If need an "export const var" (which doesn't exist), use a conditional
  36. # setter for a tool script that checks if it's executing in the editor.
  37. tool # Must place at top of file.
  38. # Must configure from the editor, defaults to null.
  39. export(Script) var const_script setget set_const_script
  40. func set_const_script(value):
  41. if Engine.is_editor_hint():
  42. const_script = value
  43. # Warn users if the value hasn't been set.
  44. func _get_configuration_warning():
  45. if not const_script:
  46. return "Must initialize property 'const_script'."
  47. return ""
  48. .. code-tab:: csharp
  49. // Tool script added for the sake of the "const [Export]" example.
  50. [Tool]
  51. public MyType
  52. {
  53. // Property initializations load during Script instancing, i.e. .new().
  54. // No "preload" loads during scene load exists in C#.
  55. // Initialize with a value. Editable at runtime.
  56. public Script MyScript = GD.Load<Script>("MyScript.cs");
  57. // Initialize with same value. Value cannot be changed.
  58. public readonly Script MyConstScript = GD.Load<Script>("MyScript.cs");
  59. // Like 'readonly' due to inaccessible setter.
  60. // But, value can be set during constructor, i.e. MyType().
  61. public Script Library { get; } = GD.Load<Script>("res://addons/plugin/library.gd");
  62. // If need a "const [Export]" (which doesn't exist), use a
  63. // conditional setter for a tool script that checks if it's executing
  64. // in the editor.
  65. private PackedScene _enemyScn;
  66. [Export]
  67. public PackedScene EnemyScn
  68. {
  69. get { return _enemyScn; }
  70. set
  71. {
  72. if (Engine.IsEditorHint())
  73. {
  74. _enemyScn = value;
  75. }
  76. }
  77. };
  78. // Warn users if the value hasn't been set.
  79. public String _GetConfigurationWarning()
  80. {
  81. if (EnemyScn == null)
  82. return "Must initialize property 'EnemyScn'.";
  83. return "";
  84. }
  85. }
  86. Note the following:
  87. 1. There are many ways in which a language can load such resources.
  88. 2. When designing how objects will access data, don't forget
  89. that one can pass resources around as references as well.
  90. 3. Keep in mind that loading a resource fetches the cached resource
  91. instance maintained by the engine. To get a new object, one must
  92. :ref:`duplicate <class_Resource_method_duplicate>` an existing reference
  93. or instantiate one from scratch with ``new()``.
  94. Nodes likewise have an alternative access point: the SceneTree.
  95. .. tabs::
  96. .. code-tab:: gdscript GDScript
  97. extends Node
  98. # Slow.
  99. func dynamic_lookup_with_dynamic_nodepath():
  100. print(get_node("Child"))
  101. # Faster. GDScript only.
  102. func dynamic_lookup_with_cached_nodepath():
  103. print($Child)
  104. # Fastest. Doesn't break if node moves later.
  105. # Note that `@onready` annotation is GDScript only.
  106. # Other languages must do...
  107. # var child
  108. # func _ready():
  109. # child = get_node("Child")
  110. @onready var child = $Child
  111. func lookup_and_cache_for_future_access():
  112. print(child)
  113. # Delegate reference assignment to an external source.
  114. # Con: need to perform a validation check.
  115. # Pro: node makes no requirements of its external structure.
  116. # 'prop' can come from anywhere.
  117. var prop
  118. func call_me_after_prop_is_initialized_by_parent():
  119. # Validate prop in one of three ways.
  120. # Fail with no notification.
  121. if not prop:
  122. return
  123. # Fail with an error message.
  124. if not prop:
  125. printerr("'prop' wasn't initialized")
  126. return
  127. # Fail and terminate.
  128. # Note: Scripts run from a release export template don't
  129. # run `assert` statements.
  130. assert(prop, "'prop' wasn't initialized")
  131. # Use an autoload.
  132. # Dangerous for typical nodes, but useful for true singleton nodes
  133. # that manage their own data and don't interfere with other objects.
  134. func reference_a_global_autoloaded_variable():
  135. print(globals)
  136. print(globals.prop)
  137. print(globals.my_getter())
  138. .. code-tab:: csharp
  139. using Godot;
  140. using System;
  141. using System.Diagnostics;
  142. public class MyNode : Node
  143. {
  144. // Slow
  145. public void DynamicLookupWithDynamicNodePath()
  146. {
  147. GD.Print(GetNode("Child"));
  148. }
  149. // Fastest. Lookup node and cache for future access.
  150. // Doesn't break if node moves later.
  151. private Node _child;
  152. public void _Ready()
  153. {
  154. _child = GetNode("Child");
  155. }
  156. public void LookupAndCacheForFutureAccess()
  157. {
  158. GD.Print(_child);
  159. }
  160. // Delegate reference assignment to an external source.
  161. // Con: need to perform a validation check.
  162. // Pro: node makes no requirements of its external structure.
  163. // 'prop' can come from anywhere.
  164. public object Prop { get; set; }
  165. public void CallMeAfterPropIsInitializedByParent()
  166. {
  167. // Validate prop in one of three ways.
  168. // Fail with no notification.
  169. if (prop == null)
  170. {
  171. return;
  172. }
  173. // Fail with an error message.
  174. if (prop == null)
  175. {
  176. GD.PrintErr("'Prop' wasn't initialized");
  177. return;
  178. }
  179. // Fail with an exception.
  180. if (prop == null)
  181. {
  182. throw new InvalidOperationException("'Prop' wasn't initialized.");
  183. }
  184. // Fail and terminate.
  185. // Note: Scripts run from a release export template don't
  186. // run `Debug.Assert` statements.
  187. Debug.Assert(Prop, "'Prop' wasn't initialized");
  188. }
  189. // Use an autoload.
  190. // Dangerous for typical nodes, but useful for true singleton nodes
  191. // that manage their own data and don't interfere with other objects.
  192. public void ReferenceAGlobalAutoloadedVariable()
  193. {
  194. MyNode globals = GetNode<MyNode>("/root/Globals");
  195. GD.Print(globals);
  196. GD.Print(globals.Prop);
  197. GD.Print(globals.MyGetter());
  198. }
  199. };
  200. .. _doc_accessing_data_or_logic_from_object:
  201. Accessing data or logic from an object
  202. --------------------------------------
  203. Godot's scripting API is duck-typed. This means that if a script executes an
  204. operation, Godot doesn't validate that it supports the operation by **type**.
  205. It instead checks that the object **implements** the individual method.
  206. For example, the :ref:`CanvasItem <class_CanvasItem>` class has a ``visible``
  207. property. All properties exposed to the scripting API are in fact a setter and
  208. getter pair bound to a name. If one tried to access
  209. :ref:`CanvasItem.visible <class_CanvasItem_property_visible>`, then Godot would do the
  210. following checks, in order:
  211. - If the object has a script attached, it will attempt to set the property
  212. through the script. This leaves open the opportunity for scripts to override
  213. a property defined on a base object by overriding the setter method for the
  214. property.
  215. - If the script does not have the property, it performs a HashMap lookup in
  216. the ClassDB for the "visible" property against the CanvasItem class and all
  217. of its inherited types. If found, it will call the bound setter or getter.
  218. For more information about HashMaps, see the
  219. :ref:`data preferences <doc_data_preferences>` docs.
  220. - If not found, it does an explicit check to see if the user wants to access
  221. the "script" or "meta" properties.
  222. - If not, it checks for a ``_set``/``_get`` implementation (depending on type
  223. of access) in the CanvasItem and its inherited types. These methods can
  224. execute logic that gives the impression that the Object has a property. This
  225. is also the case with the ``_get_property_list`` method.
  226. - Note that this happens even for non-legal symbol names such as in the
  227. case of :ref:`TileSet <class_TileSet>`'s "1/tile_name" property. This
  228. refers to the name of the tile with ID 1, i.e.
  229. ``TileSet.tile_get_name(1)``.
  230. As a result, this duck-typed system can locate a property either in the script,
  231. the object's class, or any class that object inherits, but only for things
  232. which extend Object.
  233. Godot provides a variety of options for performing runtime checks on these
  234. accesses:
  235. - A duck-typed property access. These will be property checks (as described above).
  236. If the operation isn't supported by the object, execution will halt.
  237. .. tabs::
  238. .. code-tab:: gdscript GDScript
  239. # All Objects have duck-typed get, set, and call wrapper methods.
  240. get_parent().set("visible", false)
  241. # Using a symbol accessor, rather than a string in the method call,
  242. # will implicitly call the `set` method which, in turn, calls the
  243. # setter method bound to the property through the property lookup
  244. # sequence.
  245. get_parent().visible = false
  246. # Note that if one defines a _set and _get that describe a property's
  247. # existence, but the property isn't recognized in any _get_property_list
  248. # method, then the set() and get() methods will work, but the symbol
  249. # access will claim it can't find the property.
  250. .. code-tab:: csharp
  251. // All Objects have duck-typed Get, Set, and Call wrapper methods.
  252. GetParent().Set("visible", false);
  253. // C# is a static language, so it has no dynamic symbol access, e.g.
  254. // `GetParent().Visible = false` won't work.
  255. - A method check. In the case of
  256. :ref:`CanvasItem.visible <class_CanvasItem_property_visible>`, one can
  257. access the methods, ``set_visible`` and ``is_visible`` like any other method.
  258. .. tabs::
  259. .. code-tab:: gdscript GDScript
  260. var child = get_child(0)
  261. # Dynamic lookup.
  262. child.call("set_visible", false)
  263. # Symbol-based dynamic lookup.
  264. # GDScript aliases this into a 'call' method behind the scenes.
  265. child.set_visible(false)
  266. # Dynamic lookup, checks for method existence first.
  267. if child.has_method("set_visible"):
  268. child.set_visible(false)
  269. # Cast check, followed by dynamic lookup.
  270. # Useful when you make multiple "safe" calls knowing that the class
  271. # implements them all. No need for repeated checks.
  272. # Tricky if one executes a cast check for a user-defined type as it
  273. # forces more dependencies.
  274. if child is CanvasItem:
  275. child.set_visible(false)
  276. child.show_on_top = true
  277. # If one does not wish to fail these checks without notifying users,
  278. # one can use an assert instead. These will trigger runtime errors
  279. # immediately if not true.
  280. assert(child.has_method("set_visible"))
  281. assert(child.is_in_group("offer"))
  282. assert(child is CanvasItem)
  283. # Can also use object labels to imply an interface, i.e. assume it
  284. # implements certain methods.
  285. # There are two types, both of which only exist for Nodes: Names and
  286. # Groups.
  287. # Assuming...
  288. # A "Quest" object exists and 1) that it can "complete" or "fail" and
  289. # that it will have text available before and after each state...
  290. # 1. Use a name.
  291. var quest = $Quest
  292. print(quest.text)
  293. quest.complete() # or quest.fail()
  294. print(quest.text) # implied new text content
  295. # 2. Use a group.
  296. for a_child in get_children():
  297. if a_child.is_in_group("quest"):
  298. print(quest.text)
  299. quest.complete() # or quest.fail()
  300. print(quest.text) # implied new text content
  301. # Note that these interfaces are project-specific conventions the team
  302. # defines (which means documentation! But maybe worth it?).
  303. # Any script that conforms to the documented "interface" of the name or
  304. # group can fill in for it.
  305. .. code-tab:: csharp
  306. Node child = GetChild(0);
  307. // Dynamic lookup.
  308. child.Call("SetVisible", false);
  309. // Dynamic lookup, checks for method existence first.
  310. if (child.HasMethod("SetVisible"))
  311. {
  312. child.Call("SetVisible", false);
  313. }
  314. // Use a group as if it were an "interface", i.e. assume it implements
  315. // certain methods.
  316. // Requires good documentation for the project to keep it reliable
  317. // (unless you make editor tools to enforce it at editor time).
  318. // Note, this is generally not as good as using an actual interface in
  319. // C#, but you can't set C# interfaces from the editor since they are
  320. // language-level features.
  321. if (child.IsInGroup("Offer"))
  322. {
  323. child.Call("Accept");
  324. child.Call("Reject");
  325. }
  326. // Cast check, followed by static lookup.
  327. CanvasItem ci = GetParent() as CanvasItem;
  328. if (ci != null)
  329. {
  330. ci.SetVisible(false);
  331. // useful when you need to make multiple safe calls to the class
  332. ci.ShowOnTop = true;
  333. }
  334. // If one does not wish to fail these checks without notifying users,
  335. // one can use an assert instead. These will trigger runtime errors
  336. // immediately if not true.
  337. Debug.Assert(child.HasMethod("set_visible"));
  338. Debug.Assert(child.IsInGroup("offer"));
  339. Debug.Assert(CanvasItem.InstanceHas(child));
  340. // Can also use object labels to imply an interface, i.e. assume it
  341. // implements certain methods.
  342. // There are two types, both of which only exist for Nodes: Names and
  343. // Groups.
  344. // Assuming...
  345. // A "Quest" object exists and 1) that it can "Complete" or "Fail" and
  346. // that it will have Text available before and after each state...
  347. // 1. Use a name.
  348. Node quest = GetNode("Quest");
  349. GD.Print(quest.Get("Text"));
  350. quest.Call("Complete"); // or "Fail".
  351. GD.Print(quest.Get("Text")); // Implied new text content.
  352. // 2. Use a group.
  353. foreach (Node AChild in GetChildren())
  354. {
  355. if (AChild.IsInGroup("quest"))
  356. {
  357. GD.Print(quest.Get("Text"));
  358. quest.Call("Complete"); // or "Fail".
  359. GD.Print(quest.Get("Text")); // Implied new text content.
  360. }
  361. }
  362. // Note that these interfaces are project-specific conventions the team
  363. // defines (which means documentation! But maybe worth it?).
  364. // Any script that conforms to the documented "interface" of the
  365. // name or group can fill in for it. Also note that in C#, these methods
  366. // will be slower than static accesses with traditional interfaces.
  367. - Outsource the access to a :ref:`Callable <class_Callable>`. These may be useful
  368. in cases where one needs the max level of freedom from dependencies. In
  369. this case, one relies on an external context to setup the method.
  370. .. tabs::
  371. .. code-tab:: gdscript GDScript
  372. # child.gd
  373. extends Node
  374. var fn = null
  375. func my_method():
  376. if fn:
  377. fn.call_func()
  378. # parent.gd
  379. extends Node
  380. @onready var child = $Child
  381. func _ready():
  382. child.fn = funcref(self, "print_me")
  383. child.my_method()
  384. func print_me():
  385. print(name)
  386. .. code-tab:: csharp
  387. // Child.cs
  388. using Godot;
  389. public partial class Child : Node
  390. {
  391. public FuncRef FN = null;
  392. public void MyMethod()
  393. {
  394. Debug.Assert(FN != null);
  395. FN.CallFunc();
  396. }
  397. }
  398. // Parent.cs
  399. using Godot;
  400. public partial class Parent : Node
  401. {
  402. public Node Child;
  403. public void _Ready()
  404. {
  405. Child = GetNode("Child");
  406. Child.Set("FN", GD.FuncRef(this, "PrintMe"));
  407. Child.MyMethod();
  408. }
  409. public void PrintMe() {
  410. {
  411. GD.Print(GetClass());
  412. }
  413. }
  414. These strategies contribute to Godot's flexible design. Between them, users
  415. have a breadth of tools to meet their specific needs.