Docs: Port Code Examples to C# (R, S, T, U)

* RenderingServer
 * RichTextEffect
 * SceneTree
 * SceneTreeTimer
 * ScriptCreateDialog
 * SpinBox
 * Sprite2D
 * StreamPeer
 * String
 * SurfaceTool
 * TextEdit
 * TileMap
 * Tree
 * Tween
 * UDPServer
 * UndoRedo

Co-authored-by: Aaron Franke <arnfranke@yahoo.com>
This commit is contained in:
HaSa1002 2020-11-28 00:33:15 +01:00 committed by Johannes
parent bd9799e9f0
commit bae843a1c9
No known key found for this signature in database
GPG Key ID: B988B760383F3A91
16 changed files with 323 additions and 59 deletions

View File

@ -2704,11 +2704,14 @@
<description>
Copies the viewport to a region of the screen specified by [code]rect[/code]. If [method viewport_set_render_direct_to_screen] is [code]true[/code], then the viewport does not use a framebuffer and the contents of the viewport are rendered directly to screen. However, note that the root viewport is drawn last, therefore it will draw over the screen. Accordingly, you must set the root viewport to an area that does not cover the area that you have attached this viewport to.
For example, you can set the root viewport to not render at all with the following code:
[codeblock]
FIXME: The method seems to be non-existent.
[codeblocks]
[gdscript]
func _ready():
get_viewport().set_attach_to_screen_rect(Rect2())
$Viewport.set_attach_to_screen_rect(Rect2(0, 0, 600, 600))
[/codeblock]
[/gdscript]
[/codeblocks]
Using this can result in significant optimization, especially on lower-end devices. However, it comes at the cost of having to manage your viewports manually. For a further optimization see, [method viewport_set_render_direct_to_screen].
</description>
</method>

View File

@ -6,10 +6,16 @@
<description>
A custom effect for use with [RichTextLabel].
[b]Note:[/b] For a [RichTextEffect] to be usable, a BBCode tag must be defined as a member variable called [code]bbcode[/code] in the script.
[codeblock]
[codeblocks]
[gdscript]
# The RichTextEffect will be usable like this: `[example]Some text[/example]`
var bbcode = "example"
[/codeblock]
[/gdscript]
[csharp]
// The RichTextEffect will be usable like this: `[example]Some text[/example]`
public string bbcode = "example";
[/csharp]
[/codeblocks]
[b]Note:[/b] As soon as a [RichTextLabel] contains at least one [RichTextEffect], it will continuously process the effect unless the project is paused. This may impact battery life negatively.
</description>
<tutorials>

View File

@ -69,12 +69,22 @@
<description>
Returns a [SceneTreeTimer] which will [signal SceneTreeTimer.timeout] after the given time in seconds elapsed in this [SceneTree]. If [code]process_always[/code] is set to [code]false[/code], pausing the [SceneTree] will also pause the timer.
Commonly used to create a one-shot delay timer as in the following example:
[codeblock]
[codeblocks]
[gdscript]
func some_function():
print("start")
yield(get_tree().create_timer(1.0), "timeout")
print("end")
[/codeblock]
[/gdscript]
[csharp]
public async void SomeFunction()
{
GD.Print("start");
await ToSignal(GetTree().CreateTimer(1.0f), "timeout");
GD.Print("end");
}
[/csharp]
[/codeblocks]
The timer will be automatically freed after its time elapses.
</description>
</method>

View File

@ -6,12 +6,22 @@
<description>
A one-shot timer managed by the scene tree, which emits [signal timeout] on completion. See also [method SceneTree.create_timer].
As opposed to [Timer], it does not require the instantiation of a node. Commonly used to create a one-shot delay timer as in the following example:
[codeblock]
[codeblocks]
[gdscript]
func some_function():
print("Timer started.")
yield(get_tree().create_timer(1.0), "timeout")
print("Timer ended.")
[/codeblock]
[/gdscript]
[csharp]
public async void SomeFunction()
{
GD.Print("Timer started.");
await ToSignal(GetTree().CreateTimer(1.0f), "timeout");
GD.Print("Timer ended.");
}
[/csharp]
[/codeblocks]
</description>
<tutorials>
</tutorials>

View File

@ -5,12 +5,24 @@
</brief_description>
<description>
The [ScriptCreateDialog] creates script files according to a given template for a given scripting language. The standard use is to configure its fields prior to calling one of the [method Window.popup] methods.
[codeblock]
[codeblocks]
[gdscript]
func _ready():
dialog.config("Node", "res://new_node.gd") # For in-engine types
dialog.config("\"res://base_node.gd\"", "res://derived_node.gd") # For script types
var dialog = ScriptCreateDialog.new();
dialog.config("Node", "res://new_node.gd") # For in-engine types.
dialog.config("\"res://base_node.gd\"", "res://derived_node.gd") # For script types.
dialog.popup_centered()
[/codeblock]
[/gdscript]
[csharp]
public override void _Ready()
{
var dialog = new ScriptCreateDialog();
dialog.Config("Node", "res://NewNode.cs"); // For in-engine types.
dialog.Config("\"res://BaseNode.cs\"", "res://DerivedNode.cs"); // For script types.
dialog.PopupCentered();
}
[/csharp]
[/codeblocks]
</description>
<tutorials>
</tutorials>

View File

@ -6,13 +6,22 @@
<description>
SpinBox is a numerical input text field. It allows entering integers and floats.
[b]Example:[/b]
[codeblock]
[codeblocks]
[gdscript]
var spin_box = SpinBox.new()
add_child(spin_box)
var line_edit = spin_box.get_line_edit()
line_edit.context_menu_enabled = false
spin_box.align = LineEdit.ALIGN_RIGHT
[/codeblock]
[/gdscript]
[csharp]
var spinBox = new SpinBox();
AddChild(spinBox);
var lineEdit = spinBox.GetLineEdit();
lineEdit.ContextMenuEnabled = false;
spinBox.Align = LineEdit.AlignEnum.Right;
[/csharp]
[/codeblocks]
The above code will create a [SpinBox], disable context menu on it and set the text alignment to right.
See [Range] class for more options over the [SpinBox].
[b]Note:[/b] [SpinBox] relies on an underlying [LineEdit] node. To theme a [SpinBox]'s background, add theme items for [LineEdit] and customize them.

View File

@ -15,12 +15,29 @@
</return>
<description>
Returns a [Rect2] representing the Sprite2D's boundary in local coordinates. Can be used to detect if the Sprite2D was clicked. Example:
[codeblock]
[codeblocks]
[gdscript]
func _input(event):
if event is InputEventMouseButton and event.pressed and event.button_index == BUTTON_LEFT:
if get_rect().has_point(to_local(event.position)):
print("A click!")
[/codeblock]
[/gdscript]
[csharp]
public override void _Input(InputEvent inputEvent)
{
if (inputEvent is InputEventMouseButton inputEventMouse)
{
if (inputEventMouse.Pressed &amp;&amp; inputEventMouse.ButtonIndex == (int)ButtonList.Left)
{
if (GetRect().HasPoint(ToLocal(inputEventMouse.Position)))
{
GD.Print("A click!");
}
}
}
}
[/csharp]
[/codeblocks]
</description>
</method>
<method name="is_pixel_opaque" qualifiers="const">

View File

@ -212,9 +212,14 @@
<description>
Puts a zero-terminated ASCII string into the stream prepended by a 32-bit unsigned integer representing its size.
Note: To put an ASCII string without prepending its size, you can use [method put_data]:
[codeblock]
[codeblocks]
[gdscript]
put_data("Hello world".to_ascii())
[/codeblock]
[/gdscript]
[csharp]
PutData("Hello World".ToAscii());
[/csharp]
[/codeblocks]
</description>
</method>
<method name="put_u16">
@ -261,9 +266,14 @@
<description>
Puts a zero-terminated UTF-8 string into the stream prepended by a 32 bits unsigned integer representing its size.
Note: To put an UTF-8 string without prepending its size, you can use [method put_data]:
[codeblock]
[codeblocks]
[gdscript]
put_data("Hello world".to_utf8())
[/codeblock]
[/gdscript]
[csharp]
PutData("Hello World".ToUTF8());
[/csharp]
[/codeblocks]
</description>
</method>
<method name="put_var">

View File

@ -163,11 +163,15 @@
<description>
Returns the index of the [b]first[/b] case-sensitive occurrence of the specified string in this instance, or [code]-1[/code]. Optionally, the starting search index can be specified, continuing to the end of the string.
[b]Note:[/b] If you just want to know whether a string contains a substring, use the [code]in[/code] operator as follows:
[codeblock]
# Will evaluate to `false`.
if "i" in "team":
pass
[/codeblock]
[codeblocks]
[gdscript]
print("i" in "team") # Will print `false`.
[/gdscript]
[csharp]
// C# has no in operator, but we can use `Contains()`.
GD.Print("team".Contains("i")); // Will print `false`.
[/csharp]
[/codeblocks]
</description>
</method>
<method name="findn">
@ -354,9 +358,14 @@
<description>
Return a [String] which is the concatenation of the [code]parts[/code]. The separator between elements is the string providing this method.
Example:
[codeblock]
[codeblocks]
[gdscript]
print(", ".join(["One", "Two", "Three", "Four"]))
[/codeblock]
[/gdscript]
[csharp]
GD.Print(String.Join(",", new string[] {"One", "Two", "Three", "Four"}));
[/csharp]
[/codeblocks]
</description>
</method>
<method name="json_escape">
@ -654,13 +663,18 @@
The splits in the returned array are sorted in the same order as the original string, from left to right.
If [code]maxsplit[/code] is specified, it defines the number of splits to do from the right up to [code]maxsplit[/code]. The default value of 0 means that all items are split, thus giving the same result as [method split].
Example:
[codeblock]
[codeblocks]
[gdscript]
var some_string = "One,Two,Three,Four"
var some_array = some_string.rsplit(",", true, 1)
print(some_array.size()) # Prints 2
print(some_array[0]) # Prints "Four"
print(some_array[1]) # Prints "Three,Two,One"
[/codeblock]
[/gdscript]
[csharp]
// There is no Rsplit.
[/csharp]
[/codeblocks]
</description>
</method>
<method name="rstrip">
@ -723,13 +737,21 @@
Splits the string by a [code]delimiter[/code] string and returns an array of the substrings. The [code]delimiter[/code] can be of any length.
If [code]maxsplit[/code] is specified, it defines the number of splits to do from the left up to [code]maxsplit[/code]. The default value of [code]0[/code] means that all items are split.
Example:
[codeblock]
[codeblocks]
[gdscript]
var some_string = "One,Two,Three,Four"
var some_array = some_string.split(",", true, 1)
print(some_array.size()) # Prints 2
print(some_array[0]) # Prints "One"
print(some_array[1]) # Prints "Two,Three,Four"
[/codeblock]
print(some_array[0]) # Prints "Four"
print(some_array[1]) # Prints "Three,Two,One"
[/gdscript]
[csharp]
var someString = "One,Two,Three,Four";
var someArray = someString.Split(",", true); // This is as close as it gets to Godots API.
GD.Print(someArray[0]); // Prints "Four"
GD.Print(someArray[1]); // Prints "Three,Two,One"
[/csharp]
[/codeblocks]
If you need to split strings with more complex rules, use the [RegEx] class instead.
</description>
</method>

View File

@ -5,13 +5,22 @@
</brief_description>
<description>
The [SurfaceTool] is used to construct a [Mesh] by specifying vertex attributes individually. It can be used to construct a [Mesh] from a script. All properties except indices need to be added before calling [method add_vertex]. For example, to add vertex colors and UVs:
[codeblock]
[codeblocks]
[gdscript]
var st = SurfaceTool.new()
st.begin(Mesh.PRIMITIVE_TRIANGLES)
st.set_color(Color(1, 0, 0))
st.set_uv(Vector2(0, 0))
st.set_vertex(Vector3(0, 0, 0))
[/codeblock]
[/gdscript]
[csharp]
var st = new SurfaceTool();
st.Begin(Mesh.PrimitiveType.Triangles);
st.SetColor(new Color(1, 0, 0));
st.SetUv(new Vector2(0, 0));
st.SetVertex(new Vector3(0, 0, 0));
[/csharp]
[/codeblocks]
The above [SurfaceTool] now contains one vertex of a triangle which has a UV coordinate and a specified [Color]. If another vertex were added without calling [method set_uv] or [method set_color], then the last values would be used.
Vertex attributes must be passed [b]before[/b] calling [method add_vertex]. Failure to do so will result in an error when committing the vertex information to a mesh.
Additionally, the attributes used before the first vertex is added determine the format of the mesh. For example, if you only add UVs to the first vertex, you cannot add color to any of the subsequent vertices.

View File

@ -402,13 +402,24 @@
<description>
Perform a search inside the text. Search flags can be specified in the [enum SearchFlags] enum.
Returns an empty [code]Dictionary[/code] if no result was found. Otherwise, returns a [code]Dictionary[/code] containing [code]line[/code] and [code]column[/code] entries, e.g:
[codeblock]
var result = search(key, flags, line, column)
if !result.is_empty():
[codeblocks]
[gdscript]
var result = search("print", SEARCH_WHOLE_WORDS, 0, 0)
if !result.empty():
# Result found.
var line_number = result.line
var column_number = result.column
[/codeblock]
[/gdscript]
[csharp]
int[] result = Search("print", (uint)TextEdit.SearchFlags.WholeWords, 0, 0);
if (result.Length > 0)
{
// Result found.
int lineNumber = result[(int)TextEdit.SearchResult.Line];
int columnNumber = result[(int)TextEdit.SearchResult.Column];
}
[/csharp]
[/codeblocks]
</description>
</method>
<method name="select">

View File

@ -172,12 +172,22 @@
[b]Note:[/b] Data such as navigation polygons and collision shapes are not immediately updated for performance reasons.
If you need these to be immediately updated, you can call [method update_dirty_quadrants].
Overriding this method also overrides it internally, allowing custom logic to be implemented when tiles are placed/removed:
[codeblock]
[codeblocks]
[gdscript]
func set_cell(x, y, tile, flip_x=false, flip_y=false, transpose=false, autotile_coord=Vector2())
# Write your custom logic here.
# To call the default method:
.set_cell(x, y, tile, flip_x, flip_y, transpose, autotile_coord)
[/codeblock]
[/gdscript]
[csharp]
public void SetCell(int x, int y, int tile, bool flipX = false, bool flipY = false, bool transpose = false, Vector2 autotileCoord = new Vector2())
{
// Write your custom logic here.
// To call the default method:
base.SetCell(x, y, tile, flipX, flipY, transpose, autotileCoord);
}
[/csharp]
[/codeblocks]
</description>
</method>
<method name="set_cellv">

View File

@ -6,16 +6,30 @@
<description>
This shows a tree of items that can be selected, expanded and collapsed. The tree can have multiple columns with custom controls like text editing, buttons and popups. It can be useful for structured displays and interactions.
Trees are built via code, using [TreeItem] objects to create the structure. They have a single root but multiple roots can be simulated if a dummy hidden root is added.
[codeblock]
[codeblocks]
[gdscript]
func _ready():
var tree = Tree.new()
var root = tree.create_item()
tree.set_hide_root(true)
tree.hide_root = true
var child1 = tree.create_item(root)
var child2 = tree.create_item(root)
var subchild1 = tree.create_item(child1)
subchild1.set_text(0, "Subchild1")
[/codeblock]
[/gdscript]
[csharp]
public override void _Ready()
{
var tree = new Tree();
TreeItem root = tree.CreateItem();
tree.HideRoot = true;
TreeItem child1 = tree.CreateItem(root);
TreeItem child2 = tree.CreateItem(root);
TreeItem subchild1 = tree.CreateItem(child1);
subchild1.SetText(0, "Subchild1");
}
[/csharp]
[/codeblocks]
To iterate over all the [TreeItem] objects in a [Tree] object, use [method TreeItem.get_next] and [method TreeItem.get_children] after getting the root through [method get_root]. You can use [method Object.free] on a [TreeItem] to remove it from the [Tree].
</description>
<tutorials>
@ -152,13 +166,26 @@
</return>
<description>
Returns the currently edited item. Can be used with [signal item_edited] to get the item that was modified.
[codeblock]
[codeblocks]
[gdscript]
func _ready():
$Tree.item_edited.connect(on_Tree_item_edited)
func on_Tree_item_edited():
print($Tree.get_edited()) # This item just got edited (e.g. checked).
[/codeblock]
[/gdscript]
[csharp]
public override void _Ready()
{
GetNode&lt;Tree&gt;("Tree").ItemEdited += OnTreeItemEdited;
}
public void OnTreeItemEdited()
{
GD.Print(GetNode&lt;Tree&gt;("Tree").GetEdited()); // This item just got edited (e.g. checked).
}
[/csharp]
[/codeblocks]
</description>
</method>
<method name="get_edited_column" qualifiers="const">

View File

@ -7,13 +7,22 @@
Tweens are useful for animations requiring a numerical property to be interpolated over a range of values. The name [i]tween[/i] comes from [i]in-betweening[/i], an animation technique where you specify [i]keyframes[/i] and the computer interpolates the frames that appear between them.
[Tween] is more suited than [AnimationPlayer] for animations where you don't know the final values in advance. For example, interpolating a dynamically-chosen camera zoom value is best done with a [Tween] node; it would be difficult to do the same thing with an [AnimationPlayer] node.
Here is a brief usage example that makes a 2D node move smoothly between two positions:
[codeblock]
[codeblocks]
[gdscript]
var tween = get_node("Tween")
tween.interpolate_property($Node2D, "position",
Vector2(0, 0), Vector2(100, 100), 1,
Tween.TRANS_LINEAR, Tween.EASE_IN_OUT)
tween.start()
[/codeblock]
[/gdscript]
[csharp]
var tween = GetNode&lt;Tween&gt;("Tween");
tween.InterpolateProperty(GetNode&lt;Node2D&gt;("Node2D"), "position",
new Vector2(0, 0), new Vector2(100, 100), 1,
Tween.TransitionType.Linear, Tween.EaseType.InOut);
tween.Start();
[/csharp]
[/codeblocks]
Many methods require a property name, such as [code]"position"[/code] above. You can find the correct property name by hovering over the property in the Inspector. You can also provide the components of a property directly by using [code]"property:component"[/code] (eg. [code]position:x[/code]), where it would only apply to that particular component.
Many of the methods accept [code]trans_type[/code] and [code]ease_type[/code]. The first accepts an [enum TransitionType] constant, and refers to the way the timing of the animation is handled (see [url=https://easings.net/]easings.net[/url] for some examples). The second accepts an [enum EaseType] constant, and controls where the [code]trans_type[/code] is applied to the interpolation (in the beginning, the end, or both). If you don't know which transition and easing to pick, you can try different [enum TransitionType] constants with [constant EASE_IN_OUT], and use the one that looks best.
[url=https://raw.githubusercontent.com/godotengine/godot-docs/master/img/tween_cheatsheet.png]Tween easing and transition types cheatsheet[/url]

View File

@ -7,8 +7,9 @@
A simple server that opens a UDP socket and returns connected [PacketPeerUDP] upon receiving new packets. See also [method PacketPeerUDP.connect_to_host].
After starting the server ([method listen]), you will need to [method poll] it at regular intervals (e.g. inside [method Node._process]) for it to process new packets, delivering them to the appropriate [PacketPeerUDP], and taking new connections.
Below a small example of how it can be used:
[codeblock]
# server.gd
[codeblocks]
[gdscript]
class_name Server
extends Node
var server := UDPServer.new()
@ -21,20 +22,57 @@
server.poll() # Important!
if server.is_connection_available():
var peer : PacketPeerUDP = server.take_connection()
var pkt = peer.get_packet()
var packet = peer.get_packet()
print("Accepted peer: %s:%s" % [peer.get_packet_ip(), peer.get_packet_port()])
print("Received data: %s" % [pkt.get_string_from_utf8()])
print("Received data: %s" % [packet.get_string_from_utf8()])
# Reply so it knows we received the message.
peer.put_packet(pkt)
peer.put_packet(packet)
# Keep a reference so we can keep contacting the remote peer.
peers.append(peer)
for i in range(0, peers.size()):
pass # Do something with the connected peers.
[/gdscript]
[csharp]
using Godot;
using System;
using System.Collections.Generic;
[/codeblock]
[codeblock]
# client.gd
public class Server : Node
{
public UDPServer Server = new UDPServer();
public List&lt;PacketPeerUDP&gt; Peers = new List&lt;PacketPeerUDP&gt;();
public override void _Ready()
{
Server.Listen(4242);
}
public override void _Process(float delta)
{
Server.Poll(); // Important!
if (Server.IsConnectionAvailable())
{
PacketPeerUDP peer = Server.TakeConnection();
byte[] packet = peer.GetPacket();
GD.Print($"Accepted Peer: {peer.GetPacketIp()}:{peer.GetPacketPort()}");
GD.Print($"Received Data: {packet.GetStringFromUTF8()}");
// Reply so it knows we received the message.
peer.PutPacket(packet);
// Keep a reference so we can keep contacting the remote peer.
Peers.Add(peer);
}
foreach (var peer in Peers)
{
// Do something with the peers.
}
}
}
[/csharp]
[/codeblocks]
[codeblocks]
[gdscript]
class_name Client
extends Node
var udp := PacketPeerUDP.new()
@ -50,7 +88,37 @@
if udp.get_available_packet_count() &gt; 0:
print("Connected: %s" % udp.get_packet().get_string_from_utf8())
connected = true
[/codeblock]
[/gdscript]
[csharp]
using Godot;
using System;
public class Client : Node
{
public PacketPeerUDP Udp = new PacketPeerUDP();
public bool Connected = false;
public override void _Ready()
{
Udp.ConnectToHost("127.0.0.1", 4242);
}
public override void _Process(float delta)
{
if (!Connected)
{
// Try to contact server
Udp.PutPacket("The Answer Is..42!".ToUTF8());
}
if (Udp.GetAvailablePacketCount() &gt; 0)
{
GD.Print($"Connected: {Udp.GetPacket().GetStringFromUTF8()}");
Connected = true;
}
}
}
[/csharp]
[/codeblocks]
</description>
<tutorials>
</tutorials>

View File

@ -7,7 +7,8 @@
Helper to manage undo/redo operations in the editor or custom tools. It works by registering methods and property changes inside "actions".
Common behavior is to create an action, then add do/undo calls to functions or property changes, then committing the action.
Here's an example on how to add an action to the Godot editor's own [UndoRedo], from a plugin:
[codeblock]
[codeblocks]
[gdscript]
var undo_redo = get_undo_redo() # Method of EditorPlugin.
func do_something():
@ -24,7 +25,37 @@
undo_redo.add_do_property(node, "position", Vector2(100,100))
undo_redo.add_undo_property(node, "position", node.position)
undo_redo.commit_action()
[/codeblock]
[/gdscript]
[csharp]
public UndoRedo UndoRedo;
public override void _Ready()
{
UndoRedo = GetUndoRedo(); // Method of EditorPlugin.
}
public void DoSomething()
{
// Put your code here.
}
public void UndoSomething()
{
// Put here the code that reverts what's done by "DoSomething()".
}
private void OnMyButtonPressed()
{
var node = GetNode&lt;Node2D&gt;("MyNode2D");
UndoRedo.CreateAction("Move the node");
UndoRedo.AddDoMethod(this, nameof(DoSomething));
UndoRedo.AddUndoMethod(this, nameof(UndoSomething));
UndoRedo.AddDoProperty(node, "position", new Vector2(100, 100));
UndoRedo.AddUndoProperty(node, "position", node.Position);
UndoRedo.CommitAction();
}
[/csharp]
[/codeblocks]
[method create_action], [method add_do_method], [method add_undo_method], [method add_do_property], [method add_undo_property], and [method commit_action] should be called one after the other, like in the example. Not doing so could lead to crashes.
If you don't need to register a method, you can leave [method add_do_method] and [method add_undo_method] out; the same goes for properties. You can also register more than one method/property.
</description>