c_sharp_features.rst 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. .. _doc_c_sharp_features:
  2. C# features
  3. ===========
  4. This page provides an overview of the commonly used features of both C# and Godot
  5. and how they are used together.
  6. .. _doc_c_sharp_features_type_conversion_and_casting:
  7. Type conversion and casting
  8. ---------------------------
  9. C# is a statically typed language. Therefore, you can't do the following:
  10. .. code-block:: csharp
  11. var mySprite = GetNode("MySprite");
  12. mySprite.SetFrame(0);
  13. The method ``GetNode()`` returns a ``Node`` instance.
  14. You must explicitly convert it to the desired derived type, ``Sprite2D`` in this case.
  15. For this, you have various options in C#.
  16. **Casting and Type Checking**
  17. Throws ``InvalidCastException`` if the returned node cannot be cast to Sprite2D.
  18. You would use it instead of the ``as`` operator if you are pretty sure it won't fail.
  19. .. code-block:: csharp
  20. Sprite2D mySprite = (Sprite2D)GetNode("MySprite");
  21. mySprite.SetFrame(0);
  22. **Using the AS operator**
  23. The ``as`` operator returns ``null`` if the node cannot be cast to Sprite2D,
  24. and for that reason, it cannot be used with value types.
  25. .. code-block:: csharp
  26. Sprite2D mySprite = GetNode("MySprite") as Sprite2D;
  27. // Only call SetFrame() if mySprite is not null
  28. mySprite?.SetFrame(0);
  29. **Using the generic methods**
  30. Generic methods are also provided to make this type conversion transparent.
  31. ``GetNode<T>()`` casts the node before returning it. It will throw an ``InvalidCastException`` if the node cannot be cast to the desired type.
  32. .. code-block:: csharp
  33. Sprite2D mySprite = GetNode<Sprite2D>("MySprite");
  34. mySprite.SetFrame(0);
  35. ``GetNodeOrNull<T>()`` uses the ``as`` operator and will return ``null`` if the node cannot be cast to the desired type.
  36. .. code-block:: csharp
  37. Sprite2D mySprite = GetNodeOrNull<Sprite2D>("MySprite");
  38. // Only call SetFrame() if mySprite is not null
  39. mySprite?.SetFrame(0);
  40. **Type checking using the IS operator**
  41. To check if the node can be cast to Sprite2D, you can use the ``is`` operator.
  42. The ``is`` operator returns false if the node cannot be cast to Sprite2D,
  43. otherwise it returns true. Note that using the ``is`` operator against ``null`` is always going to be falsy.
  44. .. code-block:: csharp
  45. if (GetNode("MySprite") is Sprite2D)
  46. {
  47. // Yup, it's a Sprite2D!
  48. }
  49. if (null is Sprite2D)
  50. {
  51. // This block can never happen.
  52. }
  53. For more advanced type checking, you can look into `Pattern Matching <https://docs.microsoft.com/en-us/dotnet/csharp/pattern-matching>`_.
  54. .. _doc_c_sharp_signals:
  55. C# signals
  56. ----------
  57. For a complete C# example, see the :ref:`doc_signals` section in the step by step tutorial.
  58. Declaring a signal in C# is done with the ``[Signal]`` attribute on a delegate.
  59. .. code-block:: csharp
  60. [Signal]
  61. delegate void MySignalEventHandler();
  62. [Signal]
  63. delegate void MySignalWithArgumentsEventHandler(string foo, int bar);
  64. These signals can then be connected either in the editor or from code with ``Connect``.
  65. If you want to connect a signal in the editor, you need to (re)build the project assemblies to see the new signal. This build can be manually triggered by clicking the "Build" button at the top right corner of the editor window.
  66. .. code-block:: csharp
  67. public void MyCallback()
  68. {
  69. GD.Print("My callback!");
  70. }
  71. public void MyCallbackWithArguments(string foo, int bar)
  72. {
  73. GD.Print($"My callback with: {foo} and {bar}!");
  74. }
  75. public void SomeFunction()
  76. {
  77. instance.MySignal += MyCallback;
  78. instance.MySignalWithArguments += MyCallbackWithArguments;
  79. }
  80. Emitting signals is done with the ``EmitSignal`` method.
  81. .. code-block:: csharp
  82. public void SomeFunction()
  83. {
  84. EmitSignal(SignalName.MySignal);
  85. EmitSignal(SignalName.MySignalWithArguments, "hello there", 28);
  86. }
  87. Notice that you can always reference a signal name with its generated ``SignalName``.
  88. It is possible to bind values when establishing a connection by passing a Godot array.
  89. .. code-block:: csharp
  90. public int Value { get; private set; } = 0;
  91. private void ModifyValue(int modifier)
  92. {
  93. Value += modifier;
  94. }
  95. public void SomeFunction()
  96. {
  97. var plusButton = (Button)GetNode("PlusButton");
  98. var minusButton = (Button)GetNode("MinusButton");
  99. plusButton.Pressed += () => ModifyValue(1);
  100. minusButton.Pressed += () => ModifyValue(-1);
  101. }
  102. Signals support parameters and bound values of all the `built-in types <https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/built-in-types-table>`_ and Classes derived from :ref:`Godot.Object <class_Object>`.
  103. Consequently, any ``Node`` or ``Reference`` will be compatible automatically, but custom data objects will need to extend from `Godot.Object` or one of its subclasses.
  104. .. code-block:: csharp
  105. using Godot;
  106. public partial class DataObject : Godot.Object
  107. {
  108. public string Field1 { get; set; }
  109. public string Field2 { get; set; }
  110. }
  111. Finally, signals can be created by calling ``AddUserSignal``, but be aware that it should be executed before any use of said signals (with ``Connect`` or ``EmitSignal``).
  112. .. code-block:: csharp
  113. public void SomeFunction()
  114. {
  115. AddUserSignal("MyOtherSignal");
  116. EmitSignal("MyOtherSignal");
  117. }
  118. Preprocessor defines
  119. --------------------
  120. Godot has a set of defines that allow you to change your C# code
  121. depending on the environment you are compiling to.
  122. .. note:: If you created your project before Godot 3.2, you have to modify
  123. or regenerate your `csproj` file to use this feature
  124. (compare ``<DefineConstants>`` with a new 3.2+ project).
  125. Examples
  126. ~~~~~~~~
  127. For example, you can change code based on the platform:
  128. .. code-block:: csharp
  129. public override void _Ready()
  130. {
  131. #if GODOT_SERVER
  132. // Don't try to load meshes or anything, this is a server!
  133. LaunchServer();
  134. #elif GODOT_32 || GODOT_MOBILE || GODOT_WEB
  135. // Use simple objects when running on less powerful systems.
  136. SpawnSimpleObjects();
  137. #else
  138. SpawnComplexObjects();
  139. #endif
  140. }
  141. Or you can detect which engine your code is in, useful for making cross-engine libraries:
  142. .. code-block:: csharp
  143. public void MyPlatformPrinter()
  144. {
  145. #if GODOT
  146. GD.Print("This is Godot.");
  147. #elif UNITY_5_3_OR_NEWER
  148. print("This is Unity.");
  149. #else
  150. throw new InvalidWorkflowException("Only Godot and Unity are supported.");
  151. #endif
  152. }
  153. Full list of defines
  154. ~~~~~~~~~~~~~~~~~~~~
  155. * ``GODOT`` is always defined for Godot projects.
  156. * One of ``GODOT_64`` or ``GODOT_32`` is defined depending on if the architecture is 64-bit or 32-bit.
  157. * One of ``GODOT_LINUXBSD``, ``GODOT_WINDOWS``, ``GODOT_OSX``,
  158. ``GODOT_ANDROID``, ``GODOT_IOS``, ``GODOT_HTML5``, or ``GODOT_SERVER``
  159. depending on the OS. These names may change in the future.
  160. These are created from the ``get_name()`` method of the
  161. :ref:`OS <class_OS>` singleton, but not every possible OS
  162. the method returns is an OS that Godot with Mono runs on.
  163. When **exporting**, the following may also be defined depending on the export features:
  164. * One of ``GODOT_PC``, ``GODOT_MOBILE``, or ``GODOT_WEB`` depending on the platform type.
  165. * One of ``GODOT_ARM64_V8A`` or ``GODOT_ARMEABI_V7A`` on Android only depending on the architecture.
  166. * One of ``GODOT_ARM64`` or ``GODOT_ARMV7`` on iOS only depending on the architecture.
  167. * Any of ``GODOT_S3TC``, ``GODOT_ETC``, and ``GODOT_ETC2`` depending on the texture compression type.
  168. * Any custom features added in the export menu will be capitalized and prefixed: ``foo`` -> ``GODOT_FOO``.
  169. To see an example project, see the OS testing demo:
  170. https://github.com/godotengine/godot-demo-projects/tree/master/misc/os_test