Move scripting section to tutorials/

Closes #4113
This commit is contained in:
Nathan Lovato
2020-10-07 13:51:33 -06:00
parent 9495cdb945
commit 6d8fbe38ea
95 changed files with 5 additions and 5 deletions

View File

@@ -0,0 +1,302 @@
.. _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
-----------------------
Prerequisites
~~~~~~~~~~~~~
Install the latest stable version of
`.NET Core SDK <https://dotnet.microsoft.com/download/dotnet-core>`__
(3.1 as of writing).
From Godot 3.2.3 onwards, installing Mono SDK is not a requirement anymore,
except it is required if you are building the engine from source.
Godot bundles the parts of Mono needed to run already compiled games,
however Godot does not include the tools required to build and compile
games, such as MSBuild. These tools need to be installed separately.
The required tools are included in the .NET Core SDK. MSBuild is also
included in the Mono SDK, but it can't build C# projects with the new
``csproj`` format, therefore .NET Core SDK is required for Godot 3.2.3+.
In summary, you must have installed .NET Core SDK
**and** the Mono-enabled version of Godot.
Additional notes
~~~~~~~~~~~~~~~~
Be sure to install the 64-bit version of the SDK(s)
if you are using the 64-bit version of Godot.
If you are building Godot from source, install the latest stable version of
`Mono <https://www.mono-project.com/download/stable/>`__, and make sure to
follow the steps to enable Mono support in your build as outlined in the
:ref:`doc_compiling_with_mono` page.
Configuring an external editor
------------------------------
C# support in Godot's built-in 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
See the following sections for how to configure an external editor:
JetBrains Rider
~~~~~~~~~~~~~~~
After reading the "Prerequisites" section, you can download and install
`JetBrains Rider <https://www.jetbrains.com/rider/download>`__.
In Godot's **Editor → Editor Settings** menu:
- Set **Mono** -> **Editor** -> **External Editor** to **JetBrains Rider**.
- Set **Mono** -> **Builds** -> **Build Tool** to **dotnet CLI**.
In Rider:
- Set **MSBuild version** to **.NET Core**.
- Install the **Godot support** plugin.
Visual Studio Code
~~~~~~~~~~~~~~~~~~
After reading the "Prerequisites" section, you can download and install
`Visual Studio Code <https://code.visualstudio.com/download>`__ (aka VS Code).
In Godot's **Editor → Editor Settings** menu:
- Set **Mono** -> **Editor** -> **External Editor** to **Visual Studio Code**.
In Visual Studio Code:
- Install the `C# <https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp>`__ extension.
- Install the `Mono Debug <https://marketplace.visualstudio.com/items?itemName=ms-vscode.mono-debug>`__ extension.
- Install the `C# Tools for Godot <https://marketplace.visualstudio.com/items?itemName=neikeq.godot-csharp-vscode>`__ extension.
.. note:: If you are using Linux you need to install the
`Mono SDK <https://www.mono-project.com/download/stable/#download-lin>`__
for the C# tools plugin to work.
To configure a project for debugging 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.
Visual Studio (Windows only)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Download and install the latest version of
`Visual Studio <https://visualstudio.microsoft.com/downloads/>`__.
Visual Studio will include the required SDKs if you have the correct
workloads selected, so you don't need to manually install the things
listed in the "Prerequisites" section.
While installing Visual Studio, select these workloads:
- Mobile development with .NET
- .NET Core cross-platform development
In Godot's **Editor → Editor Settings** menu:
- Set **Mono** -> **Editor** -> **External Editor** to **Visual Studio**.
Next, you need to download the Godot Visual Studio extension from github
`here <https://github.com/godotengine/godot-csharp-visualstudio/releases>`__.
Double click on the downloaded file and follow the installation process.
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 **Build** in the top right corner of the
editor. You can also click **Mono** at the bottom of the editor window
to reveal the Mono panel, then click 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.
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" />
</ItemGroup>
...
</Project>
As of Godot 3.2.3, Godot automatically downloads and sets up newly added NuGet
packages the next time it builds the project.
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>`_.

View File

@@ -0,0 +1,358 @@
.. _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
^^^^^^^^^
Global 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`.
`onready` keyword
-----------------
GDScript has the ability to defer the initialization of a member variable until the ready function
is called with `onready` (cf. :ref:`doc_gdscript_onready_keyword`).
For example:
.. code-block:: gdscript
onready var my_label = get_node("MyLabel")
However C# does not have this ability. To achieve the same effect you need to do this.
.. code-block:: csharp
private Label _myLabel;
public override void _Ready()
{
_myLabel = GetNode<Label>("MyLabel");
}
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. PoolArrays will need their own types to be used the way they are meant to.*
===================== ==============================================================
GDScript C#
===================== ==============================================================
``Array`` ``Godot.Collections.Array``
``PoolIntArray`` ``int[]``
``PoolByteArray`` ``byte[]``
``PoolFloatArray`` ``float[]``
``PoolStringArray`` ``String[]``
``PoolColorArray`` ``Color[]``
``PoolVector2Array`` ``Vector2[]``
``PoolVector3Array`` ``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 a Godot 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 Godot.Collections.Array { 1 });
minusButton.Connect("pressed", this, "ModifyValue", new Godot.Collections.Array { -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_X11``, ``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,12 @@
C#
===
.. toctree::
:maxdepth: 1
:name: toc-learn-scripting-C#
c_sharp_basics
c_sharp_features
c_sharp_differences
c_sharp_exports
c_sharp_style_guide

View File

@@ -0,0 +1,156 @@
.. _doc_creating_script_templates:
Creating script templates
=========================
Godot provides a way to use script templates as seen in the
``Script Create Dialog`` while creating a new script:
.. image:: img/script_create_dialog_templates.png
A set of default script templates is provided by default, but it's also possible
to modify existing and create new ones, both per project and the editor.
Locating the templates
----------------------
There are two places where templates can be managed.
Editor-defined templates
~~~~~~~~~~~~~~~~~~~~~~~~
These are available globally throughout any project. The location of these
templates are determined per each OS:
- Windows: ``%APPDATA%\Godot\script_templates\``
- Linux: ``$HOME/.config/godot/script_templates/``
- macOS: ``$HOME/Library/Application Support/Godot/script_templates/``
If no ``script_templates`` is detected, Godot will create a default set of
built-in templates automatically, so this logic can be used to reset the default
templates in case you've accidentally overwritten them.
Project-defined templates
~~~~~~~~~~~~~~~~~~~~~~~~~
The default path to search for templates is the
``res://script_templates/`` directory. The path can be changed by configuring
the ``editor/script_templates_search_path`` setting in the
:ref:`ProjectSettings <class_ProjectSettings>`, both via code and the editor.
If no ``script_templates`` directory is found within a project, it is simply
ignored.
Language support and overriding behavior
----------------------------------------
Depending on whether a particular language implements a way to generate scripts
out of templates, it's possible to create a template which can be recognized by
that language according to template's file extension. For GDScript and C#, the
extensions must be ``gd`` and ``cs`` respectively.
.. note:: The script templates have the same extension as the regular script
files. This may lead to an issue of a script parser treating those templates as
actual scripts within a project. To avoid this, make sure to ignore the
directory containing them by creating an empty ``.gdignore`` file. The directory won't be
visible throughout the project's filesystem anymore, yet the templates can be
modified by an external text editor anytime.
The built-in editor templates are automatically shadowed by the project-specific
templates given both scripts have the same filename.
Default template
----------------
The ``Default`` template is always generated dynamically per language and cannot
be configured nor overridden, but you can use these as the base for creating
other templates.
.. tabs::
.. code-tab:: gdscript GDScript
extends %BASE%
# Declare member variables here. Examples:
# var a%INT_TYPE% = 2
# var b%STRING_TYPE% = "text"
# Called when the node enters the scene tree for the first time.
func _ready()%VOID_RETURN%:
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
#func _process(delta%FLOAT_TYPE%)%VOID_RETURN%:
# pass
.. code-tab:: csharp
using Godot;
using System;
public class %CLASS% : %BASE%
{
// Declare member variables here. Examples:
// private int a = 2;
// private string b = "text";
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
}
// // Called every frame. 'delta' is the elapsed time since the previous frame.
// public override void _Process(float delta)
// {
//
// }
}
List of template placeholders
-----------------------------
The following describes the complete list of built-in template placeholders
which are currently implemented.
Base placeholders
~~~~~~~~~~~~~~~~~
+-------------+----------------------------------------------------------------+
| Placeholder | Description |
+=============+================================================================+
| ``%CLASS%`` | The name of the new class (used in C# only). |
+-------------+----------------------------------------------------------------+
| ``%BASE%`` | The base type a new script inherits from. |
+-------------+----------------------------------------------------------------+
| ``%TS%`` | Indentation placeholder. The exact type and number of |
| | whitespace characters used for indentation is determined by |
| | the ``text_editor/indent/type`` and ``text_editor/indent/size``|
| | settings in the :ref:`EditorSettings <class_EditorSettings>` |
| | respectively. |
+-------------+----------------------------------------------------------------+
Type placeholders
~~~~~~~~~~~~~~~~~
These are only relevant for GDScript with static typing. Whether these
placeholders are actually replaced is determined by the
``text_editor/completion/add_type_hints`` setting in the
:ref:`EditorSettings <class_EditorSettings>`.
+-------------------+--------------+
| Placeholder | Value |
+===================+==============+
| ``%INT_TYPE%`` | ``: int`` |
+-------------------+--------------+
| ``%STRING_TYPE%`` | ``: String`` |
+-------------------+--------------+
| ``%FLOAT_TYPE%`` | ``: float`` |
+-------------------+--------------+
| ``%VOID_RETURN%`` | ``-> void`` |
+-------------------+--------------+

View File

@@ -0,0 +1,210 @@
.. _doc_cross_language_scripting:
Cross-language scripting
========================
Godot allows you to mix and match scripting languages to suit your needs.
This means a single project can define nodes in both C# and GDScript.
This page will go through the possible interactions between two nodes written
in different languages.
The following two scripts will be used as references throughout this page.
.. tabs::
.. code-tab:: gdscript GDScript
extends Node
var str1 : String = "foo"
var str2 : String setget ,get_str2
func get_str2() -> String:
return "foofoo"
func print_node_name(node : Node) -> void:
print(node.get_name())
func print_array(arr : Array) -> void:
for element in arr:
print(element)
func print_x_times(msg : String, n : int) -> void:
for i in range(n):
print(msg)
.. code-tab:: csharp
public class MyCSharpNode : Node
{
public String str1 = "bar";
public String str2 { get { return "barbar"; } }
public void PrintNodeName(Node node)
{
GD.Print(node.GetName());
}
public void PrintArray(String[] arr)
{
foreach (String element in arr)
{
GD.Print(element);
}
}
public void PrintNTimes(String msg, int n)
{
for (int i = 0; i < n; ++i)
{
GD.Print(msg);
}
}
}
Instantiating nodes
-------------------
If you're not using nodes from the scene tree, you'll probably want to
instantiate nodes directly from the code.
Instantiating C# nodes from GDScript
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Using C# from GDScript doesn't need much work. Once loaded
(see :ref:`doc_gdscript_classes_as_resources`), the script can be instantiated
with :ref:`new() <class_CSharpScript_method_new>`.
::
var my_csharp_script = load("res://path_to_cs_file.cs")
var my_csharp_node = my_csharp_script.new()
print(my_csharp_node.str2) # barbar
.. warning::
When creating ``.cs`` scripts, you should always keep in mind that the class
Godot will use is the one named like the ``.cs`` file itself. If that class
does not exist in the file, you'll see the following error:
``Invalid call. Nonexistent function `new` in base``.
For example, MyCoolNode.cs should contain a class named MyCoolNode.
You also need to check your ``.cs`` file is referenced in the project's
``.csproj`` file. Otherwise, the same error will occur.
Instantiating GDScript nodes from C#
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
From the C# side, everything work the same way. Once loaded, the GDScript can
be instantiated with :ref:`GDScript.New() <class_GDScript_method_new>`.
.. code-block:: csharp
GDScript MyGDScript = (GDScript) GD.Load("res://path_to_gd_file.gd");
Object myGDScriptNode = (Godot.Object) MyGDScript.New(); // This is a Godot.Object
Here we are using an :ref:`class_Object`, but you can use type conversion like
explained in :ref:`doc_c_sharp_features_type_conversion_and_casting`.
Accessing fields
----------------
Accessing C# fields from GDScript
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Accessing C# fields from GDScript is straightforward, you shouldn't have
anything to worry about.
::
print(my_csharp_node.str1) # bar
my_csharp_node.str1 = "BAR"
print(my_csharp_node.str1) # BAR
print(my_csharp_node.str2) # barbar
# my_csharp_node.str2 = "BARBAR" # This line will hang and crash
Note that it doesn't matter if the field is defined as a property or an
attribute. However, trying to set a value on a property that does not define
a setter will result in a crash.
Accessing GDScript fields from C#
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
As C# is statically typed, accessing GDScript from C# is a bit more
convoluted, you will have to use :ref:`Object.Get() <class_Object_method_get>`
and :ref:`Object.Set() <class_Object_method_set>`. The first argument is the name of the field you want to access.
.. code-block:: csharp
GD.Print(myGDScriptNode.Get("str1")); // foo
myGDScriptNode.Set("str1", "FOO");
GD.Print(myGDScriptNode.Get("str1")); // FOO
GD.Print(myGDScriptNode.Get("str2")); // foofoo
// myGDScriptNode.Set("str2", "FOOFOO"); // This line won't do anything
Keep in mind that when setting a field value you should only use types the
GDScript side knows about.
Essentially, you want to work with built-in types as described in :ref:`doc_gdscript` or classes extending :ref:`class_Object`.
Calling methods
---------------
Calling C# methods from GDScript
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Again, calling C# methods from GDScript should be straightforward. The
marshalling process will do its best to cast the arguments to match
function signatures.
If that's impossible, you'll see the following error: ``Invalid call. Nonexistent function `FunctionName```.
::
my_csharp_node.PrintNodeName(self) # myGDScriptNode
# my_csharp_node.PrintNodeName() # This line will fail.
my_csharp_node.PrintNTimes("Hello there!", 2) # Hello there! Hello there!
my_csharp_node.PrintArray(["a", "b", "c"]) # a, b, c
my_csharp_node.PrintArray([1, 2, 3]) # 1, 2, 3
Calling GDScript methods from C#
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To call GDScript methods from C# you'll need to use
:ref:`Object.Call() <class_Object_method_call>`. The first argument is the
name of the method you want to call. The following arguments will be passed
to said method.
.. code-block:: csharp
myGDScriptNode.Call("print_node_name", this); // my_csharp_node
// myGDScriptNode.Call("print_node_name"); // This line will fail silently and won't error out.
myGDScriptNode.Call("print_n_times", "Hello there!", 2); // Hello there! Hello there!
// When dealing with functions taking a single array as arguments, we need to be careful.
// If we don't cast it into an object, the engine will treat each element of the array as a separate argument and the call will fail.
String[] arr = new String[] { "a", "b", "c" };
// myGDScriptNode.Call("print_array", arr); // This line will fail silently and won't error out.
myGDScriptNode.Call("print_array", (object)arr); // a, b, c
myGDScriptNode.Call("print_array", (object)new int[] { 1, 2, 3 }); // 1, 2, 3
// Note how the type of each array entry does not matter as long as it can be handled by the marshaller
.. warning::
As you can see, if the first argument of the called method is an array,
you'll need to cast it as ``object``.
Otherwise, each element of your array will be treated as a single argument
and the function signature won't match.
Inheritance
-----------
A GDScript file may not inherit from a C# script. Likewise, a C# script may not
inherit from a GDScript file. Due to how complex this would be to implement,
this limitation is unlikely to be lifted in the future. See
`this GitHub issue <https://github.com/godotengine/godot/issues/38352>`__
for more information.

View File

@@ -0,0 +1,528 @@
.. _doc_gdscript_more_efficiently:
GDScript: An introduction to dynamic languages
==============================================
About
-----
This tutorial aims to be a quick reference for how to use GDScript more
efficiently. It focuses on common cases specific to the language, but
also covers a lot of information on dynamically typed languages.
It's meant to be especially useful for programmers with little or no previous
experience with dynamically typed languages.
Dynamic nature
--------------
Pros & cons of dynamic typing
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GDScript is a Dynamically Typed language. As such, its main advantages
are that:
- The language is simple and easy to learn.
- Most code can be written and changed quickly and without hassle.
- Less code written means less errors & mistakes to fix.
- Easier to read the code (less clutter).
- No compilation is required to test.
- Runtime is tiny.
- Duck-typing and polymorphism by nature.
While the main disadvantages are:
- Less performance than statically typed languages.
- More difficult to refactor (symbols can't be traced)
- Some errors that would typically be detected at compile time in
statically typed languages only appear while running the code
(because expression parsing is more strict).
- Less flexibility for code-completion (some variable types are only
known at run-time).
This, translated to reality, means that Godot+GDScript are a combination
designed to create games quickly and efficiently. For games that are very
computationally intensive and can't benefit from the engine built-in
tools (such as the Vector types, Physics Engine, Math library, etc), the
possibility of using C++ is present too. This allows you to still create most of the
game in GDScript and add small bits of C++ in the areas that need
a performance boost.
Variables & assignment
~~~~~~~~~~~~~~~~~~~~~~
All variables in a dynamically typed language are "variant"-like. This
means that their type is not fixed, and is only modified through
assignment. Example:
Static:
.. code-block:: cpp
int a; // Value uninitialized.
a = 5; // This is valid.
a = "Hi!"; // This is invalid.
Dynamic:
::
var a # 'null' by default.
a = 5 # Valid, 'a' becomes an integer.
a = "Hi!" # Valid, 'a' changed to a string.
As function arguments:
~~~~~~~~~~~~~~~~~~~~~~
Functions are of dynamic nature too, which means they can be called with
different arguments, for example:
Static:
.. code-block:: cpp
void print_value(int value) {
printf("value is %i\n", value);
}
[..]
print_value(55); // Valid.
print_value("Hello"); // Invalid.
Dynamic:
::
func print_value(value):
print(value)
[..]
print_value(55) # Valid.
print_value("Hello") # Valid.
Pointers & referencing:
~~~~~~~~~~~~~~~~~~~~~~~
In static languages, such as C or C++ (and to some extent Java and C#),
there is a distinction between a variable and a pointer/reference to a
variable. The latter allows the object to be modified by other functions
by passing a reference to the original one.
In C# or Java, everything not a built-in type (int, float, sometimes
String) is always a pointer or a reference. References are also
garbage-collected automatically, which means they are erased when no
longer used. Dynamically typed languages tend to use this memory model,
too. Some Examples:
- C++:
.. code-block:: cpp
void use_class(SomeClass *instance) {
instance->use();
}
void do_something() {
SomeClass *instance = new SomeClass; // Created as pointer.
use_class(instance); // Passed as pointer.
delete instance; // Otherwise it will leak memory.
}
- Java:
.. code-block:: java
@Override
public final void use_class(SomeClass instance) {
instance.use();
}
public final void do_something() {
SomeClass instance = new SomeClass(); // Created as reference.
use_class(instance); // Passed as reference.
// Garbage collector will get rid of it when not in
// use and freeze your game randomly for a second.
}
- GDScript:
::
func use_class(instance): # Does not care about class type
instance.use() # Will work with any class that has a ".use()" method.
func do_something():
var instance = SomeClass.new() # Created as reference.
use_class(instance) # Passed as reference.
# Will be unreferenced and deleted.
In GDScript, only base types (int, float, string and the vector types)
are passed by value to functions (value is copied). Everything else
(instances, arrays, dictionaries, etc) is passed as reference. Classes
that inherit :ref:`class_Reference` (the default if nothing is specified)
will be freed when not used, but manual memory management is allowed too
if inheriting manually from :ref:`class_Object`.
Arrays
------
Arrays in dynamically typed languages can contain many different mixed
datatypes inside and are always dynamic (can be resized at any time).
Compare for example arrays in statically typed languages:
.. code-block:: cpp
int *array = new int[4]; // Create array.
array[0] = 10; // Initialize manually.
array[1] = 20; // Can't mix types.
array[2] = 40;
array[3] = 60;
// Can't resize.
use_array(array); // Passed as pointer.
delete[] array; // Must be freed.
// or
std::vector<int> array;
array.resize(4);
array[0] = 10; // Initialize manually.
array[1] = 20; // Can't mix types.
array[2] = 40;
array[3] = 60;
array.resize(3); // Can be resized.
use_array(array); // Passed reference or value.
// Freed when stack ends.
And in GDScript:
::
var array = [10, "hello", 40, 60] # Simple, and can mix types.
array.resize(3) # Can be resized.
use_array(array) # Passed as reference.
# Freed when no longer in use.
In dynamically typed languages, arrays can also double as other
datatypes, such as lists:
::
var array = []
array.append(4)
array.append(5)
array.pop_front()
Or unordered sets:
::
var a = 20
if a in [10, 20, 30]:
print("We have a winner!")
Dictionaries
------------
Dictionaries are a powerful tool in dynamically typed languages.
Most programmers that come from statically typed languages (such as C++
or C#) ignore their existence and make their life unnecessarily more
difficult. This datatype is generally not present in such languages (or
only in limited form).
Dictionaries can map any value to any other value with complete
disregard for the datatype used as either key or value. Contrary to
popular belief, they are efficient because they can be implemented
with hash tables. They are, in fact, so efficient that some languages
will go as far as implementing arrays as dictionaries.
Example of Dictionary:
::
var d = {"name": "John", "age": 22} # Simple syntax.
print("Name: ", d["name"], " Age: ", d["age"])
Dictionaries are also dynamic, keys can be added or removed at any point
at little cost:
::
d["mother"] = "Rebecca" # Addition.
d["age"] = 11 # Modification.
d.erase("name") # Removal.
In most cases, two-dimensional arrays can often be implemented more
easily with dictionaries. Here's a simple battleship game example:
::
# Battleship Game
const SHIP = 0
const SHIP_HIT = 1
const WATER_HIT = 2
var board = {}
func initialize():
board[Vector2(1, 1)] = SHIP
board[Vector2(1, 2)] = SHIP
board[Vector2(1, 3)] = SHIP
func missile(pos):
if pos in board: # Something at that position.
if board[pos] == SHIP: # There was a ship! hit it.
board[pos] = SHIP_HIT
else:
print("Already hit here!") # Hey dude you already hit here.
else: # Nothing, mark as water.
board[pos] = WATER_HIT
func game():
initialize()
missile(Vector2(1, 1))
missile(Vector2(5, 8))
missile(Vector2(2, 3))
Dictionaries can also be used as data markup or quick structures. While
GDScript's dictionaries resemble python dictionaries, it also supports Lua
style syntax and indexing, which makes it useful for writing initial
states and quick structs:
::
# Same example, lua-style support.
# This syntax is a lot more readable and usable.
# Like any GDScript identifier, keys written in this form cannot start
# with a digit.
var d = {
name = "John",
age = 22
}
print("Name: ", d.name, " Age: ", d.age) # Used "." based indexing.
# Indexing
d["mother"] = "Rebecca"
d.mother = "Caroline" # This would work too to create a new key.
For & while
-----------
Iterating in some statically typed languages can be quite complex:
.. code-block:: cpp
const char* strings = new const char*[50];
[..]
for (int i = 0; i < 50; i++) {
printf("Value: %s\n", i, strings[i]);
}
// Even in STL:
for (std::list<std::string>::const_iterator it = strings.begin(); it != strings.end(); it++) {
std::cout << *it << std::endl;
}
This is usually greatly simplified in dynamically typed languages:
::
for s in strings:
print(s)
Container datatypes (arrays and dictionaries) are iterable. Dictionaries
allow iterating the keys:
::
for key in dict:
print(key, " -> ", dict[key])
Iterating with indices is also possible:
::
for i in range(strings.size()):
print(strings[i])
The range() function can take 3 arguments:
::
range(n) # Will go from 0 to n-1.
range(b, n) # Will go from b to n-1.
range(b, n, s) # Will go from b to n-1, in steps of s.
Some statically typed programming language examples:
.. code-block:: cpp
for (int i = 0; i < 10; i++) {}
for (int i = 5; i < 10; i++) {}
for (int i = 5; i < 10; i += 2) {}
Translate to:
::
for i in range(10):
pass
for i in range(5, 10):
pass
for i in range(5, 10, 2):
pass
And backwards looping is done through a negative counter:
::
for (int i = 10; i > 0; i--) {}
Becomes:
::
for i in range(10, 0, -1):
pass
While
-----
while() loops are the same everywhere:
::
var i = 0
while i < strings.size():
print(strings[i])
i += 1
Custom iterators
----------------
You can create custom iterators in case the default ones don't quite meet your
needs by overriding the Variant class's ``_iter_init``, ``_iter_next``, and ``_iter_get``
functions in your script. An example implementation of a forward iterator follows:
::
class ForwardIterator:
var start
var current
var end
var increment
func _init(start, stop, increment):
self.start = start
self.current = start
self.end = stop
self.increment = increment
func should_continue():
return (current < end)
func _iter_init(arg):
current = start
return should_continue()
func _iter_next(arg):
current += increment
return should_continue()
func _iter_get(arg):
return current
And it can be used like any other iterator:
::
var itr = ForwardIterator.new(0, 6, 2)
for i in itr:
print(i) # Will print 0, 2, and 4.
Make sure to reset the state of the iterator in ``_iter_init``, otherwise nested
for-loops that use custom iterators will not work as expected.
Duck typing
-----------
One of the most difficult concepts to grasp when moving from a
statically typed language to a dynamic one is duck typing. Duck typing
makes overall code design much simpler and straightforward to write, but
it's not obvious how it works.
As an example, imagine a situation where a big rock is falling down a
tunnel, smashing everything on its way. The code for the rock, in a
statically typed language would be something like:
.. code-block:: cpp
void BigRollingRock::on_object_hit(Smashable *entity) {
entity->smash();
}
This way, everything that can be smashed by a rock would have to
inherit Smashable. If a character, enemy, piece of furniture, small rock
were all smashable, they would need to inherit from the class Smashable,
possibly requiring multiple inheritance. If multiple inheritance was
undesired, then they would have to inherit a common class like Entity.
Yet, it would not be very elegant to add a virtual method ``smash()`` to
Entity only if a few of them can be smashed.
With dynamically typed languages, this is not a problem. Duck typing
makes sure you only have to define a ``smash()`` function where required
and that's it. No need to consider inheritance, base classes, etc.
::
func _on_object_hit(object):
object.smash()
And that's it. If the object that hit the big rock has a smash() method,
it will be called. No need for inheritance or polymorphism. Dynamically
typed languages only care about the instance having the desired method
or member, not what it inherits or the class type. The definition of
Duck Typing should make this clearer:
*"When I see a bird that walks like a duck and swims like a duck and
quacks like a duck, I call that bird a duck"*
In this case, it translates to:
*"If the object can be smashed, don't care what it is, just smash it."*
Yes, we should call it Hulk typing instead.
It's possible that the object being hit doesn't have a smash() function.
Some dynamically typed languages simply ignore a method call when it
doesn't exist, but GDScript is stricter, so checking if the function
exists is desirable:
::
func _on_object_hit(object):
if object.has_method("smash"):
object.smash()
Then, simply define that method and anything the rock touches can be
smashed.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,289 @@
.. _doc_gdscript_exports:
GDScript exports
================
Introduction to exports
-----------------------
In Godot, class members can be exported. This means their value gets saved along
with the resource (such as the :ref:`scene <class_PackedScene>`) they're
attached to. They will also be available for editing in the property editor.
Exporting is done by using the ``export`` keyword::
extends Button
export var number = 5 # Value will be saved and visible in the property editor.
An exported variable must be initialized to a constant expression or have an
export hint in the form of an argument to the ``export`` keyword (see the
*Examples* section below).
One of the fundamental benefits of exporting member variables is to have
them visible and editable in the editor. This way, artists and game designers
can modify values that later influence how the program runs. For this, a
special export syntax is provided.
.. note::
Exporting properties can also be done in other languages such as C#.
The syntax varies depending on the language. See :ref:`doc_c_sharp_exports`
for information on C# exports.
Examples
--------
::
# If the exported value assigns a constant or constant expression,
# the type will be inferred and used in the editor.
export var number = 5
# Export can take a basic data type as an argument, which will be
# used in the editor.
export(int) var number
# Export can also take a resource type to use as a hint.
export(Texture) var character_face
export(PackedScene) var scene_file
# There are many resource types that can be used this way, try e.g.
# the following to list them:
export(Resource) var resource
# Integers and strings hint enumerated values.
# Editor will enumerate as 0, 1 and 2.
export(int, "Warrior", "Magician", "Thief") var character_class
# Editor will enumerate with string names.
export(String, "Rebecca", "Mary", "Leah") var character_name
# Named enum values
# Editor will enumerate as THING_1, THING_2, ANOTHER_THING.
enum NamedEnum {THING_1, THING_2, ANOTHER_THING = -1}
export(NamedEnum) var x
# Strings as paths
# String is a path to a file.
export(String, FILE) var f
# String is a path to a directory.
export(String, DIR) var f
# String is a path to a file, custom filter provided as hint.
export(String, FILE, "*.txt") var f
# Using paths in the global filesystem is also possible,
# but only in scripts in "tool" mode.
# String is a path to a PNG file in the global filesystem.
export(String, FILE, GLOBAL, "*.png") var tool_image
# String is a path to a directory in the global filesystem.
export(String, DIR, GLOBAL) var tool_dir
# The MULTILINE setting tells the editor to show a large input
# field for editing over multiple lines.
export(String, MULTILINE) var text
# Limiting editor input ranges
# Allow integer values from 0 to 20.
export(int, 20) var i
# Allow integer values from -10 to 20.
export(int, -10, 20) var j
# Allow floats from -10 to 20 and snap the value to multiples of 0.2.
export(float, -10, 20, 0.2) var k
# Allow values 'y = exp(x)' where 'y' varies between 100 and 1000
# while snapping to steps of 20. The editor will present a
# slider for easily editing the value.
export(float, EXP, 100, 1000, 20) var l
# Floats with easing hint
# Display a visual representation of the 'ease()' function
# when editing.
export(float, EASE) var transition_speed
# Colors
# Color given as red-green-blue value (alpha will always be 1).
export(Color, RGB) var col
# Color given as red-green-blue-alpha value.
export(Color, RGBA) var col
# Nodes
# Another node in the scene can be exported as a NodePath.
export(NodePath) var node_path
# Do take note that the node itself isn't being exported -
# there is one more step to call the true node:
var node = get_node(node_path)
# Resources
export(Resource) var resource
# In the Inspector, you can then drag and drop a resource file
# from the FileSystem dock into the variable slot.
# Opening the inspector dropdown may result in an
# extremely long list of possible classes to create, however.
# Therefore, if you specify an extension of Resource such as:
export(AnimationNode) var resource
# The drop-down menu will be limited to AnimationNode and all
# its inherited classes.
It must be noted that even if the script is not being run while in the
editor, the exported properties are still editable. This can be used
in conjunction with a :ref:`script in "tool" mode <doc_gdscript_tool_mode>`.
Exporting bit flags
-------------------
Integers used as bit flags can store multiple ``true``/``false`` (boolean)
values in one property. By using the export hint ``int, FLAGS, ...``, they
can be set from the editor::
# Set any of the given flags from the editor.
export(int, FLAGS, "Fire", "Water", "Earth", "Wind") var spell_elements = 0
You must provide a string description for each flag. In this example, ``Fire``
has value 1, ``Water`` has value 2, ``Earth`` has value 4 and ``Wind``
corresponds to value 8. Usually, constants should be defined accordingly (e.g.
``const ELEMENT_WIND = 8`` and so on).
Export hints are also provided for the physics and render layers defined in the project settings::
export(int, LAYERS_2D_PHYSICS) var layers_2d_physics
export(int, LAYERS_2D_RENDER) var layers_2d_render
export(int, LAYERS_3D_PHYSICS) var layers_3d_physics
export(int, LAYERS_3D_RENDER) var layers_3d_render
Using bit flags requires some understanding of bitwise operations.
If in doubt, use boolean variables instead.
Exporting arrays
----------------
Exported arrays can have initializers, but they must be constant expressions.
If the exported array specifies a type which inherits from Resource, the array
values can be set in the inspector by dragging and dropping multiple files
from the FileSystem dock at once.
::
# Default value must be a constant expression.
export var a = [1, 2, 3]
# Exported arrays can specify type (using the same hints as before).
export(Array, int) var ints = [1, 2, 3]
export(Array, int, "Red", "Green", "Blue") var enums = [2, 1, 0]
export(Array, Array, float) var two_dimensional = [[1.0, 2.0], [3.0, 4.0]]
# You can omit the default value, but then it would be null if not assigned.
export(Array) var b
export(Array, PackedScene) var scenes
# Arrays with specified types which inherit from resource can be set by
# drag-and-dropping multiple files from the FileSystem dock.
export(Array, Texture) var textures
export(Array, PackedScene) var scenes
# Typed arrays also work, only initialized empty:
export var vector3s = PoolVector3Array()
export var strings = PoolStringArray()
# Default value can include run-time values, but can't
# be exported.
var c = [a, 2, 3]
Setting exported variables from a tool script
---------------------------------------------
When changing an exported variable's value from a script in
:ref:`doc_gdscript_tool_mode`, the value in the inspector won't be updated
automatically. To update it, call
:ref:`property_list_changed_notify() <class_Object_method_property_list_changed_notify>`
after setting the exported variable's value.
Advanced exports
----------------
Not every type of export can be provided on the level of the language itself to
avoid unnecessary design complexity. The following describes some more or less
common exporting features which can be implemented with a low-level API.
Before reading further, you should get familiar with the way properties are
handled and how they can be customized with
:ref:`_set() <class_Object_method__get_property_list>`,
:ref:`_get() <class_Object_method__get_property_list>`, and
:ref:`_get_property_list() <class_Object_method__get_property_list>` methods as
described in :ref:`doc_accessing_data_or_logic_from_object`.
.. seealso:: For binding properties using the above methods in C++, see
:ref:`doc_binding_properties_using_set_get_property_list`.
.. warning:: The script must operate in the ``tool`` mode so the above methods
can work from within the editor.
Adding script categories
~~~~~~~~~~~~~~~~~~~~~~~~
For better visual distinguishing of properties, a special script category can be
embedded into the inspector to act as a separator. ``Script Variables`` is one
example of a built-in category.
::
func _get_property_list():
var properties = []
properties.append(
{
name = "Debug",
type = TYPE_NIL,
usage = PROPERTY_USAGE_CATEGORY | PROPERTY_USAGE_SCRIPT_VARIABLE
}
)
return properties
* ``name`` is the name of a category to be added to the inspector;
* ``PROPERTY_USAGE_CATEGORY`` indicates that the property should be treated as a
script category specifically, so the type ``TYPE_NIL`` can be ignored as it
won't be actually used for the scripting logic, yet it must be defined anyway.
Grouping properties
~~~~~~~~~~~~~~~~~~~
A list of properties with similar names can be grouped.
::
func _get_property_list():
var properties = []
properties.append({
name = "Rotate",
type = TYPE_NIL,
hint_string = "rotate_",
usage = PROPERTY_USAGE_GROUP | PROPERTY_USAGE_SCRIPT_VARIABLE
})
return properties
* ``name`` is the name of a group which is going to be displayed as collapsible
list of properties;
* every successive property added after the group property will be collapsed and
shortened as determined by the prefix defined via the ``hint_string`` key. For
instance, ``rotate_speed`` is going to be shortened to ``speed`` in this case.
* ``PROPERTY_USAGE_GROUP`` indicates that the property should be treated as a
script group specifically, so the type ``TYPE_NIL`` can be ignored as it
won't be actually used for the scripting logic, yet it must be defined anyway.

View File

@@ -0,0 +1,280 @@
.. _doc_gdscript_printf:
GDScript format strings
=======================
GDScript offers a feature called *format strings*, which allows reusing text
templates to succinctly create different but similar strings.
Format strings are just like normal strings, except they contain certain
placeholder character-sequences. These placeholders can then easily be replaced
by parameters handed to the format string.
As an example, with ``%s`` as a placeholder, the format string ``"Hello %s, how
are you?`` can easily be changed to ``"Hello World, how are you?"``. Notice
the placeholder is in the middle of the string; modifying it without format
strings could be cumbersome.
Usage in GDScript
-----------------
Examine this concrete GDScript example:
::
# Define a format string with placeholder '%s'
var format_string = "We're waiting for %s."
# Using the '%' operator, the placeholder is replaced with the desired value
var actual_string = format_string % "Godot"
print(actual_string)
# Output: "We're waiting for Godot."
Placeholders always start with a ``%``, but the next character or characters,
the *format specifier*, determines how the given value is converted to a
string.
The ``%s`` seen in the example above is the simplest placeholder and works for
most use cases: it converts the value by the same method by which an implicit
String conversion or ``str()`` would convert it. Strings remain unchanged,
Booleans turn into either ``"True"`` or ``"False"``, an integral or real number
becomes a decimal, other types usually return their data in a human-readable
string.
There is also another way to format text in GDScript, namely the ``String.format()``
method. It replaces all occurrences of a key in the string with the corresponding
value. The method can handle arrays or dictionaries for the key/value pairs.
Arrays can be used as key, index, or mixed style (see below examples). Order only
matters when the index or mixed style of Array is used.
A quick example in GDScript:
::
# Define a format string
var format_string = "We're waiting for {str}"
# Using the 'format' method, replace the 'str' placeholder
var actual_string = format_string.format({"str": "Godot"})
print(actual_string)
# Output: "We're waiting for Godot"
There are other `format specifiers`_, but they are only applicable when using
the ``%`` operator.
Multiple placeholders
---------------------
Format strings may contain multiple placeholders. In such a case, the values
are handed in the form of an array, one value per placeholder (unless using a
format specifier with ``*``, see `dynamic padding`_):
::
var format_string = "%s was reluctant to learn %s, but now he enjoys it."
var actual_string = format_string % ["Estragon", "GDScript"]
print(actual_string)
# Output: "Estragon was reluctant to learn GDScript, but now he enjoys it."
Note the values are inserted in order. Remember all placeholders must be
replaced at once, so there must be an appropriate number of values.
Format specifiers
-----------------
There are format specifiers other than ``s`` that can be used in placeholders.
They consist of one or more characters. Some of them work by themselves like
``s``, some appear before other characters, some only work with certain
values or characters.
Placeholder types
~~~~~~~~~~~~~~~~~
One and only one of these must always appear as the last character in a format
specifier. Apart from ``s``, these require certain types of parameters.
+-------+---------------------------------------------------------------------+
| ``s`` | **Simple** conversion to String by the same method as implicit |
| | String conversion. |
+-------+---------------------------------------------------------------------+
| ``c`` | A single **Unicode character**. Expects an unsigned 8-bit integer |
| | (0-255) for a code point or a single-character string. |
+-------+---------------------------------------------------------------------+
| ``d`` | A **decimal integral** number. Expects an integral or real number |
| | (will be floored). |
+-------+---------------------------------------------------------------------+
| ``o`` | An **octal integral** number. Expects an integral or real number |
| | (will be floored). |
+-------+---------------------------------------------------------------------+
| ``x`` | A **hexadecimal integral** number with **lower-case** letters. |
| | Expects an integral or real number (will be floored). |
+-------+---------------------------------------------------------------------+
| ``X`` | A **hexadecimal integral** number with **upper-case** letters. |
| | Expects an integral or real number (will be floored). |
+-------+---------------------------------------------------------------------+
| ``f`` | A **decimal real** number. Expects an integral or real number. |
+-------+---------------------------------------------------------------------+
Placeholder modifiers
~~~~~~~~~~~~~~~~~~~~~
These characters appear before the above. Some of them work only under certain
conditions.
+---------+-------------------------------------------------------------------+
| ``+`` | In number specifiers, **show + sign** if positive. |
+---------+-------------------------------------------------------------------+
| Integer | Set **padding**. Padded with spaces or with zeroes if integer |
| | starts with ``0`` in an integer placeholder. When used after |
| | ``.``, see ``.``. |
+---------+-------------------------------------------------------------------+
| ``.`` | Before ``f``, set **precision** to 0 decimal places. Can be |
| | followed up with numbers to change. Padded with zeroes. |
+---------+-------------------------------------------------------------------+
| ``-`` | **Pad to the right** rather than the left. |
+---------+-------------------------------------------------------------------+
| ``*`` | **Dynamic padding**, expect additional integral parameter to set |
| | padding or precision after ``.``, see `dynamic padding`_. |
+---------+-------------------------------------------------------------------+
Padding
-------
The ``.`` (*dot*), ``*`` (*asterisk*), ``-`` (*minus sign*) and digit
(``0``-``9``) characters are used for padding. This allows printing several
values aligned vertically as if in a column, provided a fixed-width font is
used.
To pad a string to a minimum length, add an integer to the specifier:
::
print("%10d" % 12345)
# output: " 12345"
# 5 leading spaces for a total length of 10
If the integer starts with ``0``, integral values are padded with zeroes
instead of white space:
::
print("%010d" % 12345)
# output: "0000012345"
Precision can be specified for real numbers by adding a ``.`` (*dot*) with an
integer following it. With no integer after ``.``, a precision of 0 is used,
rounding to integral value. The integer to use for padding must appear before
the dot.
::
# Pad to minimum length of 10, round to 3 decimal places
print("%10.3f" % 10000.5555)
# Output: " 10000.556"
# 1 leading space
The ``-`` character will cause padding to the right rather than the left,
useful for right text alignment:
::
print("%-10d" % 12345678)
# Output: "12345678 "
# 2 trailing spaces
Dynamic padding
~~~~~~~~~~~~~~~
By using the ``*`` (*asterisk*) character, the padding or precision can be set
without modifying the format string. It is used in place of an integer in the
format specifier. The values for padding and precision are then passed when
formatting:
::
var format_string = "%*.*f"
# Pad to length of 7, round to 3 decimal places:
print(format_string % [7, 3, 8.8888])
# Output: " 8.889"
# 2 leading spaces
It is still possible to pad with zeroes in integer placeholders by adding ``0``
before ``*``:
::
print("%0*d" % [2, 3])
# Output: "03"
Escape sequence
---------------
To insert a literal ``%`` character into a format string, it must be escaped to
avoid reading it as a placeholder. This is done by doubling the character:
::
var health = 56
print("Remaining health: %d%%" % health)
# Output: "Remaining health: 56%"
Format method examples
----------------------
The following are some examples of how to use the various invocations of the
``String.format`` method.
+------------+-----------+------------------------------------------------------------------------------+-------------------+
| **Type** | **Style** | **Example** | **Result** |
+------------+-----------+------------------------------------------------------------------------------+-------------------+
| Dictionary | key | ``"Hi, {name} v{version}!".format({"name":"Godette", "version":"3.0"})`` | Hi, Godette v3.0! |
+------------+-----------+------------------------------------------------------------------------------+-------------------+
| Dictionary | index | ``"Hi, {0} v{1}!".format({"0":"Godette", "1":"3.0"})`` | Hi, Godette v3.0! |
+------------+-----------+------------------------------------------------------------------------------+-------------------+
| Dictionary | mix | ``"Hi, {0} v{version}!".format({"0":"Godette", "version":"3.0"})`` | Hi, Godette v3.0! |
+------------+-----------+------------------------------------------------------------------------------+-------------------+
| Array | key | ``"Hi, {name} v{version}!".format([["version","3.0"], ["name","Godette"]])`` | Hi, Godette v3.0! |
+------------+-----------+------------------------------------------------------------------------------+-------------------+
| Array | index | ``"Hi, {0} v{1}!".format(["Godette","3.0"])`` | Hi, Godette v3.0! |
+------------+-----------+------------------------------------------------------------------------------+-------------------+
| Array | mix | ``"Hi, {name} v{0}!".format([3.0, ["name","Godette"]])`` | Hi, Godette v3.0! |
+------------+-----------+------------------------------------------------------------------------------+-------------------+
| Array | no index | ``"Hi, {} v{}!".format(["Godette", 3.0], "{}")`` | Hi, Godette v3.0! |
+------------+-----------+------------------------------------------------------------------------------+-------------------+
Placeholders can also be customized when using ``String.format``, here's some
examples of that functionality.
+-----------------+------------------------------------------------------+------------------+
| **Type** | **Example** | **Result** |
+-----------------+------------------------------------------------------+------------------+
| Infix (default) | ``"Hi, {0} v{1}".format(["Godette", "3.0"], "{_}")`` | Hi, Godette v3.0 |
+-----------------+------------------------------------------------------+------------------+
| Postfix | ``"Hi, 0% v1%".format(["Godette", "3.0"], "_%")`` | Hi, Godette v3.0 |
+-----------------+------------------------------------------------------+------------------+
| Prefix | ``"Hi, %0 v%1".format(["Godette", "3.0"], "%_")`` | Hi, Godette v3.0 |
+-----------------+------------------------------------------------------+------------------+
Combining both the ``String.format`` method and the ``%`` operator could be useful, as
``String.format`` does not have a way to manipulate the representation of numbers.
+---------------------------------------------------------------------------+-------------------+
| **Example** | **Result** |
+---------------------------------------------------------------------------+-------------------+
| ``"Hi, {0} v{version}".format({0:"Godette", "version":"%0.2f" % 3.114})`` | Hi, Godette v3.11 |
+---------------------------------------------------------------------------+-------------------+

View File

@@ -0,0 +1,839 @@
.. _doc_gdscript_styleguide:
GDScript style guide
====================
This style guide lists conventions to write elegant GDScript. The goal is to
encourage writing clean, readable code and promote consistency across projects,
discussions, and tutorials. Hopefully, this will also support the development of
auto-formatting tools.
Since GDScript is close to Python, this guide is inspired by Python's
`PEP 8 <https://www.python.org/dev/peps/pep-0008/>`__ programming
style guide.
Style guides aren't meant as hard rulebooks. At times, you may not be able to
apply some of the guidelines below. When that happens, use your best judgment,
and ask fellow developers for insights.
In general, keeping your code consistent in your projects and within your team is
more important than following this guide to a tee.
.. note:: Godot's built-in script editor uses a lot of these conventions
by default. Let it help you.
Here is a complete class example based on these guidelines:
::
class_name StateMachine
extends Node
# Hierarchical State machine for the player.
# Initializes states and delegates engine callbacks
# (_physics_process, _unhandled_input) to the state.
signal state_changed(previous, new)
export var initial_state = NodePath()
var is_active = true setget set_is_active
onready var _state = get_node(initial_state) setget set_state
onready var _state_name = _state.name
func _init():
add_to_group("state_machine")
func _ready():
connect("state_changed", self, "_on_state_changed")
_state.enter()
func _unhandled_input(event):
_state.unhandled_input(event)
func _physics_process(delta):
_state.physics_process(delta)
func transition_to(target_state_path, msg={}):
if not has_node(target_state_path):
return
var target_state = get_node(target_state_path)
assert(target_state.is_composite == false)
_state.exit()
self._state = target_state
_state.enter(msg)
Events.emit_signal("player_state_changed", _state.name)
func set_is_active(value):
is_active = value
set_physics_process(value)
set_process_unhandled_input(value)
set_block_signals(not value)
func set_state(value):
_state = value
_state_name = _state.name
func _on_state_changed(previous, new):
print("state changed")
emit_signal("state_changed")
.. _formatting:
Formatting
----------
Encoding and special characters
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Use line feed (**LF**) characters to break lines, not CRLF or CR. *(editor default)*
* Use one line feed character at the end of each file. *(editor default)*
* Use **UTF-8** encoding without a `byte order mark <https://en.wikipedia.org/wiki/Byte_order_mark>`_. *(editor default)*
* Use **Tabs** instead of spaces for indentation. *(editor default)*
Indentation
~~~~~~~~~~~
Each indent level should be one greater than the block containing it.
**Good**:
::
for i in range(10):
print("hello")
**Bad**:
::
for i in range(10):
print("hello")
for i in range(10):
print("hello")
Use 2 indent levels to distinguish continuation lines from
regular code blocks.
**Good**:
::
effect.interpolate_property(sprite, "transform/scale",
sprite.get_scale(), Vector2(2.0, 2.0), 0.3,
Tween.TRANS_QUAD, Tween.EASE_OUT)
**Bad**:
::
effect.interpolate_property(sprite, "transform/scale",
sprite.get_scale(), Vector2(2.0, 2.0), 0.3,
Tween.TRANS_QUAD, Tween.EASE_OUT)
Exceptions to this rule are arrays, dictionaries, and enums. Use a single
indentation level to distinguish continuation lines:
**Good**:
::
var party = [
"Godot",
"Godette",
"Steve",
]
var character_dict = {
"Name": "Bob",
"Age": 27,
"Job": "Mechanic",
}
enum Tiles {
TILE_BRICK,
TILE_FLOOR,
TILE_SPIKE,
TILE_TELEPORT,
}
**Bad**:
::
var party = [
"Godot",
"Godette",
"Steve",
]
var character_dict = {
"Name": "Bob",
"Age": 27,
"Job": "Mechanic",
}
enum Tiles {
TILE_BRICK,
TILE_FLOOR,
TILE_SPIKE,
TILE_TELEPORT,
}
Trailing comma
~~~~~~~~~~~~~~
Use a trailing comma on the last line in arrays, dictionaries, and enums. This
results in easier refactoring and better diffs in version control as the last
line doesn't need to be modified when adding new elements.
**Good**:
::
enum Tiles {
TILE_BRICK,
TILE_FLOOR,
TILE_SPIKE,
TILE_TELEPORT,
}
**Bad**:
::
enum Tiles {
TILE_BRICK,
TILE_FLOOR,
TILE_SPIKE,
TILE_TELEPORT
}
Trailing commas are unnecessary in single-line lists, so don't add them in this case.
**Good**:
::
enum Tiles {TILE_BRICK, TILE_FLOOR, TILE_SPIKE, TILE_TELEPORT}
**Bad**:
::
enum Tiles {TILE_BRICK, TILE_FLOOR, TILE_SPIKE, TILE_TELEPORT,}
Blank lines
~~~~~~~~~~~
Surround functions and class definitions with two blank lines:
::
func heal(amount):
health += amount
health = min(health, max_health)
emit_signal("health_changed", health)
func take_damage(amount, effect=null):
health -= amount
health = max(0, health)
emit_signal("health_changed", health)
Use one blank line inside functions to separate logical sections.
Line length
~~~~~~~~~~~
Keep individual lines of code under 100 characters.
If you can, try to keep lines under 80 characters. This helps to read the code
on small displays and with two scripts opened side-by-side in an external text
editor. For example, when looking at a differential revision.
One statement per line
~~~~~~~~~~~~~~~~~~~~~~
Never combine multiple statements on a single line. No, C programmers,
not even with a single line conditional statement.
**Good**:
::
if position.x > width:
position.x = 0
if flag:
print("flagged")
**Bad**:
::
if position.x > width: position.x = 0
if flag: print("flagged")
The only exception to that rule is the ternary operator:
::
next_state = "fall" if not is_on_floor() else "idle"
Format multiline statements for readability
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When you have particularly long ``if`` statements or nested ternary expressions,
wrapping them over multiple lines improves readability. Since continuation lines
are still part of the same expression, 2 indent levels should be used instead of one.
GDScript allows wrapping statements using multiple lines using parentheses or
backslashes. Parentheses are favored in this style guide since they make for
easier refactoring. With backslashes, you have to ensure that the last line
never contains a backslash at the end. With parentheses, you don't have to
worry about the last line having a backslash at the end.
When wrapping a conditional expression over multiple lines, the ``and``/``or``
keywords should be placed at the beginning of the line continuation, not at the
end of the previous line.
**Good**:
::
var angle_degrees = 135
var quadrant = (
"northeast" if angle_degrees <= 90
else "southeast" if angle_degrees <= 180
else "southwest" if angle_degrees <= 270
else "northwest"
)
var position = Vector2(250, 350)
if (
position.x > 200 and position.x < 400
and position.y > 300 and position.y < 400
):
pass
**Bad**:
::
var angle_degrees = 135
var quadrant = "northeast" if angle_degrees <= 90 else "southeast" if angle_degrees <= 180 else "southwest" if angle_degrees <= 270 else "northwest"
var position = Vector2(250, 350)
if position.x > 200 and position.x < 400 and position.y > 300 and position.y < 400:
pass
Avoid unnecessary parentheses
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Avoid parentheses in expressions and conditional statements. Unless
necessary for order of operations or wrapping over multiple lines,
they only reduce readability.
**Good**:
::
if is_colliding():
queue_free()
**Bad**:
::
if (is_colliding()):
queue_free()
Boolean operators
~~~~~~~~~~~~~~~~~
Prefer the plain English versions of boolean operators, as they are the most accessible:
- Use ``and`` instead of ``&&``.
- Use ``or`` instead of ``||``.
You may also use parentheses around boolean operators to clear any ambiguity.
This can make long expressions easier to read.
**Good**:
::
if (foo and bar) or baz:
print("condition is true")
**Bad**:
::
if foo && bar || baz:
print("condition is true")
Comment spacing
~~~~~~~~~~~~~~~
Regular comments should start with a space, but not code that you comment out.
This helps differentiate text comments from disabled code.
**Good**:
::
# This is a comment.
#print("This is disabled code")
**Bad**:
::
#This is a comment.
# print("This is disabled code")
.. note::
In the script editor, to toggle the selected code commented, press
:kbd:`Ctrl + K`. This feature adds a single # sign at the start
of the selected lines.
Whitespace
~~~~~~~~~~
Always use one space around operators and after commas. Also, avoid extra spaces
in dictionary references and function calls.
**Good**:
::
position.x = 5
position.y = target_position.y + 10
dict["key"] = 5
my_array = [4, 5, 6]
print("foo")
**Bad**:
::
position.x=5
position.y = mpos.y+10
dict ["key"] = 5
myarray = [4,5,6]
print ("foo")
Don't use spaces to align expressions vertically:
::
x = 100
y = 100
velocity = 500
Quotes
~~~~~~
Use double quotes unless single quotes make it possible to escape fewer
characters in a given string. See the examples below:
::
# Normal string.
print("hello world")
# Use double quotes as usual to avoid escapes.
print("hello 'world'")
# Use single quotes as an exception to the rule to avoid escapes.
print('hello "world"')
# Both quote styles would require 2 escapes; prefer double quotes if it's a tie.
print("'hello' \"world\"")
Numbers
~~~~~~~
Don't omit the leading or trailing zero in floating-point numbers. Otherwise,
this makes them less readable and harder to distinguish from integers at a
glance.
**Good**::
var float_number = 0.234
var other_float_number = 13.0
**Bad**::
var float_number = .234
var other_float_number = 13.
Use lowercase for letters in hexadecimal numbers, as their lower height makes
the number easier to read.
**Good**::
var hex_number = 0xfb8c0b
**Bad**::
var hex_number = 0xFB8C0B
Take advantage of GDScript's underscores in literals to make large numbers more
readable.
**Good**::
var large_number = 1_234_567_890
var large_hex_number = 0xffff_f8f8_0000
var large_bin_number = 0b1101_0010_1010
# Numbers lower than 1000000 generally don't need separators.
var small_number = 12345
**Bad**::
var large_number = 1234567890
var large_hex_number = 0xfffff8f80000
var large_bin_number = 0b110100101010
# Numbers lower than 1000000 generally don't need separators.
var small_number = 12_345
.. _naming_conventions:
Naming conventions
------------------
These naming conventions follow the Godot Engine style. Breaking these will make
your code clash with the built-in naming conventions, leading to inconsistent
code.
File names
~~~~~~~~~~
Use snake_case for file names. For named classes, convert the PascalCase class
name to snake_case::
# This file should be saved as `weapon.gd`.
class_name Weapon
extends Node
::
# This file should be saved as `yaml_parser.gd`.
class_name YAMLParser
extends Object
This is consistent with how C++ files are named in Godot's source code. This
also avoids case sensitivity issues that can crop up when exporting a project
from Windows to other platforms.
Classes and nodes
~~~~~~~~~~~~~~~~~
Use PascalCase for class and node names:
::
extends KinematicBody
Also use PascalCase when loading a class into a constant or a variable:
::
const Weapon = preload("res://weapon.gd")
Functions and variables
~~~~~~~~~~~~~~~~~~~~~~~
Use snake\_case to name functions and variables:
::
var particle_effect
func load_level():
Prepend a single underscore (\_) to virtual methods functions the user must
override, private functions, and private variables:
::
var _counter = 0
func _recalculate_path():
Signals
~~~~~~~
Use the past tense to name signals:
::
signal door_opened
signal score_changed
Constants and enums
~~~~~~~~~~~~~~~~~~~
Write constants with CONSTANT\_CASE, that is to say in all caps with an
underscore (\_) to separate words:
::
const MAX_SPEED = 200
Use PascalCase for enum *names* and CONSTANT\_CASE for their members, as they
are constants:
::
enum Element {
EARTH,
WATER,
AIR,
FIRE,
}
Code order
----------
This first section focuses on code order. For formatting, see
:ref:`formatting`. For naming conventions, see :ref:`naming_conventions`.
We suggest to organize GDScript code this way:
::
01. tool
02. class_name
03. extends
04. # docstring
05. signals
06. enums
07. constants
08. exported variables
09. public variables
10. private variables
11. onready variables
12. optional built-in virtual _init method
13. built-in virtual _ready method
14. remaining built-in virtual methods
15. public methods
16. private methods
We optimized the order to make it easy to read the code from top to bottom, to
help developers reading the code for the first time understand how it works, and
to avoid errors linked to the order of variable declarations.
This code order follows four rules of thumb:
1. Properties and signals come first, followed by methods.
2. Public comes before private.
3. Virtual callbacks come before the class's interface.
4. The object's construction and initialization functions, ``_init`` and
``_ready``, come before functions that modify the object at runtime.
Class declaration
~~~~~~~~~~~~~~~~~
If the code is meant to run in the editor, place the ``tool`` keyword on the
first line of the script.
Follow with the `class_name` if necessary. You can turn a GDScript file into a
global type in your project using this feature. For more information, see
:ref:`doc_gdscript`.
Then, add the `extends` keyword if the class extends a built-in type.
Following that, you should have the class's optional docstring as comments. You
can use that to explain the role of your class to your teammates, how it works,
and how other developers should use it, for example.
::
class_name MyNode
extends Node
# A brief description of the class's role and functionality.
# Longer description.
Signals and properties
~~~~~~~~~~~~~~~~~~~~~~
Write signal declarations, followed by properties, that is to say, member
variables, after the docstring.
Enums should come after signals, as you can use them as export hints for other
properties.
Then, write constants, exported variables, public, private, and onready
variables, in that order.
::
signal spawn_player(position)
enum Jobs {KNIGHT, WIZARD, ROGUE, HEALER, SHAMAN}
const MAX_LIVES = 3
export(Jobs) var job = Jobs.KNIGHT
export var max_health = 50
export var attack = 5
var health = max_health setget set_health
var _speed = 300.0
onready var sword = get_node("Sword")
onready var gun = get_node("Gun")
.. note::
The GDScript compiler evaluates onready variables right before the ``_ready``
callback. You can use that to cache node dependencies, that is to say, to get
child nodes in the scene that your class relies on. This is what the example
above shows.
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.
Methods and static functions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
After the class's properties come the methods.
Start with the ``_init()`` callback method, that the engine will call upon
creating the object in memory. Follow with the ``_ready()`` callback, that Godot
calls when it adds a node to the scene tree.
These functions should come first because they show how the object is
initialized.
Other built-in virtual callbacks, like ``_unhandled_input()`` and
``_physics_process``, should come next. These control the object's main loop and
interactions with the game engine.
The rest of the class's interface, public and private methods, come after that,
in that order.
::
func _init():
add_to_group("state_machine")
func _ready():
connect("state_changed", self, "_on_state_changed")
_state.enter()
func _unhandled_input(event):
_state.unhandled_input(event)
func transition_to(target_state_path, msg={}):
if not has_node(target_state_path):
return
var target_state = get_node(target_state_path)
assert(target_state.is_composite == false)
_state.exit()
self._state = target_state
_state.enter(msg)
Events.emit_signal("player_state_changed", _state.name)
func _on_state_changed(previous, new):
print("state changed")
emit_signal("state_changed")
Static typing
-------------
Since Godot 3.1, GDScript supports :ref:`optional static typing<doc_gdscript_static_typing>`.
Declared types
~~~~~~~~~~~~~~
To declare a variable's type, use ``<variable>: <type>``:
::
var health: int = 0
To declare the return type of a function, use ``-> <type>``:
::
func heal(amount: int) -> void:
Inferred types
~~~~~~~~~~~~~~
In most cases you can let the compiler infer the type, using ``:=``:
::
var health := 0 # The compiler will use the int type.
However, in a few cases when context is missing, the compiler falls back to
the function's return type. For example, ``get_node()`` cannot infer a type
unless the scene or file of the node is loaded in memory. In this case, you
should set the type explicitly.
**Good**:
::
onready var health_bar: ProgressBar = get_node("UI/LifeBar")
Alternatively, you can use the ``as`` keyword to cast the return type, and
that type will be used to infer the type of the var.
.. rst-class:: code-example-good
::
onready var health_bar := get_node("UI/LifeBar") as ProgressBar
# health_bar will be typed as ProgressBar
This option is also considered more :ref:`type-safe<doc_gdscript_static_typing_safe_lines>` than the first.
**Bad**:
::
# The compiler can't infer the exact type and will use Node
# instead of ProgressBar.
onready var health_bar := get_node("UI/LifeBar")

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

View File

@@ -0,0 +1,19 @@
GDScript
========
.. toctree::
:maxdepth: 1
:name: toc-learn-scripting-gdscript
gdscript_basics
gdscript_advanced
gdscript_exports
gdscript_styleguide
static_typing
warning_system
gdscript_format_string
.. seealso::
See :ref:`doc_gdscript_grammar` if you are interested in writing a third-party
tool that interacts with GDScript, such as a linter or formatter.

View File

@@ -0,0 +1,386 @@
.. _doc_gdscript_static_typing:
Static typing in GDScript
=========================
In this guide, you will learn:
- **How to use types in GDScript**
- That **static types can help you avoid bugs**
Where and how you use this new language feature is entirely up to you:
you can use it only in some sensitive GDScript files, use it everywhere,
or write code like you always did!
Static types can be used on variables, constants, functions, parameters,
and return types.
.. note::
Typed GDScript is available since Godot 3.1.
A brief look at static typing
-----------------------------
With typed GDScript, Godot can detect even more errors as you write
code! It gives you and your teammates more information as you're
working, as the arguments' types show up when you call a method.
Imagine you're programming an inventory system. You code an ``Item``
node, then an ``Inventory``. To add items to the inventory, the people
who work with your code should always pass an ``Item`` to the
``Inventory.add`` method. With types, you can enforce this:
::
# In 'Item.gd'.
class_name Item
# In 'Inventory.gd'.
class_name Inventory
func add(reference: Item, amount: int = 1):
var item = find_item(reference)
if not item:
item = _instance_item_from_db(reference)
item.amount += amount
Another significant advantage of typed GDScript is the new **warning
system**. From version 3.1, Godot gives you warnings about your code as
you write it: the engine identifies sections of your code that may lead
to issues at runtime, but lets you decide whether or not you want to
leave the code as it is. More on that in a moment.
Static types also give you better code completion options. Below, you
can see the difference between a dynamic and a static typed completion
options for a class called ``PlayerController``.
You've probably stored a node in a variable before, and typed a dot to
be left with no autocomplete suggestions:
.. figure:: img/typed_gdscript_code_completion_dynamic.png
:alt: code completion options for dynamic
This is due to dynamic code. Godot cannot know what node or value type
you're passing to the function. If you write the type explicitly
however, you will get all public methods and variables from the node:
.. figure:: img/typed_gdscript_code_completion_typed.png
:alt: code completion options for typed
In the future, typed GDScript will also increase code performance:
Just-In-Time compilation and other compiler improvements are already
on the roadmap!
Overall, typed programming gives you a more structured experience. It
helps prevent errors and improves the self-documenting aspect of your
scripts. This is especially helpful when you're working in a team or on
a long-term project: studies have shown that developers spend most of
their time reading other people's code, or scripts they wrote in the
past and forgot about. The clearer and the more structured the code, the
faster it is to understand, the faster you can move forward.
How to use static typing
------------------------
To define the type of a variable or a constant, write a colon after the
variable's name, followed by its type. E.g. ``var health: int``. This
forces the variable's type to always stay the same:
::
var damage: float = 10.5
const MOVE_SPEED: float = 50.0
Godot will try to infer types if you write a colon, but you omit the
type:
::
var life_points := 4
var damage := 10.5
var motion := Vector2()
Currently you can use three types of… types:
1. :ref:`Built-in <doc_gdscript_builtin_types>`
2. Core classes and nodes (``Object``, ``Node``, ``Area2D``,
``Camera2D``, etc.)
3. Your own, custom classes. Look at the new :ref:`class_name <doc_scripting_continued_class_name>`
feature to register types in the editor.
.. note::
You don't need to write type hints for constants, as Godot sets it automatically from the assigned value. But you can still do so to make the intent of your code clearer.
Custom variable types
~~~~~~~~~~~~~~~~~~~~~
You can use any class, including your custom classes, as types. There
are two ways to use them in scripts. The first method is to preload the
script you want to use as a type in a constant:
::
const Rifle = preload("res://player/weapons/Rifle.gd")
var my_rifle: Rifle
The second method is to use the ``class_name`` keyword when you create.
For the example above, your Rifle.gd would look like this:
::
extends Node2D
class_name Rifle
If you use ``class_name``, Godot registers the Rifle type globally in
the editor, and you can use it anywhere, without having to preload it
into a constant:
::
var my_rifle: Rifle
Variable casting
~~~~~~~~~~~~~~~~
Type casting is a key concept in typed languages.
Casting is the conversion of a value from one type to another.
Imagine an Enemy in your game, that ``extends Area2D``. You want it to
collide with the Player, a ``KinematicBody2D`` with a script called
``PlayerController`` attached to it. You use the ``on_body_entered``
signal to detect the collision. With typed code, the body you detect is
going to be a generic ``PhysicsBody2D``, and not your
``PlayerController`` on the ``_on_body_entered`` callback.
You can check if this ``PhysicsBody2D`` is your Player with the ``as``
casting keyword, and using the colon ``:`` again to force the variable
to use this type. This forces the variable to stick to the
``PlayerController`` type:
::
func _on_body_entered(body: PhysicsBody2D) -> void:
var player := body as PlayerController
if not player:
return
player.damage()
As we're dealing with a custom type, if the ``body`` doesn't extend
``PlayerController``, the ``player``\ variable will be set to ``null``.
We can use this to check if the body is the player or not. We will also
get full autocompletion on the player variable thanks to that cast.
.. note::
If you try to cast with a built-in type and it fails, Godot will throw an error.
.. _doc_gdscript_static_typing_safe_lines:
Safe lines
^^^^^^^^^^
You can also use casting to ensure safe lines. Safe lines are a new
tool in Godot 3.1 to tell you when ambiguous lines of code are
type-safe. As you can mix and match typed and dynamic code, at times,
Godot doesn't have enough information to know if an instruction will trigger
an error or not at runtime.
This happens when you get a child node. Let's take a timer for example:
with dynamic code, you can get the node with ``$Timer``. GDScript
supports `duck-typing <https://stackoverflow.com/a/4205163/8125343>`__,
so even if your timer is of type ``Timer``, it is also a ``Node`` and an
``Object``, two classes it extends. With dynamic GDScript, you also
don't care about the node's type as long as it has the methods you need
to call.
You can use casting to tell Godot the type you expect when you get a
node: ``($Timer as Timer)``, ``($Player as KinematicBody2D)``, etc.
Godot will ensure the type works and if so, the line number will turn
green at the left of the script editor.
.. figure:: img/typed_gdscript_safe_unsafe_line.png
:alt: Unsafe vs Safe Line
Unsafe line (line 7) vs Safe Lines (line 6 and 8)
.. note::
You can turn off safe lines or change their color in the editor settings.
Define the return type of a function with the arrow ->
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To define the return type of a function, write a dash and a right angle
bracket ``->`` after its declaration, followed by the return type:
::
func _process(delta: float) -> void:
pass
The type ``void`` means the function does not return anything. You can
use any type, as with variables:
::
func hit(damage: float) -> bool:
health_points -= damage
return health_points <= 0
You can also use your own nodes as return types:
::
# Inventory.gd
# Adds an item to the inventory and returns it.
func add(reference: Item, amount: int) -> Item:
var item: Item = find_item(reference)
if not item:
item = ItemDatabase.get_instance(reference)
item.amount += amount
return item
Typed or dynamic: stick to one style
------------------------------------
Typed GDScript and dynamic GDScript can coexist in the same project. But
it's recommended to stick to either style for consistency in your codebase,
and for your peers. It's easier for everyone to work together if you
follow the same guidelines, and faster to read and understand other
people's code.
Typed code takes a little more writing, but you get the benefits we
discussed above. Here's an example of the same, empty script, in a
dynamic style:
::
extends Node
func _ready():
pass
func _process(delta):
pass
And with static typing:
::
extends Node
func _ready() -> void:
pass
func _process(delta: float) -> void:
pass
As you can see, you can also use types with the engine's virtual
methods. Signal callbacks, like any methods, can also use types. Here's
a ``body_entered`` signal in a dynamic style:
::
func _on_Area2D_body_entered(body):
pass
And the same callback, with type hints:
::
func _on_area_entered(area: CollisionObject2D) -> void:
pass
You're free to replace, e.g. the ``CollisionObject2D``, with your own type,
to cast parameters automatically:
::
func _on_area_entered(bullet: Bullet) -> void:
if not bullet:
return
take_damage(bullet.damage)
The ``bullet`` variable could hold any ``CollisionObject2D`` here, but
we make sure it is our ``Bullet``, a node we created for our project. If
it's anything else, like an ``Area2D``, or any node that doesn't extend
``Bullet``, the ``bullet`` variable will be ``null``.
Warning system
--------------
.. note::
Documentation about the GDScript warning system has been moved to
:ref:`doc_gdscript_warning_system`.
Cases where you can't specify types
-----------------------------------
To wrap up this introduction, let's cover a few cases where you can't
use type hints. All the examples below **will trigger errors**.
You can't use Enums as types:
::
enum MoveDirection {UP, DOWN, LEFT, RIGHT}
var current_direction: MoveDirection
You can't specify the type of individual members in an array. This will
give you an error:
::
var enemies: Array = [$Goblin: Enemy, $Zombie: Enemy]
You can't force the assignment of types in a ``for`` loop, as each
element the ``for`` keyword loops over already has a different type. So you
**cannot** write:
::
var names = ["John", "Marta", "Samantha", "Jimmy"]
for name: String in names:
pass
Two scripts can't depend on each other in a cyclic fashion:
::
# Player.gd
extends Area2D
class_name Player
var rifle: Rifle
::
# Rifle.gd
extends Area2D
class_name Rifle
var player: Player
Summary
-------
Typed GDScript is a powerful tool. Available as of version 3.1 of Godot, it
helps you write more structured code, avoid common errors, and
create scalable systems. In the future, static types will also bring you
a nice performance boost thanks to upcoming compiler optimizations.

View File

@@ -0,0 +1,51 @@
.. _doc_gdscript_warning_system:
GDScript warning system
=======================
The GDScript warning system complements :ref:`static typing <doc_gdscript_static_typing>`
(but it can work without static typing too). It's here to help you avoid
mistakes that are hard to spot during development, and that may lead
to runtime errors.
You can configure warnings in the Project Settings under the section
called **Gdscript**:
.. figure:: img/typed_gdscript_warning_system_settings.png
:alt: Warning system project settings
Warning system project settings
You can find a list of warnings for the active GDScript file in the
script editor's status bar. The example below has 3 warnings:
.. figure:: img/typed_gdscript_warning_example.png
:alt: Warning system example
Warning system example
To ignore specific warnings in one file, insert a special comment of the
form ``# warning-ignore:warning-id``, or click on the ignore link to the
right of the warning's description. Godot will add a comment above the
corresponding line and the code won't trigger the corresponding warning
anymore:
.. figure:: img/typed_gdscript_warning_system_ignore.png
:alt: Warning system ignore example
Warning system ignore example
You can also choose to ignore not just one but all warnings of a certain
type in this file with ``# warning-ignore-all:warning-id``. To ignore all
warnings of all types in a file add the comment ``# warnings-disable`` to it.
Warnings won't prevent the game from running, but you can turn them into
errors if you'd like. This way your game won't compile unless you fix
all warnings. Head to the ``GDScript`` section of the Project Settings to
turn on this option. Here's the same file as the previous example with
warnings as errors turned on:
.. figure:: img/typed_gdscript_warning_system_errors.png
:alt: Warnings as errors
Warnings as errors

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -0,0 +1,12 @@
Scripting
=========
.. toctree::
:maxdepth: 1
:name: toc-learn-scripting
gdscript/index
visual_script/index
c_sharp/index
cross_language_scripting
creating_script_templates

View File

@@ -0,0 +1,102 @@
.. _doc_custom_visualscript_nodes:
Custom VisualScript nodes
=========================
Custom nodes are written in GDScript and can then be used in VisualScript.
This is useful for offloading complex code to GDScript and reusing it.
Creating a custom node
----------------------
Create a new script that extends :ref:`class_VisualScriptCustomNode` and put a ``tool`` keyword at the top. This is needed for the script to run in the editor.
There are some functions that can be implemented to set parameters of the custom node.
Only add functions that are needed, a ``_has_input_sequence_port`` function is not necessary if it should return ``false`` for example.
The most important part of a custom node is the ``_step`` function. The logic of the node is defined there.
The ``inputs`` parameter holds the value of the input ports.
The ``outputs`` parameter is an array where the indices represent the output port ids. It can be modified to set the values of the output ports.
``start_mode`` can be checked to see if it is the first time ``_step`` is called.
``working_mem`` is persistent each ``_step`` call. It can be used to store information.
If you want to throw an error, for example if the input types are incorrect, you can return the error message as a string.
When everything goes right, return the id of the sequence port which should be called next. If your custom node doesn't have any, just return 0.
Example:
::
tool
extends VisualScriptCustomNode
# The name of the custom node as it appears in the search.
func _get_caption():
return "Get Input Direction 2D"
func _get_category():
return "Input"
# The text displayed after the input port / sequence arrow.
func _get_text():
return ""
func _get_input_value_port_count():
return 0
# The types of the inputs per index starting from 0.
func _get_input_value_port_type(idx):
return TYPE_OBJECT
func _get_output_value_port_count():
return 1
# The types of outputs per index starting from 0.
func _get_output_value_port_type(idx):
return TYPE_VECTOR2
# The text displayed before each output node per index.
func _get_output_value_port_name(idx):
return "Direction"
func _has_input_sequence_port():
return true
# The number of output sequence ports to use
# (has to be at least one if you have an input sequence port).
func _get_output_sequence_port_count():
return 1
func _step(inputs, outputs, start_mode, working_mem):
# start_mode can be checked to see if it is the first time _step is called.
# This is useful if you only want to do an operation once.
# working_memory is persistent between _step calls.
# The inputs array contains the value of the input ports.
var x = int(Input.is_action_pressed("ui_right")) - int(Input.is_action_pressed("ui_left"))
var y = int(Input.is_action_pressed("ui_down")) - int(Input.is_action_pressed("ui_up"))
# The outputs array is used to set the data of the output ports.
outputs[0] = Vector2(x, y)
# Return the error string if an error occurred, else the id of the next sequence port.
return 0
Using a custom node
-------------------
To use the script, add a ``CustomNode``, select it and drag your custom node script into the ``script`` property shown in the inspector.
.. image:: img/visual_script_custom_node_set_script.png
Result:
.. image:: img/visual_script_custom_node_result.png

View File

@@ -0,0 +1,131 @@
.. _doc_getting_started_visual_script:
Getting started with Visual Scripting
=====================================
As with everything in Godot, we prioritize a good experience over copying or integrating third party solutions
which might not fit nicely in the current workflow. This led us to write our own version of how we believe
this feature would work best with the engine.
In Godot, a Visual Script fits smoothly together with regular scripts in the Editor tab
.. image:: img/visual_script1.png
In fact, Visual Scripting integrates so well to Godot that it's hard to believe it was added only
in version 3.0. This is because, when editing, the rest of Godot panels and docks act like a
palette from where you can drag and drop all sorts of information to the script canvas:
.. image:: img/visual_script2.png
Creating a script
-----------------
Creating scripts works the same as with other scripting languages: Select any node in the scene
and push the "New Script" button at the top right corner of the Scene Tree dock:
.. image:: img/visual_script3.png
Once it opens, the script type "Visual Script" must be selected from the drop down list. The script extension
must be ".vs" (for Visual Script!).
.. image:: img/visual_script4.png
Finally, the Script Editor will open, allowing you to start editing the visual script:
.. image:: img/visual_script5.png
Adding a function
-----------------
Unlike other visual scripting implementations, Visual Scripting in Godot is heavily based on functions.
This happens because it uses the same interface to communicate with the engine as other scripting engines.
In Godot, the scripting interface is universal and all implementations conform to it.
A function is an individual canvas with nodes connected.
A single script can contain many functions, each of which will have a canvas of its own, allowing for more organization.
There are three main ways to add functions in a script:
Overriding a virtual function
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Most types of nodes and other types of objects in Godot contain virtual functions. These are functions that
will be called (run your code) when something happens and can be looked up in the reference. Virtual functions
are listed when pressing the "Override" icon in the member panel:
.. image:: img/visual_script6.png
In the following example, a function will be executed when the node is loaded and added to the running scene.
For this, the _ready() virtual method will be overridden:
.. image:: img/visual_script7.png
Finally, a canvas appears for this function, showing the override:
.. image:: img/visual_script8.png
As some functions expect you to return a value, they will also add a return node where such value is supposed to be
provided:
.. image:: img/visual_script9.png
Connecting a signal to a function
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Nodes in a tree emit signals when something happens. Godot uses signals for all sorts of things.
A typical example would be a button that emits a "pressed" signal when actually pressed.
For this, a node must be selected and the Node tab opened. This will allow inspecting the signals.
Once they are displayed, connect the "pressed" signal:
.. image:: img/visual_script10.png
This will open the connection dialog. In this dialog, you must select the node where the signal will be
connected to, and the function that will receive the signal:
.. image:: img/visual_script11.png
If this is done right, a new function will be created in our script and a signal will automatically be
connected to it:
.. image:: img/visual_script12.png
Creating a function manually
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The last way to create functions is to do it manually. In general, this is not as common unless you
really need it. Custom functions work when another (or the same) script calls them manually.
The main use cases for this are breaking a larger function up into several manageable chunks and reusing your visual code.
To create a function manually, push the big "Plus" button, and a new function will be added
with a default name:
.. image:: img/visual_script13.png
This will add a new function, which can be renamed by simply double clicking its name:
.. image:: img/visual_script14.png
To edit the "arguments" this function can get (the values you pass to it when you call this function),
simply click the Function node and check the inspector:
.. image:: img/visual_script15.png
More on that will be explained later in this document.

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

View File

@@ -0,0 +1,11 @@
VisualScript
============
.. toctree::
:maxdepth: 3
:name: toc-learn-scripting-visual_script
what_is_visual_scripting
getting_started
nodes_purposes
custom_visualscript_nodes

View File

@@ -0,0 +1,510 @@
.. _doc_nodes_purposes_visual_script:
Nodes and terminology
=====================
Before continuing, it must be noted that the *Node* terminology needs to be used with care.
When referring to *Visual Script Nodes* (or generally *Nodes*) this text will refer to the little boxes you connect with lines, which are part of a graph.
When referring to *Scene Nodes*, it is implied that the elements that make up a Scene are being referred, which are part of a tree. Their naming is similar but their function is different.
When referring to *Node* here, it will be implied that a *Visual Script Node* is referred to unless indicated otherwise.
.. image:: img/visual_script16.png
Node properties
---------------
Like in most visual scripting implementations, each node has editable properties. In Godot, though, we try to avoid
bloating the nodes with editable controls for the sake of readability.
Nodes still display the required information as text, but editing is done via the *Inspector*. To edit them,
select any node and edit its properties in the *Inspector*.
Ports and connections
---------------------
Programming in Godot Visual Scripting is done via *Nodes* and *Port Connections* inside each function.
Ports
~~~~~
Nodes in Godot Visual Scripting have *Ports*. These are endpoints that appear to the
left and right of nodes and which can be used to make *Connections*:
There are two types of *Ports*: *Sequence* and *Data*.
.. image:: img/visual_script17.png
*Sequence Ports* indicate the order in which operations are executed.
Typically when a *Node* is done processing, it will go to the next node from one of the ports at the right.
If nothing is connected, the function may end, or another output *Sequence Port* might be tried (this depends on the node).
Thanks to this, you can follow the logic flow within a function by following the white lines.
Not every *Node* has *Sequence Ports*. In fact, most do not.
*Data Ports* ports contain typed values. Types can be any regular Godot types,
such as a boolean, an integer, a string, a Vector3, an array, any Object or Scene Node, etc.
A *Data Port* on the right side of a node is considered an output, while,
a port on the left side is an input. Connecting them allows information to flow to the next node.
Not all *Data Port* types are compatible and will allow connections, though.
Pay special attention to colors and icons, as each type has a different representation:
.. image:: img/visual_script18.png
Connections
~~~~~~~~~~~
Connecting is a relatively simple process. Drag an *Output Port* towards an *Input Port*.
.. image:: img/visual_script_connect.gif
Disconnecting takes a bit more practice. Disconnecting in *Data Ports* happens by
dragging the *Input* away, while for *Sequence Ports*, this happens by dragging the *Output* away.
.. image:: img/visual_script_disconnect.gif
This may seem strange at first, but it happens because *Data Ports* are 1:N
(A single output port can connect to many inputs), while *Sequence Ports* are N:1
(Many sequence outputs can be connected to a single input).
Connecting to empty space (drag to connect but unpress over empty space) is also context sensitive, it will supply
a list of most common operations. For sequences, it will be conditional nodes:
.. image:: img/visual_script52.png
While, for data, a contextual set/get/call menu will open:
.. image:: img/visual_script53.png
Adding nodes
------------
Finally! We got to the fun part! But, before explaining in more detail what each type of node does,
let's take a short look at how nodes are most commonly added and dealt with.
Accessing scene nodes
~~~~~~~~~~~~~~~~~~~~~
One of the most common tasks is accessing Scene Tree Nodes (again, not to mistake with *Visual Script Nodes*).
Dragging from the Scene Tree and dropping into the canvas will ask you to *call a method* (sometimes referred to as *member function*) on this node.
.. image:: img/visual_script19.png
While accessing properties is desired in most cases (more on that below), sometimes *calling methods* can be useful too.
Methods execute specific actions on objects. In the above case, the mouse pointer can be warped to a position in local
coordinates to the control. Another common use case is queueing a node for deletion, which is done with the *queue_free* method.
.. image:: img/visual_script20.png
Care must be taken that this only works if the scene being edited contains your *Visual Script* in one of the nodes! Otherwise, a warning will be shown.
Accessing scene node properties
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This is the most common way to edit *Scene Nodes* in Visual Scripting. Select a *Scene Node* from the *Scene Tree*, go to the Inspector, find *the Name* of the property you want to edit (hint, *not* the value!) and drag it to the canvas:
.. image:: img/visual_script21.png
The result is that this value can be changed from your script by writing to a *Data Port*.
If instead reading this value is desired, drag the node again but hold :kbd:`Ctrl` (or :kbd:`Cmd` on macOS). This will create a getter:
.. image:: img/visual_script22.png
In this case, the value can be read from a *Data Port*.
Variables
~~~~~~~~~
Variables are memory containers local to the script which can hold a value. This value can be read from any of the functions of the script or from other scripts via the method described in the previous step.
To add a Variable, push the "+" button on the *Variables* section of the Members panel. Double-click the new variable to rename it:
.. image:: img/visual_script23.png
Right-clicking the variable allows you to configure its properties:
.. image:: img/visual_script24.png
.. image:: img/visual_script25.png
As it can be seen above, the type and initial value of the variable can be changed, as well as some property hints.
Ticking the "Export" option makes the variable visible in the Inspector when selecting the node. This also makes it available to other scripts via the method described in the previous step.
.. image:: img/visual_script28.png
To use the variable in the script, simply drag it to the canvas to create a getter:
.. image:: img/visual_script26.png
Likewise, hold :kbd:`Ctrl` (or :kbd:`Cmd` on macOS) to drop a setter:
.. image:: img/visual_script27.png
Signals
~~~~~~~
It is also possible to create your own signals in a script and use them. For this, do the same steps you did for variables in the previous step, except for *Signals*:
.. image:: img/visual_script29.png
A signal can also be edited via the right-click menu to customize its arguments:
.. image:: img/visual_script30.png
The signal you have created will appear in the Inspector, along with the built-in node signals. This allows you to connect it from another script from another *Scene Node*:
.. image:: img/visual_script31.png
Finally, to emit the signal, simply drag it to the canvas:
.. image:: img/visual_script32.png
Remember that emitting a signal is a sequenced operation, so it must come from a Sequence port.
Adding more nodes
-----------------
Now that the basics are covered, let's discuss the large amount of utility nodes available for your canvas!
Below the member panel, exists the list of all available node types:
.. image:: img/visual_script33.png
Pressing :kbd:`Ctrl + F` (or :kbd:`Cmd + F` on macOS) allows you to search the list.
Any of them can be dragged to the scene. Unlike nodes (e.g. dragging a property
from the Inspector sets the context to the node being edited automatically), these are added without any "contextual" information, so this has to be done manually.
.. image:: img/visual_script34.png
Remember that you can check the class reference for what each node does, as they are documented there. That mentioned,
a brief overview of node types follows:
Constants
~~~~~~~~~
Constant nodes are nodes that provide values that, while not changing over time, can be useful as reference values.
Most of the time they are integer or float.
.. image:: img/visual_script36.png
The first one is "Constant", which allows you to select any value of any type as constant, from an integer (42) to a String ("Hello!"). In general, this node is not used that often because of default input values in *Data Ports*, but it's good to know it exists.
The second is the GlobalConstant node, which contains a long list of constants for global types in Godot. In there
you can find some useful constants to refer to key names, joystick or mouse buttons, etc.
The third one is MathConstant, which provides typical mathematical constants, such as PI, E, etc.
Data
~~~~
Data nodes deal with all sorts of access to information. Any information in Godot is accessed via these nodes, so
they are some of the most important ones to use and pretty diverse.
.. image:: img/visual_script37.png
There are many types of nodes of interest here, so a short attempt to describe them will follow:
Action
^^^^^^
Action nodes are vital when dealing with input from a device. You can read more about actions in the (@TODO ACTION TUTE LINK).
In the following example below, the control is moved to the right when the "move_right" action is pressed.
.. image:: img/visual_script38.png
Engine Singleton
^^^^^^^^^^^^^^^^
Engine singletons are global interfaces (meaning they can be accessed without a reference; unlike Scene Nodes, they are always available).
They have several purposes, but in general, they are useful for low-level access or OS-related access.
.. image:: img/visual_script39.png
Remember that dragging a connection to empty space will help you call functions or set/get properties on these:
.. image:: img/visual_script40.png
Local Variables
^^^^^^^^^^^^^^^
These are nodes you can use as temporary storage for your graphs. Make sure they all have the same name and type when using them and they will reference the same piece of memory.
.. image:: img/visual_script41.png
As it can be seen above, there are two nodes available: A simple getter, and a sequenced setter (setting requires a sequence port).
Scene Node
^^^^^^^^^^
This is just a reference to a node in the tree, but it's easier to use this node by dragging the actual node
from the scene tree to the canvas (this will create it and configure it).
Self
^^^^
In some rare occasions, it may be desired to pass this Scene Node as argument.
It can be used to call functions and set/get properties, or drag nodes (or event the node itself that has the script) from the Scene Tree to the canvas for this.
SceneTree
^^^^^^^^^
This node is similar to the Singleton node because it references the SceneTree, which contains the active scene.
SceneTree, however, only works when the node is sitting in the scene and active, otherwise accessing it will
return an error.
SceneTree allows for many low-level things, like setting stretch options, calling groups, make timers, or even
load another scene. It's a good class to get familiar with.
Preload
^^^^^^^
This does the same function as preload() in GDScript. It maintains this resource loaded and ready to use. Rather than
instancing the node, it's simpler to drag the desired resource from the filesystem dock to the canvas.
Resource Path
^^^^^^^^^^^^^
This node is a simple helper to get a string with a path to a resource you can pick. It's useful in functions that
load things from disk.
Comment
^^^^^^^
A Comment node works as a node you can resize to put around other nodes. It will not try to get focus or be brought
to top when selecting it. It can also be used to write text on it.
.. image:: img/visual_script42.png
Flow Control
~~~~~~~~~~~~
Flow control nodes allow the execution to take different branches, usually depending on a
given condition.
.. image:: img/visual_script43.png
Condition
^^^^^^^^^
This is a simple node that checks a bool port. If ``true``, it will go via the "true" sequence port. If ``false``,
the second. After going for either of them, it goes via the "done" port. Leaving sequence
ports disconnected is fine if not all of them are used.
Iterator
^^^^^^^^
Some data types in Godot (ie, arrays, dictionaries) are iterable. This means that a bit of code can run
for each element that it has.
The Iterator node goes through all elements and, for each of them, it goes via the "each" sequence port,
making the element available in the "elem" data port.
When done, it goes via the "exit" sequence port.
Return
^^^^^^
Some functions can return values. In general for virtual ones, Godot will add the Return node for you.
A return node forces the function to end.
Sequence
^^^^^^^^
This node is useful mostly for organizing your graph. It calls its sequence ports in order.
TypeCast
^^^^^^^^
This is a useful and commonly used node. You can use it to cast arguments or other objects
to the type you desire. Afterwards, you can even drag the object output to get full completion.
.. image:: img/visual_script55.png
It is also possible to cast to a script, which will allow complete script properties and functions:
.. image:: img/visual_script54.png
Switch
^^^^^^
The Switch node is similar to the Condition node, but it matches many values at the same time.
While
^^^^^
This is a more primitive form of iteration. "repeat" sequence output will be called as long as
the condition in the "cond" data port is met.
Functions
~~~~~~~~~
Functions are simple helpers, most of the time deterministic. They take some arguments as
input and return an output. They are almost never sequenced.
Built-In
^^^^^^^^
There is a list of built-in helpers. The list is almost identical to the one from :ref:`GDScript<class_@GDScript>`. Most of them are mathematical functions, but others can be useful helpers. Make sure to take a look at the list
at some point.
By Type
^^^^^^^
Those are the methods available to basic types. For example, if you want a dot-product, you can search for "dot" instead of the Vector3 category.
In most cases just search the list of nodes, it should be faster.
Call
^^^^
This is the generic calling node. It is rarely used directly but by dragging to empty space on an already configured node.
Constructors
^^^^^^^^^^^^
These are all the functions needed to create Godot basic datatypes. For example, If you need to create a Vector3 out of 3 floats, a constructor must be used.
.. image:: img/visual_script44.png
Destructor
^^^^^^^^^^
This is the opposite to Constructor, it allows to separate any basic type (ie, Vector3) into its sub-elements.
.. image:: img/visual_script45.png
Emit Signal
^^^^^^^^^^^
Emits signals from any object. In general it's not that useful, as dragging a signal to the canvas works better.
Get/Set
^^^^^^^
Generic Getter/Setter node. Dragging properties from the Inspector works better, as they appear properly configured on drop.
Wait
^^^^
The Wait nodes will suspend execution of the function until something happens (many frames can pass until resuming, in fact).
Default nodes allow you to wait for a frame to pass, a fixed frame or a given amount of time until execution is resumed.
Yield
^^^^^
This node completely suspends the execution of the script, and it will make the function return a value that can be used to resume execution.
Yield Signal
^^^^^^^^^^^^
Same as Yield, but will wait until a given signal is emitted.
Index
~~~~~
Generic indexing operator, not often used but it's good that it exists just in case.
Operators
~~~~~~~~~
These are mostly generic operators, such as addition, multiplication, comparison, etc.
By default, these mostly accept any datatype (and will throw an error at run-time if the types
fed do not match those expected by the operator). It is always recommended to set the right
type for operators to catch errors faster and make the graph easier to read.
.. image:: img/visual_script46.png
Expression Node
^^^^^^^^^^^^^^^
Among the operators, the *Expression* node is the most powerful. If well used, it allows you to enormously simplify
visual scripts that are math or logic heavy. Type any expression on it and it will be executed in real-time.
Expression nodes can:
- Perform math and logic expressions based on custom inputs (eg: "a*5+b", where a and b are custom inputs):
.. image:: img/visual_script47.png
- Access local variables or properties:
.. image:: img/visual_script48.png
- Use most of the existing built-in functions that are available to GDScript, such as ``sin()``, ``cos()``, ``print()``, as well as constructors, such as ``Vector3(x, y, z)``, ``Rect2(...)``, etc.:
.. image:: img/visual_script49.png
- Call API functions:
.. image:: img/visual_script50.png
- Use sequenced mode, which makes more sense in case of respecting the processing order:
.. image:: img/visual_script51.png

View File

@@ -0,0 +1,24 @@
.. _doc_what_is_visual_script:
What is Visual Scripting
========================
Visual Scripting is a tool designed to make the entry barrier to programming
much lower. As code is more visual, it needs less abstract thinking to be
understood. Any artist, animator, game designer, etc. can look at it and quickly
grasp the flow of logic.
The reason it does not make existing programming obsolete is, simply, that it does not scale as well.
It takes considerably more time to create code with it, and it's often more difficult
to modify than just writing a few characters.
With the misunderstanding cleared up, the question that remains is what are the practical
uses for Visual Scripting.
The most common use cases are as follows:
* Game development beginners who want to learn an engine but have no programming experience yet.
* Artists and Game Designers who have no experience in programming and want to create quick prototypes or simple games.
* Programmers working in a team that want to make part of the game logic available to Artists or Game Designers in order to offload some of their work.
These scenarios are far more common than one might think, so this is why Godot has added this feature.