Move scripting section to tutorials/

Closes #4113
This commit is contained in:
Nathan Lovato
2020-10-07 13:51:33 -06:00
parent 9cf9fb716a
commit 4272395ab7
95 changed files with 5 additions and 5 deletions

View File

@@ -0,0 +1,315 @@
.. _doc_c_sharp:
C# basics
=========
Introduction
------------
.. warning:: C# support is a new feature available since Godot 3.0.
As such, you may still run into some issues, or find spots
where the documentation could be improved.
Please report issues with C# in Godot on the
`engine GitHub page <https://github.com/godotengine/godot/issues>`_,
and any documentation issues on the
`documentation GitHub page <https://github.com/godotengine/godot-docs/issues>`_.
This page provides a brief introduction to C#, both what it is and
how to use it in Godot. Afterwards, you may want to look at
:ref:`how to use specific features <doc_c_sharp_features>`, read about the
:ref:`differences between the C# and the GDScript API <doc_c_sharp_differences>`
and (re)visit the :ref:`Scripting section <doc_scripting>` of the
step-by-step tutorial.
C# is a high-level programming language developed by Microsoft. In Godot,
it is implemented with the Mono 6.x .NET framework, including full support
for C# 8.0. Mono is an open source implementation of Microsoft's .NET Framework
based on the ECMA standards for C# and the Common Language Runtime.
A good starting point for checking its capabilities is the
`Compatibility <http://www.mono-project.com/docs/about-mono/compatibility/>`_
page in the Mono documentation.
.. note:: This is **not** a full-scale tutorial on the C# language as a whole.
If you aren't already familiar with its syntax or features,
see the
`Microsoft C# guide <https://docs.microsoft.com/en-us/dotnet/csharp/index>`_
or look for a suitable introduction elsewhere.
Setting up C# for Godot
-----------------------
Windows (Visual Studio)
~~~~~~~~~~~~~~~~~~~~~~~
Download and install the latest version of
`Visual Studio <https://visualstudio.microsoft.com/downloads/>`_
(*not* Visual Studio Code), which contains utilities required to use
C# in Godot. If you don't plan on using the Visual Studio IDE,
you can download just the
`Visual Studio Build Tools <https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=BuildTools&rel=15>`_
instead.
Make sure you at least have the .NET Framework 4.5 targeting pack installed, you can get it using any of the installers mentioned above inside the "Individual components" tab.
Windows (JetBrains Rider)
~~~~~~~~~~~~~~~~~~~~~~~~~
JetBrains Rider comes with bundled MSBuild, so nothing extra is required.
Make sure to set the following preferences:
- In Godot's Editor Settings:
- Set **Mono External Editor** to **JetBrains Rider**.
- set **Mono Build Tool** to **JetBrains Mono**.
- In Rider:
- Set **MSBuild version** to either **Bundled with Rider** or **.NET Core**.
- Install the **Godot support** plugin.
macOS and Linux
~~~~~~~~~~~~~~~
Download and install the latest version of the
`Mono SDK <http://www.mono-project.com/download/>`_. As of Godot 3.1 beta 3,
the version number doesn't matter since Godot bundles its own Mono 5.18
installation. We only need the Mono installation for NuGet and MSBuild
which are required to use C# in Godot.
.. note:: To download Mono on macOS, use the "Stable Channel" link
from the `Mono Downloads Page <http://www.mono-project.com/download/>`_.
The Visual Studio channel is an earlier version of Mono and
will not work.
Additional notes
~~~~~~~~~~~~~~~~
Your Godot version must have Mono support enabled,
so make sure to download the **Mono version** of Godot.
If you are building Godot from source, make sure to follow the steps to
enable Mono support in your build as outlined in the
:ref:`doc_compiling_with_mono` page.
In summary, you must have installed Visual Studio or Mono (depending
on your operating system) **and** the Mono-enabled version of Godot.
Configuring an external editor
------------------------------
C# support in Godot's script editor is minimal. Consider using an
external IDE or editor, such as `Visual Studio Code <https://code.visualstudio.com/>`_
or MonoDevelop. These provide autocompletion, debugging, and other
useful features for C#. To select an external editor in Godot,
click on **Editor → Editor Settings** and scroll down to
**Mono**. Under **Mono**, click on **Editor**, and select your
external editor of choice. Godot currently supports the following
external editors:
- Visual Studio 2019
- Visual Studio Code
- MonoDevelop
- Visual Studio for Mac
- JetBrains Rider
.. note::
If you are using Visual Studio Code, ensure you download and install the
`C# extension <https://marketplace.visualstudio.com/items?itemName=ms-vscode.csharp>`_
to enable features like syntax highlighting and IntelliSense.
.. note::
If you are using Visual Studio 2019, you must follow the instructions found
in the `:ref:doc_c_sharp_configuring_vs_2019_for_debugging` section below.
Creating a C# script
--------------------
After you successfully set up C# for Godot, you should see the following option
when selecting **Attach Script** in the context menu of a node in your scene:
.. image:: img/attachcsharpscript.png
Note that while some specifics change, most concepts work the same
when using C# for scripting. If you're new to Godot, you may want to follow
the tutorials on :ref:`doc_scripting` at this point.
While some places in the documentation still lack C# examples, most concepts
can be transferred easily from GDScript.
Project setup and workflow
--------------------------
When you create the first C# script, Godot initializes the C# project files
for your Godot project. This includes generating a C# solution (``.sln``)
and a project file (``.csproj``), as well as some utility files and folders
(``.mono`` and ``Properties/AssemblyInfo.cs``).
All of these but ``.mono`` are important and should be committed to your
version control system. ``.mono`` can be safely added to the ignore list of your VCS.
When troubleshooting, it can sometimes help to delete the ``.mono`` folder
and let it regenerate.
Example
-------
Here's a blank C# script with some comments to demonstrate how it works.
.. code-block:: csharp
using Godot;
using System;
public class YourCustomClass : Node
{
// Member variables here, example:
private int a = 2;
private string b = "textvar";
public override void _Ready()
{
// Called every time the node is added to the scene.
// Initialization here.
GD.Print("Hello from C# to Godot :)");
}
public override void _Process(float delta)
{
// Called every frame. Delta is time since the last frame.
// Update game logic here.
}
}
As you can see, functions normally in global scope in GDScript like Godot's
``print`` function are available in the ``GD`` class which is part of
the ``Godot`` namespace. For a list of methods in the ``GD`` class, see the
class reference pages for
:ref:`@GDScript <class_@gdscript>` and :ref:`@GlobalScope <class_@globalscope>`.
.. note::
Keep in mind that the class you wish to attach to your node should have the same
name as the ``.cs`` file. Otherwise, you will get the following error
and won't be able to run the scene:
*"Cannot find class XXX for script res://XXX.cs"*
General differences between C# and GDScript
-------------------------------------------
The C# API uses ``PascalCase`` instead of ``snake_case`` in GDScript/C++.
Where possible, fields and getters/setters have been converted to properties.
In general, the C# Godot API strives to be as idiomatic as is reasonably possible.
For more information, see the :ref:`doc_c_sharp_differences` page.
.. warning::
You need to (re)build the project assemblies whenever you want to see new
exported variables or signals in the editor. This build can be manually
triggered by clicking the word **Mono** at the bottom of the editor window
to reveal the Mono panel, then clicking the **Build Project** button.
You will also need to rebuild the project assemblies to apply changes in
"tool" scripts.
Current gotchas and known issues
--------------------------------
As C# support is quite new in Godot, there are some growing pains and things
that need to be ironed out. Below is a list of the most important issues
you should be aware of when diving into C# in Godot, but if in doubt, also
take a look over the official
`issue tracker for Mono issues <https://github.com/godotengine/godot/labels/topic%3Amono>`_.
- Writing editor plugins is possible, but it is currently quite convoluted.
- State is currently not saved and restored when hot-reloading,
with the exception of exported variables.
- Attached C# scripts should refer to a class that has a class name
that matches the file name.
- There are some methods such as ``Get()``/``Set()``, ``Call()``/``CallDeferred()``
and signal connection method ``Connect()`` that rely on Godot's ``snake_case`` API
naming conventions.
So when using e.g. ``CallDeferred("AddChild")``, ``AddChild`` will not work because
the API is expecting the original ``snake_case`` version ``add_child``. However, you
can use any custom properties or methods without this limitation.
As of Godot 3.2.2, exporting Mono projects is supported for desktop platforms
(Linux, Windows and macOS), Android, HTML5, and iOS. The only platform not
supported yet is UWP.
Performance of C# in Godot
--------------------------
According to some preliminary `benchmarks <https://github.com/cart/godot3-bunnymark>`_,
the performance of C# in Godot — while generally in the same order of magnitude
— is roughly **~4×** that of GDScript in some naive cases. C++ is still
a little faster; the specifics are going to vary according to your use case.
GDScript is likely fast enough for most general scripting workloads.
C# is faster, but requires some expensive marshalling when talking to Godot.
Using NuGet packages in Godot
-----------------------------
`NuGet <https://www.nuget.org/>`_ packages can be installed and used with Godot,
as with any C# project. Many IDEs are able to add packages directly.
They can also be added manually by adding the package reference in
the ``.csproj`` file located in the project root:
.. code-block:: xml
:emphasize-lines: 2
<ItemGroup>
<PackageReference Include="Newtonsoft.Json">
<Version>11.0.2</Version>
</PackageReference>
</ItemGroup>
...
</Project>
.. note::
By default, tools like NuGet put ``Version`` as an attribute of the ```PackageReference``` Node. **You must manually create a Version node as shown above.** This is because the version of MSBuild used requires this. (This will be fixed in Godot 4.0.)
Whenever packages are added or modified, run ``nuget restore`` (*not* ``dotnet restore``) in the root of the
project directory. To ensure that NuGet packages will be available for
msbuild to use, run:
.. code-block:: none
msbuild /t:restore
Profiling your C# code
----------------------
- `Mono log profiler <https://www.mono-project.com/docs/debug+profile/profile/profiler/>`_ is available for Linux and macOS. Due to a Mono change, it does not work on Windows currently.
- External Mono profiler like `JetBrains dotTrace <https://www.jetbrains.com/profiler/>`_ can be used as described `here <https://github.com/godotengine/godot/pull/34382>`_.
.. _doc_c_sharp_configuring_vs_2019_for_debugging:
Configuring VS 2019 for debugging
---------------------------------
.. note::
Godot has built-in support for workflows involving several popular C# IDEs.
Built-in support for Visual Studio will be including in future versions,
but in the meantime, the steps below can let you configure VS 2019 for use
with Godot C# projects.
1. Install VS 2019 with ``.NET desktop development`` and ``Desktop development with C++`` workloads selected.
2. **Ensure that you do not have Xamarin installed.** Do not choose the ``Mobile development with .NET`` workload. Xamarin changes the DLLs used by MonoDebugger, which breaks debugging.
3. Install the `VSMonoDebugger extension <https://marketplace.visualstudio.com/items?itemName=GordianDotNet.VSMonoDebugger0d62>`_.
4. In VS 2019 --> Extensions --> Mono --> Settings:
- Select ``Debug/Deploy to local Windows``.
- Leave ``Local Deploy Path`` blank.
- Set the ``Mono Debug Port`` to the port in Godot --> Project --> Project Settings --> Mono --> Debugger Agent.
- Also select ``Wait for Debugger`` in the Godot Mono options. `This Godot Addon <https://godotengine.org/asset-library/asset/435>`_ may be helpful.
5. Run the game in Godot. It should hang at the Godot splash screen while it waits for your debugger to attach.
6. In VS 2019, open your project and choose Extensions --> Mono --> Attach to Mono Debugger.
Configuring Visual Studio Code for debugging
--------------------------------------------
To configure debugging, open Visual Studio Code and download the Mono Debug extension from
Microsoft and the Godot extension by Ignacio. Then open the Godot project folder in VS Code.
Go to the Run tab and click on **create a launch.json file**. Select **C# Godot** from the dropdown
menu. Now, when you start the debugger in VS Code your Godot project will run.

View File

@@ -0,0 +1,343 @@
.. _doc_c_sharp_differences:
C# API differences to GDScript
==============================
This is a (incomplete) list of API differences between C# and GDScript.
General differences
-------------------
As explained in the :ref:`doc_c_sharp`, C# generally uses ``PascalCase`` instead
of the ``snake_case`` used in GDScript and C++.
Global scope
------------
Global functions and some constants had to be moved to classes, since C#
does not allow declaring them in namespaces.
Most global constants were moved to their own enums.
Constants
^^^^^^^^^
In C#, only primitive types can be constant. For example, the ``TAU`` constant
is replaced by the ``Mathf.Tau`` constant, but the ``Vector2.RIGHT`` constant
is replaced by the ``Vector2.Right`` read-only property. This behaves similarly
to a constant, but can't be used in some contexts like ``switch`` statements.
Global enum constants were moved to their own enums.
For example, ``ERR_*`` constants were moved to the ``Error`` enum.
Special cases:
======================= ===========================================================
GDScript C#
======================= ===========================================================
``SPKEY`` ``GD.SpKey``
``TYPE_*`` ``Variant.Type`` enum
``OP_*`` ``Variant.Operator`` enum
======================= ===========================================================
Math functions
^^^^^^^^^^^^^^
Math global functions, like ``abs``, ``acos``, ``asin``, ``atan`` and ``atan2``, are
located under ``Mathf`` as ``Abs``, ``Acos``, ``Asin``, ``Atan`` and ``Atan2``.
The ``PI`` constant can be found as ``Mathf.Pi``.
Random functions
^^^^^^^^^^^^^^^^
Random global functions, like ``rand_range`` and ``rand_seed``, are located under ``GD``.
Example: ``GD.RandRange`` and ``GD.RandSeed``.
Other functions
^^^^^^^^^^^^^^^
Many other global functions like ``print`` and ``var2str`` are located under ``GD``.
Example: ``GD.Print`` and ``GD.Var2Str``.
Exceptions:
=========================== =======================================================
GDScript C#
=========================== =======================================================
``weakref(obj)`` ``Object.WeakRef(obj)``
``is_instance_valid(obj)`` ``Object.IsInstanceValid(obj)``
=========================== =======================================================
Tips
^^^^
Sometimes it can be useful to use the ``using static`` directive. This directive allows
to access the members and nested types of a class without specifying the class name.
Example:
.. code-block:: csharp
using static Godot.GD;
public class Test
{
static Test()
{
Print("Hello"); // Instead of GD.Print("Hello");
}
}
Export keyword
--------------
Use the ``[Export]`` attribute instead of the GDScript ``export`` keyword.
This attribute can also be provided with optional :ref:`PropertyHint<enum_@GlobalScope_PropertyHint>` and ``hintString`` parameters.
Default values can be set by assigning a value.
Example:
.. code-block:: csharp
using Godot;
public class MyNode : Node
{
[Export]
private NodePath _nodePath;
[Export]
private string _name = "default";
[Export(PropertyHint.Range, "0,100000,1000,or_greater")]
private int _income;
[Export(PropertyHint.File, "*.png,*.jpg")]
private string _icon;
}
Signal keyword
--------------
Use the ``[Signal]`` attribute to declare a signal instead of the GDScript ``signal`` keyword.
This attribute should be used on a `delegate`, whose name signature will be used to define the signal.
.. code-block:: csharp
[Signal]
delegate void MySignal(string willSendsAString);
See also: :ref:`doc_c_sharp_signals`.
Singletons
----------
Singletons are available as static classes rather than using the singleton pattern.
This is to make code less verbose than it would be with an ``Instance`` property.
Example:
.. code-block:: csharp
Input.IsActionPressed("ui_down")
However, in some very rare cases this is not enough. For example, you may want
to access a member from the base class ``Godot.Object``, like ``Connect``.
For such use cases we provide a static property named ``Singleton`` that returns
the singleton instance. The type of this instance is ``Godot.Object``.
Example:
.. code-block:: csharp
Input.Singleton.Connect("joy_connection_changed", this, nameof(Input_JoyConnectionChanged));
String
------
Use ``System.String`` (``string``). Most of Godot's String methods are
provided by the ``StringExtensions`` class as extension methods.
Example:
.. code-block:: csharp
string upper = "I LIKE SALAD FORKS";
string lower = upper.ToLower();
There are a few differences, though:
* ``erase``: Strings are immutable in C#, so we cannot modify the string
passed to the extension method. For this reason, ``Erase`` was added as an
extension method of ``StringBuilder`` instead of string.
Alternatively, you can use ``string.Remove``.
* ``IsSubsequenceOf``/``IsSubsequenceOfi``: An additional method is provided,
which is an overload of ``IsSubsequenceOf``, allowing you to explicitly specify
case sensitivity:
.. code-block:: csharp
str.IsSubsequenceOf("ok"); // Case sensitive
str.IsSubsequenceOf("ok", true); // Case sensitive
str.IsSubsequenceOfi("ok"); // Case insensitive
str.IsSubsequenceOf("ok", false); // Case insensitive
* ``Match``/``Matchn``/``ExprMatch``: An additional method is provided besides
``Match`` and ``Matchn``, which allows you to explicitly specify case sensitivity:
.. code-block:: csharp
str.Match("*.txt"); // Case sensitive
str.ExprMatch("*.txt", true); // Case sensitive
str.Matchn("*.txt"); // Case insensitive
str.ExprMatch("*.txt", false); // Case insensitive
Basis
-----
Structs cannot have parameterless constructors in C#. Therefore, ``new Basis()``
initializes all primitive members to their default value. Use ``Basis.Identity``
for the equivalent of ``Basis()`` in GDScript and C++.
The following method was converted to a property with a different name:
==================== ==============================================================
GDScript C#
==================== ==============================================================
``get_scale()`` ``Scale``
==================== ==============================================================
Transform2D
-----------
Structs cannot have parameterless constructors in C#. Therefore, ``new Transform2D()``
initializes all primitive members to their default value.
Please use ``Transform2D.Identity`` for the equivalent of ``Transform2D()`` in GDScript and C++.
The following methods were converted to properties with their respective names changed:
==================== ==============================================================
GDScript C#
==================== ==============================================================
``get_rotation()`` ``Rotation``
``get_scale()`` ``Scale``
==================== ==============================================================
Plane
-----
The following method was converted to a property with a *slightly* different name:
================ ==================================================================
GDScript C#
================ ==================================================================
``center()`` ``Center``
================ ==================================================================
Rect2
-----
The following field was converted to a property with a *slightly* different name:
================ ==================================================================
GDScript C#
================ ==================================================================
``end`` ``End``
================ ==================================================================
The following method was converted to a property with a different name:
================ ==================================================================
GDScript C#
================ ==================================================================
``get_area()`` ``Area``
================ ==================================================================
Quat
----
Structs cannot have parameterless constructors in C#. Therefore, ``new Quat()``
initializes all primitive members to their default value.
Please use ``Quat.Identity`` for the equivalent of ``Quat()`` in GDScript and C++.
The following methods were converted to a property with a different name:
===================== =============================================================
GDScript C#
===================== =============================================================
``length()`` ``Length``
``length_squared()`` ``LengthSquared``
===================== =============================================================
Array
-----
*This is temporary. PackedArrays will need their own types to be used the way they are meant to.*
====================== ==============================================================
GDScript C#
====================== ==============================================================
``Array`` ``Godot.Collections.Array``
``PackedInt32Array`` ``int[]``
``PackedInt64Array`` ``long[]``
``PackedByteArray`` ``byte[]``
``PackedFloat32Array`` ``float[]``
``PackedFloat64Array`` ``double[]``
``PackedStringArray`` ``String[]``
``PackedColorArray`` ``Color[]``
``PackedVector2Array`` ``Vector2[]``
``PackedVector3Array`` ``Vector3[]``
====================== ==============================================================
``Godot.Collections.Array<T>`` is a type-safe wrapper around ``Godot.Collections.Array``.
Use the ``Godot.Collections.Array<T>(Godot.Collections.Array)`` constructor to create one.
Dictionary
----------
Use ``Godot.Collections.Dictionary``.
``Godot.Collections.Dictionary<T>`` is a type-safe wrapper around ``Godot.Collections.Dictionary``.
Use the ``Godot.Collections.Dictionary<T>(Godot.Collections.Dictionary)`` constructor to create one.
Variant
-------
``System.Object`` (``object``) is used instead of ``Variant``.
Communicating with other scripting languages
--------------------------------------------
This is explained extensively in :ref:`doc_cross_language_scripting`.
Yield
-----
Something similar to GDScript's ``yield`` with a single parameter can be achieved with
C#'s `yield keyword <https://docs.microsoft.com/en-US/dotnet/csharp/language-reference/keywords/yield>`_.
The equivalent of yield on signal can be achieved with async/await and ``Godot.Object.ToSignal``.
Example:
.. code-block:: csharp
await ToSignal(timer, "timeout");
GD.Print("After timeout");
Other differences
-----------------
``preload``, as it works in GDScript, is not available in C#.
Use ``GD.Load`` or ``ResourceLoader.Load`` instead.
Other differences:
================ ==================================================================
GDScript C#
================ ==================================================================
``Color8`` ``Color.Color8``
``is_inf`` ``float.IsInfinity``
``is_nan`` ``float.IsNaN``
``dict2inst`` TODO
``inst2dict`` TODO
================ ==================================================================

View File

@@ -0,0 +1,245 @@
.. _doc_c_sharp_features:
C# features
===========
This page provides an overview of the commonly used features of both C# and Godot
and how they are used together.
.. _doc_c_sharp_features_type_conversion_and_casting:
Type conversion and casting
---------------------------
C# is a statically typed language. Therefore, you can't do the following:
.. code-block:: csharp
var mySprite = GetNode("MySprite");
mySprite.SetFrame(0);
The method ``GetNode()`` returns a ``Node`` instance.
You must explicitly convert it to the desired derived type, ``Sprite`` in this case.
For this, you have various options in C#.
**Casting and Type Checking**
Throws ``InvalidCastException`` if the returned node cannot be cast to Sprite.
You would use it instead of the ``as`` operator if you are pretty sure it won't fail.
.. code-block:: csharp
Sprite mySprite = (Sprite)GetNode("MySprite");
mySprite.SetFrame(0);
**Using the AS operator**
The ``as`` operator returns ``null`` if the node cannot be cast to Sprite,
and for that reason, it cannot be used with value types.
.. code-block:: csharp
Sprite mySprite = GetNode("MySprite") as Sprite;
// Only call SetFrame() if mySprite is not null
mySprite?.SetFrame(0);
**Using the generic methods**
Generic methods are also provided to make this type conversion transparent.
``GetNode<T>()`` casts the node before returning it. It will throw an ``InvalidCastException`` if the node cannot be cast to the desired type.
.. code-block:: csharp
Sprite mySprite = GetNode<Sprite>("MySprite");
mySprite.SetFrame(0);
``GetNodeOrNull<T>()`` uses the ``as`` operator and will return ``null`` if the node cannot be cast to the desired type.
.. code-block:: csharp
Sprite mySprite = GetNodeOrNull<Sprite>("MySprite");
// Only call SetFrame() if mySprite is not null
mySprite?.SetFrame(0);
**Type checking using the IS operator**
To check if the node can be cast to Sprite, you can use the ``is`` operator.
The ``is`` operator returns false if the node cannot be cast to Sprite,
otherwise it returns true.
.. code-block:: csharp
if (GetNode("MySprite") is Sprite)
{
// Yup, it's a sprite!
}
For more advanced type checking, you can look into `Pattern Matching <https://docs.microsoft.com/en-us/dotnet/csharp/pattern-matching>`_.
.. _doc_c_sharp_signals:
C# signals
----------
For a complete C# example, see the **Handling a signal** section in the step by step :ref:`doc_scripting` tutorial.
Declaring a signal in C# is done with the ``[Signal]`` attribute on a delegate.
.. code-block:: csharp
[Signal]
delegate void MySignal();
[Signal]
delegate void MySignalWithArguments(string foo, int bar);
These signals can then be connected either in the editor or from code with ``Connect``.
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.
.. code-block:: csharp
public void MyCallback()
{
GD.Print("My callback!");
}
public void MyCallbackWithArguments(string foo, int bar)
{
GD.Print("My callback with: ", foo, " and ", bar, "!");
}
public void SomeFunction()
{
instance.Connect("MySignal", this, "MyCallback");
instance.Connect(nameof(MySignalWithArguments), this, "MyCallbackWithArguments");
}
Emitting signals is done with the ``EmitSignal`` method.
.. code-block:: csharp
public void SomeFunction()
{
EmitSignal(nameof(MySignal));
EmitSignal("MySignalWithArguments", "hello there", 28);
}
Notice that you can always reference a signal name with the ``nameof`` keyword (applied on the delegate itself).
It is possible to bind values when establishing a connection by passing an object array.
.. code-block:: csharp
public int Value { get; private set; } = 0;
private void ModifyValue(int modifier)
{
Value += modifier;
}
public void SomeFunction()
{
var plusButton = (Button)GetNode("PlusButton");
var minusButton = (Button)GetNode("MinusButton");
plusButton.Connect("pressed", this, "ModifyValue", new object[] { 1 });
minusButton.Connect("pressed", this, "ModifyValue", new object[] { -1 });
}
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>`.
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.
.. code-block:: csharp
public class DataObject : Godot.Object
{
public string Field1 { get; set; }
public string Field2 { get; set; }
}
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``).
.. code-block:: csharp
public void SomeFunction()
{
AddUserSignal("MyOtherSignal");
EmitSignal("MyOtherSignal");
}
Preprocessor defines
--------------------
Godot has a set of defines that allow you to change your C# code
depending on the environment you are compiling to.
.. note:: If you created your project before Godot 3.2, you have to modify
or regenerate your `csproj` file to use this feature
(compare ``<DefineConstants>`` with a new 3.2+ project).
Examples
~~~~~~~~
For example, you can change code based on the platform:
.. code-block:: csharp
public override void _Ready()
{
#if GODOT_SERVER
// Don't try to load meshes or anything, this is a server!
LaunchServer();
#elif GODOT_32 || GODOT_MOBILE || GODOT_WEB
// Use simple objects when running on less powerful systems.
SpawnSimpleObjects();
#else
SpawnComplexObjects();
#endif
}
Or you can detect which engine your code is in, useful for making cross-engine libraries:
.. code-block:: csharp
public void MyPlatformPrinter()
{
#if GODOT
GD.Print("This is Godot.");
#elif UNITY_5_3_OR_NEWER
print("This is Unity.");
#else
throw new InvalidWorkflowException("Only Godot and Unity are supported.");
#endif
}
Full list of defines
~~~~~~~~~~~~~~~~~~~~
* ``GODOT`` is always defined for Godot projects.
* One of ``GODOT_64`` or ``GODOT_32`` is defined depending on if the architecture is 64-bit or 32-bit.
* One of ``GODOT_LINUXBSD``, ``GODOT_WINDOWS``, ``GODOT_OSX``,
``GODOT_ANDROID``, ``GODOT_IOS``, ``GODOT_HTML5``, or ``GODOT_SERVER``
depending on the OS. These names may change in the future.
These are created from the ``get_name()`` method of the
:ref:``OS <class_OS>`` singleton, but not every possible OS
the method returns is an OS that Godot with Mono runs on.
When **exporting**, the following may also be defined depending on the export features:
* One of ``GODOT_PC``, ``GODOT_MOBILE``, or ``GODOT_WEB`` depending on the platform type.
* One of ``GODOT_ARM64_V8A`` or ``GODOT_ARMEABI_V7A`` on Android only depending on the architecture.
* One of ``GODOT_ARM64`` or ``GODOT_ARMV7`` on iOS only depending on the architecture.
* Any of ``GODOT_S3TC``, ``GODOT_ETC``, and ``GODOT_ETC2`` depending on the texture compression type.
* Any custom features added in the export menu will be capitalized and prefixed: ``foo`` -> ``GODOT_FOO``.
To see an example project, see the OS testing demo:
https://github.com/godotengine/godot-demo-projects/tree/master/misc/os_test

View File

@@ -0,0 +1,324 @@
.. _doc_c_sharp_styleguide:
C# style guide
==============
Having well-defined and consistent coding conventions is important for every project, and Godot
is no exception to this rule.
This page contains a coding style guide, which is followed by developers of and contributors to Godot
itself. As such, it is mainly intended for those who want to contribute to the project, but since
the conventions and guidelines mentioned in this article are those most widely adopted by the users
of the language, we encourage you to do the same, especially if you do not have such a guide yet.
.. note:: This article is by no means an exhaustive guide on how to follow the standard coding
conventions or best practices. If you feel unsure of an aspect which is not covered here,
please refer to more comprehensive documentation, such as
`C# Coding Conventions <https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/inside-a-program/coding-conventions>`_ or
`Framework Design Guidelines <https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/naming-guidelines>`_.
Language specification
----------------------
Godot currently uses **C# version 7.0** in its engine and example source code. So, before we move to
a newer version, care must be taken to avoid mixing language features only available in C# 7.1 or
later.
For detailed information on C# features in different versions, please see
`What's New in C# <https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/>`_.
Formatting
----------
General guidelines
~~~~~~~~~~~~~~~~~~
* Use line feed (**LF**) characters to break lines, not CRLF or CR.
* Use one line feed character at the end of each file, except for `csproj` files.
* Use **UTF-8** encoding without a `byte order mark <https://en.wikipedia.org/wiki/Byte_order_mark>`_.
* Use **4 spaces** instead of tabs for indentation (which is referred to as "soft tabs").
* Consider breaking a line into several if it's longer than 100 characters.
Line breaks and blank lines
~~~~~~~~~~~~~~~~~~~~~~~~~~~
For a general indentation rule, follow `the "Allman Style" <https://en.wikipedia.org/wiki/Indentation_style#Allman_style>`_
which recommends placing the brace associated with a control statement on the next line, indented to
the same level:
.. code-block:: csharp
// Use this style:
if (x > 0)
{
DoSomething();
}
// NOT this:
if (x > 0) {
DoSomething();
}
However, you may choose to omit line breaks inside brackets:
* For simple property accessors.
* For simple object, array, or collection initializers.
* For abstract auto property, indexer, or event declarations.
.. code-block:: csharp
// You may put the brackets in a single line in following cases:
public interface MyInterface
{
int MyProperty { get; set; }
}
public class MyClass : ParentClass
{
public int Value
{
get { return 0; }
set
{
ArrayValue = new [] {value};
}
}
}
Insert a blank line:
* After a list of ``using`` statements.
* Between method, properties, and inner type declarations.
* At the end of each file.
Field and constant declarations can be grouped together according to relevance. In that case, consider
inserting a blank line between the groups for easier reading.
Avoid inserting a blank line:
* After ``{``, the opening brace.
* Before ``}``, the closing brace.
* After a comment block or a single-line comment.
* Adjacent to another blank line.
.. code-block:: csharp
using System;
using Godot;
// Blank line after `using` list.
public class MyClass
{ // No blank line after `{`.
public enum MyEnum
{
Value,
AnotherValue // No blank line before `}`.
}
// Blank line around inner types.
public const int SomeConstant = 1;
public const int AnotherConstant = 2;
private Vector3 _x; // Related constants or fields can be
private Vector3 _y; // grouped together.
private float _width;
private float _height;
public int MyProperty { get; set; }
// Blank line around properties.
public void MyMethod()
{
// Some comment.
AnotherMethod(); // No blank line after a comment.
}
// Blank line around methods.
public void AnotherMethod()
{
}
}
Using spaces
~~~~~~~~~~~~
Insert a space:
* Around a binary and tertiary operator.
* Between an opening parenthesis and ``if``, ``for``, ``foreach``, ``catch``, ``while``, ``lock`` or ``using`` keywords.
* Before and within a single line accessor block.
* Between accessors in a single line accessor block.
* After a comma which is not at the end of a line.
* After a semicolon in a ``for`` statement.
* After a colon in a single line ``case`` statement.
* Around a colon in a type declaration.
* Around a lambda arrow.
* After a single-line comment symbol (``//``), and before it if used at the end of a line.
Do not use a space:
* After type cast parentheses.
* Within single line initializer braces.
The following example shows a proper use of spaces, according to some of the above mentioned conventions:
.. code-block:: csharp
public class MyClass<A, B> : Parent<A, B>
{
public float MyProperty { get; set; }
public float AnotherProperty
{
get { return MyProperty; }
}
public void MyMethod()
{
int[] values = {1, 2, 3, 4}; // No space within initializer brackets.
int sum = 0;
// Single line comment.
for (int i = 0; i < values.Length; i++)
{
switch (i)
{
case 3: return;
default:
sum += i > 2 ? 0 : 1;
break;
}
}
i += (int)MyProperty; // No space after a type cast.
}
}
Naming conventions
------------------
Use **PascalCase** for all namespaces, type names and member level identifiers (i.e. methods, properties,
constants, events), except for private fields:
.. code-block:: csharp
namespace ExampleProject
{
public class PlayerCharacter
{
public const float DefaultSpeed = 10f;
public float CurrentSpeed { get; set; }
protected int HitPoints;
private void CalculateWeaponDamage()
{
}
}
}
Use **camelCase** for all other identifiers (i.e. local variables, method arguments), and use
an underscore (``_``) as a prefix for private fields (but not for methods or properties, as explained above):
.. code-block:: csharp
private Vector3 _aimingAt; // Use a `_` prefix for private fields.
private void Attack(float attackStrength)
{
Enemy targetFound = FindTarget(_aimingAt);
targetFound?.Hit(attackStrength);
}
There's an exception with acronyms which consist of two letters, like ``UI``, which should be written in
uppercase letters where PascalCase would be expected, and in lowercase letters otherwise.
Note that ``id`` is **not** an acronym, so it should be treated as a normal identifier:
.. code-block:: csharp
public string Id { get; }
public UIManager UI
{
get { return uiManager; }
}
It is generally discouraged to use a type name as a prefix of an identifier, like ``string strText``
or ``float fPower``, for example. An exception is made, however, for interfaces, which
**should**, in fact, have an uppercase letter ``I`` prefixed to their names, like ``IInventoryHolder`` or ``IDamageable``.
Lastly, consider choosing descriptive names and do not try to shorten them too much if it affects
readability.
For instance, if you want to write code to find a nearby enemy and hit it with a weapon, prefer:
.. code-block:: csharp
FindNearbyEnemy()?.Damage(weaponDamage);
Rather than:
.. code-block:: csharp
FindNode()?.Change(wpnDmg);
Member variables
----------------
Don't declare member variables if they are only used locally in a method, as it
makes the code more difficult to follow. Instead, declare them as local
variables in the method's body.
Local variables
---------------
Declare local variables as close as possible to their first use. This makes it
easier to follow the code, without having to scroll too much to find where the
variable was declared.
Implicitly typed local variables
--------------------------------
Consider using implicitly typing (``var``) for declaration of a local variable, but do so
**only when the type is evident** from the right side of the assignment:
.. code-block:: csharp
// You can use `var` for these cases:
var direction = new Vector2(1, 0);
var value = (int)speed;
var text = "Some value";
for (var i = 0; i < 10; i++)
{
}
// But not for these:
var value = GetValue();
var velocity = direction * 1.5;
// It's generally a better idea to use explicit typing for numeric values, especially with
// the existence of the `real_t` alias in Godot, which can either be double or float
// depending on the build configuration.
var value = 1.5;
Other considerations
--------------------
* Use explicit access modifiers.
* Use properties instead of non-private fields.
* Use modifiers in this order:
``public``/``protected``/``private``/``internal``/``virtual``/``override``/``abstract``/``new``/``static``/``readonly``.
* Avoid using fully-qualified names or ``this.`` prefix for members when it's not necessary.
* Remove unused ``using`` statements and unnecessary parentheses.
* Consider omitting the default initial value for a type.
* Consider using null-conditional operators or type initializers to make the code more compact.
* Use safe cast when there is a possibility of the value being a different type, and use direct cast otherwise.

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

@@ -0,0 +1,11 @@
C#
===
.. toctree::
:maxdepth: 1
:name: toc-learn-scripting-C#
c_sharp_basics
c_sharp_features
c_sharp_differences
c_sharp_style_guide