Replace XML codeblock spaces with tabs

This commit is contained in:
kobewi
2025-05-17 20:00:17 +02:00
committed by Rémi Verschelde
parent 5dd76968d8
commit 13f642d959
122 changed files with 2407 additions and 2432 deletions

View File

@ -457,8 +457,8 @@
[codeblock] [codeblock]
print(" (x) (fmod(x, 1.5)) (fposmod(x, 1.5))") print(" (x) (fmod(x, 1.5)) (fposmod(x, 1.5))")
for i in 7: for i in 7:
var x = i * 0.5 - 1.5 var x = i * 0.5 - 1.5
print("%4.1f %4.1f | %4.1f" % [x, fmod(x, 1.5), fposmod(x, 1.5)]) print("%4.1f %4.1f | %4.1f" % [x, fmod(x, 1.5), fposmod(x, 1.5)])
[/codeblock] [/codeblock]
Prints: Prints:
[codeblock lang=text] [codeblock lang=text]
@ -498,21 +498,21 @@
var drink = "water" var drink = "water"
func _ready(): func _ready():
var id = get_instance_id() var id = get_instance_id()
var instance = instance_from_id(id) var instance = instance_from_id(id)
print(instance.foo) # Prints "water" print(instance.foo) # Prints "water"
[/gdscript] [/gdscript]
[csharp] [csharp]
public partial class MyNode : Node public partial class MyNode : Node
{ {
public string Drink { get; set; } = "water"; public string Drink { get; set; } = "water";
public override void _Ready() public override void _Ready()
{ {
ulong id = GetInstanceId(); ulong id = GetInstanceId();
var instance = (MyNode)InstanceFromId(Id); var instance = (MyNode)InstanceFromId(Id);
GD.Print(instance.Drink); // Prints "water" GD.Print(instance.Drink); // Prints "water"
} }
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -642,10 +642,10 @@
extends Sprite extends Sprite
var elapsed = 0.0 var elapsed = 0.0
func _process(delta): func _process(delta):
var min_angle = deg_to_rad(0.0) var min_angle = deg_to_rad(0.0)
var max_angle = deg_to_rad(90.0) var max_angle = deg_to_rad(90.0)
rotation = lerp_angle(min_angle, max_angle, elapsed) rotation = lerp_angle(min_angle, max_angle, elapsed)
elapsed += delta elapsed += delta
[/codeblock] [/codeblock]
[b]Note:[/b] This function lerps through the shortest path between [param from] and [param to]. However, when these two angles are approximately [code]PI + k * TAU[/code] apart for any integer [code]k[/code], it's not obvious which way they lerp due to floating-point precision errors. For example, [code]lerp_angle(0, PI, weight)[/code] lerps counter-clockwise, while [code]lerp_angle(0, PI + 5 * TAU, weight)[/code] lerps clockwise. [b]Note:[/b] This function lerps through the shortest path between [param from] and [param to]. However, when these two angles are approximately [code]PI + k * TAU[/code] apart for any integer [code]k[/code], it's not obvious which way they lerp due to floating-point precision errors. For example, [code]lerp_angle(0, PI, weight)[/code] lerps counter-clockwise, while [code]lerp_angle(0, PI + 5 * TAU, weight)[/code] lerps clockwise.
</description> </description>
@ -815,7 +815,7 @@
[codeblock] [codeblock]
print("#(i) (i % 3) (posmod(i, 3))") print("#(i) (i % 3) (posmod(i, 3))")
for i in range(-3, 4): for i in range(-3, 4):
print("%2d %2d | %2d" % [i, i % 3, posmod(i, 3)]) print("%2d %2d | %2d" % [i, i % 3, posmod(i, 3)])
[/codeblock] [/codeblock]
Prints: Prints:
[codeblock lang=text] [codeblock lang=text]
@ -1429,9 +1429,9 @@
json.parse('["a", "b", "c"]') json.parse('["a", "b", "c"]')
var result = json.get_data() var result = json.get_data()
if result is Array: if result is Array:
print(result[0]) # Prints "a" print(result[0]) # Prints "a"
else: else:
print("Unexpected result!") print("Unexpected result!")
[/codeblock] [/codeblock]
See also [method type_string]. See also [method type_string].
</description> </description>
@ -1471,8 +1471,8 @@
Prints: Prints:
[codeblock lang=text] [codeblock lang=text]
{ {
"a": 1, "a": 1,
"b": 2 "b": 2
} }
[/codeblock] [/codeblock]
[b]Note:[/b] Converting [Signal] or [Callable] is not supported and will result in an empty value for these types, regardless of their data. [b]Note:[/b] Converting [Signal] or [Callable] is not supported and will result in an empty value for these types, regardless of their data.
@ -2613,11 +2613,11 @@
[codeblock] [codeblock]
var error = method_that_returns_error() var error = method_that_returns_error()
if error != OK: if error != OK:
printerr("Failure!") printerr("Failure!")
# Or, alternatively: # Or, alternatively:
if error: if error:
printerr("Still failing!") printerr("Still failing!")
[/codeblock] [/codeblock]
[b]Note:[/b] Many functions do not return an error code, but will print error messages to standard output. [b]Note:[/b] Many functions do not return an error code, but will print error messages to standard output.
</constant> </constant>

View File

@ -12,30 +12,30 @@
var aes = AESContext.new() var aes = AESContext.new()
func _ready(): func _ready():
var key = "My secret key!!!" # Key must be either 16 or 32 bytes. var key = "My secret key!!!" # Key must be either 16 or 32 bytes.
var data = "My secret text!!" # Data size must be multiple of 16 bytes, apply padding if needed. var data = "My secret text!!" # Data size must be multiple of 16 bytes, apply padding if needed.
# Encrypt ECB # Encrypt ECB
aes.start(AESContext.MODE_ECB_ENCRYPT, key.to_utf8_buffer()) aes.start(AESContext.MODE_ECB_ENCRYPT, key.to_utf8_buffer())
var encrypted = aes.update(data.to_utf8_buffer()) var encrypted = aes.update(data.to_utf8_buffer())
aes.finish() aes.finish()
# Decrypt ECB # Decrypt ECB
aes.start(AESContext.MODE_ECB_DECRYPT, key.to_utf8_buffer()) aes.start(AESContext.MODE_ECB_DECRYPT, key.to_utf8_buffer())
var decrypted = aes.update(encrypted) var decrypted = aes.update(encrypted)
aes.finish() aes.finish()
# Check ECB # Check ECB
assert(decrypted == data.to_utf8_buffer()) assert(decrypted == data.to_utf8_buffer())
var iv = "My secret iv!!!!" # IV must be of exactly 16 bytes. var iv = "My secret iv!!!!" # IV must be of exactly 16 bytes.
# Encrypt CBC # Encrypt CBC
aes.start(AESContext.MODE_CBC_ENCRYPT, key.to_utf8_buffer(), iv.to_utf8_buffer()) aes.start(AESContext.MODE_CBC_ENCRYPT, key.to_utf8_buffer(), iv.to_utf8_buffer())
encrypted = aes.update(data.to_utf8_buffer()) encrypted = aes.update(data.to_utf8_buffer())
aes.finish() aes.finish()
# Decrypt CBC # Decrypt CBC
aes.start(AESContext.MODE_CBC_DECRYPT, key.to_utf8_buffer(), iv.to_utf8_buffer()) aes.start(AESContext.MODE_CBC_DECRYPT, key.to_utf8_buffer(), iv.to_utf8_buffer())
decrypted = aes.update(encrypted) decrypted = aes.update(encrypted)
aes.finish() aes.finish()
# Check CBC # Check CBC
assert(decrypted == data.to_utf8_buffer()) assert(decrypted == data.to_utf8_buffer())
[/gdscript] [/gdscript]
[csharp] [csharp]
using Godot; using Godot;
@ -43,35 +43,35 @@
public partial class MyNode : Node public partial class MyNode : Node
{ {
private AesContext _aes = new AesContext(); private AesContext _aes = new AesContext();
public override void _Ready() public override void _Ready()
{ {
string key = "My secret key!!!"; // Key must be either 16 or 32 bytes. string key = "My secret key!!!"; // Key must be either 16 or 32 bytes.
string data = "My secret text!!"; // Data size must be multiple of 16 bytes, apply padding if needed. string data = "My secret text!!"; // Data size must be multiple of 16 bytes, apply padding if needed.
// Encrypt ECB // Encrypt ECB
_aes.Start(AesContext.Mode.EcbEncrypt, key.ToUtf8Buffer()); _aes.Start(AesContext.Mode.EcbEncrypt, key.ToUtf8Buffer());
byte[] encrypted = _aes.Update(data.ToUtf8Buffer()); byte[] encrypted = _aes.Update(data.ToUtf8Buffer());
_aes.Finish(); _aes.Finish();
// Decrypt ECB // Decrypt ECB
_aes.Start(AesContext.Mode.EcbDecrypt, key.ToUtf8Buffer()); _aes.Start(AesContext.Mode.EcbDecrypt, key.ToUtf8Buffer());
byte[] decrypted = _aes.Update(encrypted); byte[] decrypted = _aes.Update(encrypted);
_aes.Finish(); _aes.Finish();
// Check ECB // Check ECB
Debug.Assert(decrypted == data.ToUtf8Buffer()); Debug.Assert(decrypted == data.ToUtf8Buffer());
string iv = "My secret iv!!!!"; // IV must be of exactly 16 bytes. string iv = "My secret iv!!!!"; // IV must be of exactly 16 bytes.
// Encrypt CBC // Encrypt CBC
_aes.Start(AesContext.Mode.EcbEncrypt, key.ToUtf8Buffer(), iv.ToUtf8Buffer()); _aes.Start(AesContext.Mode.EcbEncrypt, key.ToUtf8Buffer(), iv.ToUtf8Buffer());
encrypted = _aes.Update(data.ToUtf8Buffer()); encrypted = _aes.Update(data.ToUtf8Buffer());
_aes.Finish(); _aes.Finish();
// Decrypt CBC // Decrypt CBC
_aes.Start(AesContext.Mode.EcbDecrypt, key.ToUtf8Buffer(), iv.ToUtf8Buffer()); _aes.Start(AesContext.Mode.EcbDecrypt, key.ToUtf8Buffer(), iv.ToUtf8Buffer());
decrypted = _aes.Update(encrypted); decrypted = _aes.Update(encrypted);
_aes.Finish(); _aes.Finish();
// Check CBC // Check CBC
Debug.Assert(decrypted == data.ToUtf8Buffer()); Debug.Assert(decrypted == data.ToUtf8Buffer());
} }
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -14,14 +14,14 @@
extends AStar3D extends AStar3D
func _compute_cost(u, v): func _compute_cost(u, v):
var u_pos = get_point_position(u) var u_pos = get_point_position(u)
var v_pos = get_point_position(v) var v_pos = get_point_position(v)
return abs(u_pos.x - v_pos.x) + abs(u_pos.y - v_pos.y) + abs(u_pos.z - v_pos.z) return abs(u_pos.x - v_pos.x) + abs(u_pos.y - v_pos.y) + abs(u_pos.z - v_pos.z)
func _estimate_cost(u, v): func _estimate_cost(u, v):
var u_pos = get_point_position(u) var u_pos = get_point_position(u)
var v_pos = get_point_position(v) var v_pos = get_point_position(v)
return abs(u_pos.x - v_pos.x) + abs(u_pos.y - v_pos.y) + abs(u_pos.z - v_pos.z) return abs(u_pos.x - v_pos.x) + abs(u_pos.y - v_pos.y) + abs(u_pos.z - v_pos.z)
[/gdscript] [/gdscript]
[csharp] [csharp]
using Godot; using Godot;
@ -29,20 +29,20 @@
[GlobalClass] [GlobalClass]
public partial class MyAStar3D : AStar3D public partial class MyAStar3D : AStar3D
{ {
public override float _ComputeCost(long fromId, long toId) public override float _ComputeCost(long fromId, long toId)
{ {
Vector3 fromPoint = GetPointPosition(fromId); Vector3 fromPoint = GetPointPosition(fromId);
Vector3 toPoint = GetPointPosition(toId); Vector3 toPoint = GetPointPosition(toId);
return Mathf.Abs(fromPoint.X - toPoint.X) + Mathf.Abs(fromPoint.Y - toPoint.Y) + Mathf.Abs(fromPoint.Z - toPoint.Z); return Mathf.Abs(fromPoint.X - toPoint.X) + Mathf.Abs(fromPoint.Y - toPoint.Y) + Mathf.Abs(fromPoint.Z - toPoint.Z);
} }
public override float _EstimateCost(long fromId, long toId) public override float _EstimateCost(long fromId, long toId)
{ {
Vector3 fromPoint = GetPointPosition(fromId); Vector3 fromPoint = GetPointPosition(fromId);
Vector3 toPoint = GetPointPosition(toId); Vector3 toPoint = GetPointPosition(toId);
return Mathf.Abs(fromPoint.X - toPoint.X) + Mathf.Abs(fromPoint.Y - toPoint.Y) + Mathf.Abs(fromPoint.Z - toPoint.Z); return Mathf.Abs(fromPoint.X - toPoint.X) + Mathf.Abs(fromPoint.Y - toPoint.Y) + Mathf.Abs(fromPoint.Z - toPoint.Z);
} }
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -115,24 +115,24 @@
var current_rotation var current_rotation
func _process(delta): func _process(delta):
if Input.is_action_just_pressed("animate"): if Input.is_action_just_pressed("animate"):
current_rotation = get_quaternion() current_rotation = get_quaternion()
state_machine.travel("Animate") state_machine.travel("Animate")
var velocity = current_rotation * animation_tree.get_root_motion_position() / delta var velocity = current_rotation * animation_tree.get_root_motion_position() / delta
set_velocity(velocity) set_velocity(velocity)
move_and_slide() move_and_slide()
[/gdscript] [/gdscript]
[/codeblocks] [/codeblocks]
By using this in combination with [method get_root_motion_rotation_accumulator], you can apply the root motion position more correctly to account for the rotation of the node. By using this in combination with [method get_root_motion_rotation_accumulator], you can apply the root motion position more correctly to account for the rotation of the node.
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _process(delta): func _process(delta):
if Input.is_action_just_pressed("animate"): if Input.is_action_just_pressed("animate"):
state_machine.travel("Animate") state_machine.travel("Animate")
set_quaternion(get_quaternion() * animation_tree.get_root_motion_rotation()) set_quaternion(get_quaternion() * animation_tree.get_root_motion_rotation())
var velocity = (animation_tree.get_root_motion_rotation_accumulator().inverse() * get_quaternion()) * animation_tree.get_root_motion_position() / delta var velocity = (animation_tree.get_root_motion_rotation_accumulator().inverse() * get_quaternion()) * animation_tree.get_root_motion_position() / delta
set_velocity(velocity) set_velocity(velocity)
move_and_slide() move_and_slide()
[/gdscript] [/gdscript]
[/codeblocks] [/codeblocks]
If [member root_motion_local] is [code]true[/code], returns the pre-multiplied translation value with the inverted rotation. If [member root_motion_local] is [code]true[/code], returns the pre-multiplied translation value with the inverted rotation.
@ -140,12 +140,12 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _process(delta): func _process(delta):
if Input.is_action_just_pressed("animate"): if Input.is_action_just_pressed("animate"):
state_machine.travel("Animate") state_machine.travel("Animate")
set_quaternion(get_quaternion() * animation_tree.get_root_motion_rotation()) set_quaternion(get_quaternion() * animation_tree.get_root_motion_rotation())
var velocity = get_quaternion() * animation_tree.get_root_motion_position() / delta var velocity = get_quaternion() * animation_tree.get_root_motion_position() / delta
set_velocity(velocity) set_velocity(velocity)
move_and_slide() move_and_slide()
[/gdscript] [/gdscript]
[/codeblocks] [/codeblocks]
</description> </description>
@ -161,12 +161,12 @@
var prev_root_motion_position_accumulator var prev_root_motion_position_accumulator
func _process(delta): func _process(delta):
if Input.is_action_just_pressed("animate"): if Input.is_action_just_pressed("animate"):
state_machine.travel("Animate") state_machine.travel("Animate")
var current_root_motion_position_accumulator = animation_tree.get_root_motion_position_accumulator() var current_root_motion_position_accumulator = animation_tree.get_root_motion_position_accumulator()
var difference = current_root_motion_position_accumulator - prev_root_motion_position_accumulator var difference = current_root_motion_position_accumulator - prev_root_motion_position_accumulator
prev_root_motion_position_accumulator = current_root_motion_position_accumulator prev_root_motion_position_accumulator = current_root_motion_position_accumulator
transform.origin += difference transform.origin += difference
[/gdscript] [/gdscript]
[/codeblocks] [/codeblocks]
However, if the animation loops, an unintended discrete change may occur, so this is only useful for some simple use cases. However, if the animation loops, an unintended discrete change may occur, so this is only useful for some simple use cases.
@ -182,9 +182,9 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _process(delta): func _process(delta):
if Input.is_action_just_pressed("animate"): if Input.is_action_just_pressed("animate"):
state_machine.travel("Animate") state_machine.travel("Animate")
set_quaternion(get_quaternion() * animation_tree.get_root_motion_rotation()) set_quaternion(get_quaternion() * animation_tree.get_root_motion_rotation())
[/gdscript] [/gdscript]
[/codeblocks] [/codeblocks]
</description> </description>
@ -201,12 +201,12 @@
var prev_root_motion_rotation_accumulator var prev_root_motion_rotation_accumulator
func _process(delta): func _process(delta):
if Input.is_action_just_pressed("animate"): if Input.is_action_just_pressed("animate"):
state_machine.travel("Animate") state_machine.travel("Animate")
var current_root_motion_rotation_accumulator = animation_tree.get_root_motion_rotation_accumulator() var current_root_motion_rotation_accumulator = animation_tree.get_root_motion_rotation_accumulator()
var difference = prev_root_motion_rotation_accumulator.inverse() * current_root_motion_rotation_accumulator var difference = prev_root_motion_rotation_accumulator.inverse() * current_root_motion_rotation_accumulator
prev_root_motion_rotation_accumulator = current_root_motion_rotation_accumulator prev_root_motion_rotation_accumulator = current_root_motion_rotation_accumulator
transform.basis *= Basis(difference) transform.basis *= Basis(difference)
[/gdscript] [/gdscript]
[/codeblocks] [/codeblocks]
However, if the animation loops, an unintended discrete change may occur, so this is only useful for some simple use cases. However, if the animation loops, an unintended discrete change may occur, so this is only useful for some simple use cases.
@ -225,12 +225,12 @@
var scale_accum = Vector3(1, 1, 1) var scale_accum = Vector3(1, 1, 1)
func _process(delta): func _process(delta):
if Input.is_action_just_pressed("animate"): if Input.is_action_just_pressed("animate"):
current_scale = get_scale() current_scale = get_scale()
scale_accum = Vector3(1, 1, 1) scale_accum = Vector3(1, 1, 1)
state_machine.travel("Animate") state_machine.travel("Animate")
scale_accum += animation_tree.get_root_motion_scale() scale_accum += animation_tree.get_root_motion_scale()
set_scale(current_scale * scale_accum) set_scale(current_scale * scale_accum)
[/gdscript] [/gdscript]
[/codeblocks] [/codeblocks]
</description> </description>
@ -245,12 +245,12 @@
var prev_root_motion_scale_accumulator var prev_root_motion_scale_accumulator
func _process(delta): func _process(delta):
if Input.is_action_just_pressed("animate"): if Input.is_action_just_pressed("animate"):
state_machine.travel("Animate") state_machine.travel("Animate")
var current_root_motion_scale_accumulator = animation_tree.get_root_motion_scale_accumulator() var current_root_motion_scale_accumulator = animation_tree.get_root_motion_scale_accumulator()
var difference = current_root_motion_scale_accumulator - prev_root_motion_scale_accumulator var difference = current_root_motion_scale_accumulator - prev_root_motion_scale_accumulator
prev_root_motion_scale_accumulator = current_root_motion_scale_accumulator prev_root_motion_scale_accumulator = current_root_motion_scale_accumulator
transform.basis = transform.basis.scaled(difference) transform.basis = transform.basis.scaled(difference)
[/gdscript] [/gdscript]
[/codeblocks] [/codeblocks]
However, if the animation loops, an unintended discrete change may occur, so this is only useful for some simple use cases. However, if the animation loops, an unintended discrete change may occur, so this is only useful for some simple use cases.

View File

@ -57,13 +57,13 @@
extends Node extends Node
class Stats: class Stats:
pass pass
func _ready(): func _ready():
var a = Array([], TYPE_INT, "", null) # Array[int] var a = Array([], TYPE_INT, "", null) # Array[int]
var b = Array([], TYPE_OBJECT, "Node", null) # Array[Node] var b = Array([], TYPE_OBJECT, "Node", null) # Array[Node]
var c = Array([], TYPE_OBJECT, "Node", Sword) # Array[Sword] var c = Array([], TYPE_OBJECT, "Node", Sword) # Array[Sword]
var d = Array([], TYPE_OBJECT, "RefCounted", Stats) # Array[Stats] var d = Array([], TYPE_OBJECT, "RefCounted", Stats) # Array[Stats]
[/codeblock] [/codeblock]
The [param base] array's elements are converted when necessary. If this is not possible or [param base] is already typed, this constructor fails and returns an empty [Array]. The [param base] array's elements are converted when necessary. If this is not possible or [param base] is already typed, this constructor fails and returns an empty [Array].
In GDScript, this constructor is usually not necessary, as it is possible to create a typed array through static typing: In GDScript, this constructor is usually not necessary, as it is possible to create a typed array through static typing:
@ -164,36 +164,36 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func greater_than_5(number): func greater_than_5(number):
return number &gt; 5 return number &gt; 5
func _ready(): func _ready():
print([6, 10, 6].all(greater_than_5)) # Prints true (3/3 elements evaluate to true). print([6, 10, 6].all(greater_than_5)) # Prints true (3/3 elements evaluate to true).
print([4, 10, 4].all(greater_than_5)) # Prints false (1/3 elements evaluate to true). print([4, 10, 4].all(greater_than_5)) # Prints false (1/3 elements evaluate to true).
print([4, 4, 4].all(greater_than_5)) # Prints false (0/3 elements evaluate to true). print([4, 4, 4].all(greater_than_5)) # Prints false (0/3 elements evaluate to true).
print([].all(greater_than_5)) # Prints true (0/0 elements evaluate to true). print([].all(greater_than_5)) # Prints true (0/0 elements evaluate to true).
# Same as the first line above, but using a lambda function. # Same as the first line above, but using a lambda function.
print([6, 10, 6].all(func(element): return element &gt; 5)) # Prints true print([6, 10, 6].all(func(element): return element &gt; 5)) # Prints true
[/gdscript] [/gdscript]
[csharp] [csharp]
private static bool GreaterThan5(int number) private static bool GreaterThan5(int number)
{ {
return number &gt; 5; return number &gt; 5;
} }
public override void _Ready() public override void _Ready()
{ {
// Prints True (3/3 elements evaluate to true). // Prints True (3/3 elements evaluate to true).
GD.Print(new Godot.Collections.Array&gt;int&lt; { 6, 10, 6 }.All(GreaterThan5)); GD.Print(new Godot.Collections.Array&gt;int&lt; { 6, 10, 6 }.All(GreaterThan5));
// Prints False (1/3 elements evaluate to true). // Prints False (1/3 elements evaluate to true).
GD.Print(new Godot.Collections.Array&gt;int&lt; { 4, 10, 4 }.All(GreaterThan5)); GD.Print(new Godot.Collections.Array&gt;int&lt; { 4, 10, 4 }.All(GreaterThan5));
// Prints False (0/3 elements evaluate to true). // Prints False (0/3 elements evaluate to true).
GD.Print(new Godot.Collections.Array&gt;int&lt; { 4, 4, 4 }.All(GreaterThan5)); GD.Print(new Godot.Collections.Array&gt;int&lt; { 4, 4, 4 }.All(GreaterThan5));
// Prints True (0/0 elements evaluate to true). // Prints True (0/0 elements evaluate to true).
GD.Print(new Godot.Collections.Array&gt;int&lt; { }.All(GreaterThan5)); GD.Print(new Godot.Collections.Array&gt;int&lt; { }.All(GreaterThan5));
// Same as the first line above, but using a lambda function. // Same as the first line above, but using a lambda function.
GD.Print(new Godot.Collections.Array&gt;int&lt; { 6, 10, 6 }.All(element =&gt; element &gt; 5)); // Prints True GD.Print(new Godot.Collections.Array&gt;int&lt; { 6, 10, 6 }.All(element =&gt; element &gt; 5)); // Prints True
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -210,16 +210,16 @@
The [param method] should take one [Variant] parameter (the current array element) and return a [bool]. The [param method] should take one [Variant] parameter (the current array element) and return a [bool].
[codeblock] [codeblock]
func greater_than_5(number): func greater_than_5(number):
return number &gt; 5 return number &gt; 5
func _ready(): func _ready():
print([6, 10, 6].any(greater_than_5)) # Prints true (3 elements evaluate to true). print([6, 10, 6].any(greater_than_5)) # Prints true (3 elements evaluate to true).
print([4, 10, 4].any(greater_than_5)) # Prints true (1 elements evaluate to true). print([4, 10, 4].any(greater_than_5)) # Prints true (1 elements evaluate to true).
print([4, 4, 4].any(greater_than_5)) # Prints false (0 elements evaluate to true). print([4, 4, 4].any(greater_than_5)) # Prints false (0 elements evaluate to true).
print([].any(greater_than_5)) # Prints false (0 elements evaluate to true). print([].any(greater_than_5)) # Prints false (0 elements evaluate to true).
# Same as the first line above, but using a lambda function. # Same as the first line above, but using a lambda function.
print([6, 10, 6].any(func(number): return number &gt; 5)) # Prints true print([6, 10, 6].any(func(number): return number &gt; 5)) # Prints true
[/codeblock] [/codeblock]
See also [method all], [method filter], [method map] and [method reduce]. See also [method all], [method filter], [method map] and [method reduce].
[b]Note:[/b] Unlike relying on the size of an array returned by [method filter], this method will return as early as possible to improve performance (especially with large arrays). [b]Note:[/b] Unlike relying on the size of an array returned by [method filter], this method will return as early as possible to improve performance (especially with large arrays).
@ -292,23 +292,23 @@
If [param before] is [code]true[/code] (as by default), the returned index comes before all existing elements equal to [param value] in the array. If [param before] is [code]true[/code] (as by default), the returned index comes before all existing elements equal to [param value] in the array.
[codeblock] [codeblock]
func sort_by_amount(a, b): func sort_by_amount(a, b):
if a[1] &lt; b[1]: if a[1] &lt; b[1]:
return true return true
return false return false
func _ready(): func _ready():
var my_items = [["Tomato", 2], ["Kiwi", 5], ["Rice", 9]] var my_items = [["Tomato", 2], ["Kiwi", 5], ["Rice", 9]]
var apple = ["Apple", 5] var apple = ["Apple", 5]
# "Apple" is inserted before "Kiwi". # "Apple" is inserted before "Kiwi".
my_items.insert(my_items.bsearch_custom(apple, sort_by_amount, true), apple) my_items.insert(my_items.bsearch_custom(apple, sort_by_amount, true), apple)
var banana = ["Banana", 5] var banana = ["Banana", 5]
# "Banana" is inserted after "Kiwi". # "Banana" is inserted after "Kiwi".
my_items.insert(my_items.bsearch_custom(banana, sort_by_amount, false), banana) my_items.insert(my_items.bsearch_custom(banana, sort_by_amount, false), banana)
# Prints [["Tomato", 2], ["Apple", 5], ["Kiwi", 5], ["Banana", 5], ["Rice", 9]] # Prints [["Tomato", 2], ["Apple", 5], ["Kiwi", 5], ["Banana", 5], ["Rice", 9]]
print(my_items) print(my_items)
[/codeblock] [/codeblock]
[b]Note:[/b] Calling [method bsearch_custom] on an [i]unsorted[/i] array will result in unexpected behavior. Use [method sort_custom] with [param func] before calling this method. [b]Note:[/b] Calling [method bsearch_custom] on an [i]unsorted[/i] array will result in unexpected behavior. Use [method sort_custom] with [param func] before calling this method.
</description> </description>
@ -384,13 +384,13 @@
The [param method] receives one of the array elements as an argument, and should return [code]true[/code] to add the element to the filtered array, or [code]false[/code] to exclude it. The [param method] receives one of the array elements as an argument, and should return [code]true[/code] to add the element to the filtered array, or [code]false[/code] to exclude it.
[codeblock] [codeblock]
func is_even(number): func is_even(number):
return number % 2 == 0 return number % 2 == 0
func _ready(): func _ready():
print([1, 4, 5, 8].filter(is_even)) # Prints [4, 8] print([1, 4, 5, 8].filter(is_even)) # Prints [4, 8]
# Same as above, but using a lambda function. # Same as above, but using a lambda function.
print([1, 4, 5, 8].filter(func(number): return number % 2 == 0)) print([1, 4, 5, 8].filter(func(number): return number % 2 == 0))
[/codeblock] [/codeblock]
See also [method any], [method all], [method map] and [method reduce]. See also [method any], [method all], [method map] and [method reduce].
</description> </description>
@ -416,10 +416,10 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func is_even(number): func is_even(number):
return number % 2 == 0 return number % 2 == 0
func _ready(): func _ready():
print([1, 3, 4, 7].find_custom(is_even.bind())) # Prints 2 print([1, 3, 4, 7].find_custom(is_even.bind())) # Prints 2
[/gdscript] [/gdscript]
[/codeblocks] [/codeblocks]
</description> </description>
@ -481,7 +481,7 @@
In GDScript, this is equivalent to the [code]in[/code] operator: In GDScript, this is equivalent to the [code]in[/code] operator:
[codeblock] [codeblock]
if 4 in [2, 4, 6, 8]: if 4 in [2, 4, 6, 8]:
print("4 is here!") # Will be printed. print("4 is here!") # Will be printed.
[/codeblock] [/codeblock]
[b]Note:[/b] For performance reasons, the search is affected by the [param value]'s [enum Variant.Type]. For example, [code]7[/code] ([int]) and [code]7.0[/code] ([float]) are not considered equal for this method. [b]Note:[/b] For performance reasons, the search is affected by the [param value]'s [enum Variant.Type]. For example, [code]7[/code] ([int]) and [code]7.0[/code] ([float]) are not considered equal for this method.
</description> </description>
@ -549,13 +549,13 @@
The [param method] should take one [Variant] parameter (the current array element) and can return any [Variant]. The [param method] should take one [Variant] parameter (the current array element) and can return any [Variant].
[codeblock] [codeblock]
func double(number): func double(number):
return number * 2 return number * 2
func _ready(): func _ready():
print([1, 2, 3].map(double)) # Prints [2, 4, 6] print([1, 2, 3].map(double)) # Prints [2, 4, 6]
# Same as above, but using a lambda function. # Same as above, but using a lambda function.
print([1, 2, 3].map(func(element): return element * 2)) print([1, 2, 3].map(func(element): return element * 2))
[/codeblock] [/codeblock]
See also [method filter], [method reduce], [method any] and [method all]. See also [method filter], [method reduce], [method any] and [method all].
</description> </description>
@ -635,36 +635,36 @@
The [param method] takes two arguments: the current value of [param accum] and the current array element. If [param accum] is [code]null[/code] (as by default), the iteration will start from the second element, with the first one used as initial value of [param accum]. The [param method] takes two arguments: the current value of [param accum] and the current array element. If [param accum] is [code]null[/code] (as by default), the iteration will start from the second element, with the first one used as initial value of [param accum].
[codeblock] [codeblock]
func sum(accum, number): func sum(accum, number):
return accum + number return accum + number
func _ready(): func _ready():
print([1, 2, 3].reduce(sum, 0)) # Prints 6 print([1, 2, 3].reduce(sum, 0)) # Prints 6
print([1, 2, 3].reduce(sum, 10)) # Prints 16 print([1, 2, 3].reduce(sum, 10)) # Prints 16
# Same as above, but using a lambda function. # Same as above, but using a lambda function.
print([1, 2, 3].reduce(func(accum, number): return accum + number, 10)) print([1, 2, 3].reduce(func(accum, number): return accum + number, 10))
[/codeblock] [/codeblock]
If [method max] is not desirable, this method may also be used to implement a custom comparator: If [method max] is not desirable, this method may also be used to implement a custom comparator:
[codeblock] [codeblock]
func _ready(): func _ready():
var arr = [Vector2i(5, 0), Vector2i(3, 4), Vector2i(1, 2)] var arr = [Vector2i(5, 0), Vector2i(3, 4), Vector2i(1, 2)]
var longest_vec = arr.reduce(func(max, vec): return vec if is_length_greater(vec, max) else max) var longest_vec = arr.reduce(func(max, vec): return vec if is_length_greater(vec, max) else max)
print(longest_vec) # Prints (3, 4) print(longest_vec) # Prints (3, 4)
func is_length_greater(a, b): func is_length_greater(a, b):
return a.length() &gt; b.length() return a.length() &gt; b.length()
[/codeblock] [/codeblock]
This method can also be used to count how many elements in an array satisfy a certain condition, similar to [method count]: This method can also be used to count how many elements in an array satisfy a certain condition, similar to [method count]:
[codeblock] [codeblock]
func is_even(number): func is_even(number):
return number % 2 == 0 return number % 2 == 0
func _ready(): func _ready():
var arr = [1, 2, 3, 4, 5] var arr = [1, 2, 3, 4, 5]
# If the current element is even, increment count, otherwise leave count the same. # If the current element is even, increment count, otherwise leave count the same.
var even_count = arr.reduce(func(count, next): return count + 1 if is_even(next) else count, 0) var even_count = arr.reduce(func(count, next): return count + 1 if is_even(next) else count, 0)
print(even_count) # Prints 2 print(even_count) # Prints 2
[/codeblock] [/codeblock]
See also [method map], [method filter], [method any], and [method all]. See also [method map], [method filter], [method any], and [method all].
</description> </description>
@ -781,18 +781,18 @@
[param func] is called as many times as necessary, receiving two array elements as arguments. The function should return [code]true[/code] if the first element should be moved [i]before[/i] the second one, otherwise it should return [code]false[/code]. [param func] is called as many times as necessary, receiving two array elements as arguments. The function should return [code]true[/code] if the first element should be moved [i]before[/i] the second one, otherwise it should return [code]false[/code].
[codeblock] [codeblock]
func sort_ascending(a, b): func sort_ascending(a, b):
if a[1] &lt; b[1]: if a[1] &lt; b[1]:
return true return true
return false return false
func _ready(): func _ready():
var my_items = [["Tomato", 5], ["Apple", 9], ["Rice", 4]] var my_items = [["Tomato", 5], ["Apple", 9], ["Rice", 4]]
my_items.sort_custom(sort_ascending) my_items.sort_custom(sort_ascending)
print(my_items) # Prints [["Rice", 4], ["Tomato", 5], ["Apple", 9]] print(my_items) # Prints [["Rice", 4], ["Tomato", 5], ["Apple", 9]]
# Sort descending, using a lambda function. # Sort descending, using a lambda function.
my_items.sort_custom(func(a, b): return a[1] &gt; b[1]) my_items.sort_custom(func(a, b): return a[1] &gt; b[1])
print(my_items) # Prints [["Apple", 9], ["Tomato", 5], ["Rice", 4]] print(my_items) # Prints [["Apple", 9], ["Tomato", 5], ["Rice", 4]]
[/codeblock] [/codeblock]
It may also be necessary to use this method to sort strings by natural order, with [method String.naturalnocasecmp_to], as in the following example: It may also be necessary to use this method to sort strings by natural order, with [method String.naturalnocasecmp_to], as in the following example:
[codeblock] [codeblock]

View File

@ -27,9 +27,9 @@
[csharp] [csharp]
Vector3[] vertices = Vector3[] vertices =
[ [
new Vector3(0, 1, 0), new Vector3(0, 1, 0),
new Vector3(1, 0, 0), new Vector3(1, 0, 0),
new Vector3(0, 0, 1), new Vector3(0, 0, 1),
]; ];
// Initialize the ArrayMesh. // Initialize the ArrayMesh.

View File

@ -22,10 +22,10 @@
@export var strength = 4.0 @export var strength = 4.0
func _instantiate(): func _instantiate():
var effect = CustomAudioEffectInstance.new() var effect = CustomAudioEffectInstance.new()
effect.base = self effect.base = self
return effect return effect
[/codeblock] [/codeblock]
[b]Note:[/b] It is recommended to keep a reference to the original [AudioEffect] in the new instance. Depending on the implementation this allows the effect instance to listen for changes at run-time and be modified accordingly. [b]Note:[/b] It is recommended to keep a reference to the original [AudioEffect] in the new instance. Depending on the implementation this allows the effect instance to listen for changes at run-time and be modified accordingly.
</description> </description>

View File

@ -14,17 +14,17 @@
var phase = 0.0 var phase = 0.0
func _ready(): func _ready():
$AudioStreamPlayer.play() $AudioStreamPlayer.play()
playback = $AudioStreamPlayer.get_stream_playback() playback = $AudioStreamPlayer.get_stream_playback()
fill_buffer() fill_buffer()
func fill_buffer(): func fill_buffer():
var increment = pulse_hz / sample_hz var increment = pulse_hz / sample_hz
var frames_available = playback.get_frames_available() var frames_available = playback.get_frames_available()
for i in range(frames_available): for i in range(frames_available):
playback.push_frame(Vector2.ONE * sin(phase * TAU)) playback.push_frame(Vector2.ONE * sin(phase * TAU))
phase = fmod(phase + increment, 1.0) phase = fmod(phase + increment, 1.0)
[/gdscript] [/gdscript]
[csharp] [csharp]
[Export] public AudioStreamPlayer Player { get; set; } [Export] public AudioStreamPlayer Player { get; set; }
@ -36,25 +36,25 @@
public override void _Ready() public override void _Ready()
{ {
if (Player.Stream is AudioStreamGenerator generator) // Type as a generator to access MixRate. if (Player.Stream is AudioStreamGenerator generator) // Type as a generator to access MixRate.
{ {
_sampleHz = generator.MixRate; _sampleHz = generator.MixRate;
Player.Play(); Player.Play();
_playback = (AudioStreamGeneratorPlayback)Player.GetStreamPlayback(); _playback = (AudioStreamGeneratorPlayback)Player.GetStreamPlayback();
FillBuffer(); FillBuffer();
} }
} }
public void FillBuffer() public void FillBuffer()
{ {
float increment = _pulseHz / _sampleHz; float increment = _pulseHz / _sampleHz;
int framesAvailable = _playback.GetFramesAvailable(); int framesAvailable = _playback.GetFramesAvailable();
for (int i = 0; i &lt; framesAvailable; i++) for (int i = 0; i &lt; framesAvailable; i++)
{ {
_playback.PushFrame(Vector2.One * (float)Mathf.Sin(phase * Mathf.Tau)); _playback.PushFrame(Vector2.One * (float)Mathf.Sin(phase * Mathf.Tau));
phase = Mathf.PosMod(phase + increment, 1.0); phase = Mathf.PosMod(phase + increment, 1.0);
} }
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -32,15 +32,15 @@
@onready var audio_player = $AudioStreamPlayer @onready var audio_player = $AudioStreamPlayer
func _ready(): func _ready():
get_window().files_dropped.connect(_on_files_dropped) get_window().files_dropped.connect(_on_files_dropped)
func _on_files_dropped(files): func _on_files_dropped(files):
if files[0].get_extension() == "wav": if files[0].get_extension() == "wav":
audio_player.stream = AudioStreamWAV.load_from_file(files[0], { audio_player.stream = AudioStreamWAV.load_from_file(files[0], {
"force/max_rate": true, "force/max_rate": true,
"force/max_rate_hz": 11025 "force/max_rate_hz": 11025
}) })
audio_player.play() audio_player.play()
[/codeblock] [/codeblock]
</description> </description>
</method> </method>

View File

@ -155,9 +155,9 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
var my_basis = Basis( var my_basis = Basis(
Vector3(2, 0, 0), Vector3(2, 0, 0),
Vector3(0, 4, 0), Vector3(0, 4, 0),
Vector3(0, 0, 8) Vector3(0, 0, 8)
) )
# Rotating the Basis in any way preserves its scale. # Rotating the Basis in any way preserves its scale.
my_basis = my_basis.rotated(Vector3.UP, TAU / 2) my_basis = my_basis.rotated(Vector3.UP, TAU / 2)
@ -167,9 +167,9 @@
[/gdscript] [/gdscript]
[csharp] [csharp]
var myBasis = new Basis( var myBasis = new Basis(
Vector3(2.0f, 0.0f, 0.0f), Vector3(2.0f, 0.0f, 0.0f),
Vector3(0.0f, 4.0f, 0.0f), Vector3(0.0f, 4.0f, 0.0f),
Vector3(0.0f, 0.0f, 8.0f) Vector3(0.0f, 0.0f, 8.0f)
); );
// Rotating the Basis in any way preserves its scale. // Rotating the Basis in any way preserves its scale.
myBasis = myBasis.Rotated(Vector3.Up, Mathf.Tau / 2.0f); myBasis = myBasis.Rotated(Vector3.Up, Mathf.Tau / 2.0f);
@ -227,18 +227,17 @@
[gdscript] [gdscript]
# Rotate this Node3D every frame. # Rotate this Node3D every frame.
func _process(delta): func _process(delta):
basis = basis.rotated(Vector3.UP, TAU * delta) basis = basis.rotated(Vector3.UP, TAU * delta)
basis = basis.rotated(Vector3.RIGHT, TAU * delta) basis = basis.rotated(Vector3.RIGHT, TAU * delta)
basis = basis.orthonormalized()
basis = basis.orthonormalized()
[/gdscript] [/gdscript]
[csharp] [csharp]
// Rotate this Node3D every frame. // Rotate this Node3D every frame.
public override void _Process(double delta) public override void _Process(double delta)
{ {
Basis = Basis.Rotated(Vector3.Up, Mathf.Tau * (float)delta) Basis = Basis.Rotated(Vector3.Up, Mathf.Tau * (float)delta)
.Rotated(Vector3.Right, Mathf.Tau * (float)delta) .Rotated(Vector3.Right, Mathf.Tau * (float)delta)
.Orthonormalized(); .Orthonormalized();
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -280,9 +279,9 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
var my_basis = Basis( var my_basis = Basis(
Vector3(1, 1, 1), Vector3(1, 1, 1),
Vector3(2, 2, 2), Vector3(2, 2, 2),
Vector3(3, 3, 3) Vector3(3, 3, 3)
) )
my_basis = my_basis.scaled(Vector3(0, 2, -2)) my_basis = my_basis.scaled(Vector3(0, 2, -2))
@ -292,9 +291,9 @@
[/gdscript] [/gdscript]
[csharp] [csharp]
var myBasis = new Basis( var myBasis = new Basis(
new Vector3(1.0f, 1.0f, 1.0f), new Vector3(1.0f, 1.0f, 1.0f),
new Vector3(2.0f, 2.0f, 2.0f), new Vector3(2.0f, 2.0f, 2.0f),
new Vector3(3.0f, 3.0f, 3.0f) new Vector3(3.0f, 3.0f, 3.0f)
); );
myBasis = myBasis.Scaled(new Vector3(0.0f, 2.0f, -2.0f)); myBasis = myBasis.Scaled(new Vector3(0.0f, 2.0f, -2.0f));
@ -317,10 +316,10 @@
var target_basis = Basis.IDENTITY.rotated(Vector3.UP, TAU / 2) var target_basis = Basis.IDENTITY.rotated(Vector3.UP, TAU / 2)
func _ready(): func _ready():
create_tween().tween_method(interpolate, 0.0, 1.0, 5.0).set_trans(Tween.TRANS_EXPO) create_tween().tween_method(interpolate, 0.0, 1.0, 5.0).set_trans(Tween.TRANS_EXPO)
func interpolate(weight): func interpolate(weight):
basis = start_basis.slerp(target_basis, weight) basis = start_basis.slerp(target_basis, weight)
[/codeblock] [/codeblock]
</description> </description>
</method> </method>
@ -355,9 +354,9 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
var my_basis = Basis( var my_basis = Basis(
Vector3(1, 2, 3), Vector3(1, 2, 3),
Vector3(4, 5, 6), Vector3(4, 5, 6),
Vector3(7, 8, 9) Vector3(7, 8, 9)
) )
my_basis = my_basis.transposed() my_basis = my_basis.transposed()
@ -367,9 +366,9 @@
[/gdscript] [/gdscript]
[csharp] [csharp]
var myBasis = new Basis( var myBasis = new Basis(
new Vector3(1.0f, 2.0f, 3.0f), new Vector3(1.0f, 2.0f, 3.0f),
new Vector3(4.0f, 5.0f, 6.0f), new Vector3(4.0f, 5.0f, 6.0f),
new Vector3(7.0f, 8.0f, 9.0f) new Vector3(7.0f, 8.0f, 9.0f)
); );
myBasis = myBasis.Transposed(); myBasis = myBasis.Transposed();

View File

@ -9,26 +9,26 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _ready(): func _ready():
var button = Button.new() var button = Button.new()
button.text = "Click me" button.text = "Click me"
button.pressed.connect(_button_pressed) button.pressed.connect(_button_pressed)
add_child(button) add_child(button)
func _button_pressed(): func _button_pressed():
print("Hello world!") print("Hello world!")
[/gdscript] [/gdscript]
[csharp] [csharp]
public override void _Ready() public override void _Ready()
{ {
var button = new Button(); var button = new Button();
button.Text = "Click me"; button.Text = "Click me";
button.Pressed += ButtonPressed; button.Pressed += ButtonPressed;
AddChild(button); AddChild(button);
} }
private void ButtonPressed() private void ButtonPressed()
{ {
GD.Print("Hello world!"); GD.Print("Hello world!");
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -8,42 +8,42 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func print_args(arg1, arg2, arg3 = ""): func print_args(arg1, arg2, arg3 = ""):
prints(arg1, arg2, arg3) prints(arg1, arg2, arg3)
func test(): func test():
var callable = Callable(self, "print_args") var callable = Callable(self, "print_args")
callable.call("hello", "world") # Prints "hello world ". callable.call("hello", "world") # Prints "hello world ".
callable.call(Vector2.UP, 42, callable) # Prints "(0.0, -1.0) 42 Node(node.gd)::print_args" callable.call(Vector2.UP, 42, callable) # Prints "(0.0, -1.0) 42 Node(node.gd)::print_args"
callable.call("invalid") # Invalid call, should have at least 2 arguments. callable.call("invalid") # Invalid call, should have at least 2 arguments.
[/gdscript] [/gdscript]
[csharp] [csharp]
// Default parameter values are not supported. // Default parameter values are not supported.
public void PrintArgs(Variant arg1, Variant arg2, Variant arg3 = default) public void PrintArgs(Variant arg1, Variant arg2, Variant arg3 = default)
{ {
GD.PrintS(arg1, arg2, arg3); GD.PrintS(arg1, arg2, arg3);
} }
public void Test() public void Test()
{ {
// Invalid calls fail silently. // Invalid calls fail silently.
Callable callable = new Callable(this, MethodName.PrintArgs); Callable callable = new Callable(this, MethodName.PrintArgs);
callable.Call("hello", "world"); // Default parameter values are not supported, should have 3 arguments. callable.Call("hello", "world"); // Default parameter values are not supported, should have 3 arguments.
callable.Call(Vector2.Up, 42, callable); // Prints "(0, -1) 42 Node(Node.cs)::PrintArgs" callable.Call(Vector2.Up, 42, callable); // Prints "(0, -1) 42 Node(Node.cs)::PrintArgs"
callable.Call("invalid"); // Invalid call, should have 3 arguments. callable.Call("invalid"); // Invalid call, should have 3 arguments.
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
In GDScript, it's possible to create lambda functions within a method. Lambda functions are custom callables that are not associated with an [Object] instance. Optionally, lambda functions can also be named. The name will be displayed in the debugger, or when calling [method get_method]. In GDScript, it's possible to create lambda functions within a method. Lambda functions are custom callables that are not associated with an [Object] instance. Optionally, lambda functions can also be named. The name will be displayed in the debugger, or when calling [method get_method].
[codeblock] [codeblock]
func _init(): func _init():
var my_lambda = func (message): var my_lambda = func (message):
print(message) print(message)
# Prints "Hello everyone!" # Prints "Hello everyone!"
my_lambda.call("Hello everyone!") my_lambda.call("Hello everyone!")
# Prints "Attack!", when the button_pressed signal is emitted. # Prints "Attack!", when the button_pressed signal is emitted.
button_pressed.connect(func(): print("Attack!")) button_pressed.connect(func(): print("Attack!"))
[/codeblock] [/codeblock]
In GDScript, you can access methods and global functions as [Callable]s: In GDScript, you can access methods and global functions as [Callable]s:
[codeblock] [codeblock]
@ -117,12 +117,12 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _ready(): func _ready():
grab_focus.call_deferred() grab_focus.call_deferred()
[/gdscript] [/gdscript]
[csharp] [csharp]
public override void _Ready() public override void _Ready()
{ {
Callable.From(GrabFocus).CallDeferred(); Callable.From(GrabFocus).CallDeferred();
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -158,10 +158,10 @@
Returns the array of arguments bound via successive [method bind] or [method unbind] calls. These arguments will be added [i]after[/i] the arguments passed to the call, from which [method get_unbound_arguments_count] arguments on the right have been previously excluded. Returns the array of arguments bound via successive [method bind] or [method unbind] calls. These arguments will be added [i]after[/i] the arguments passed to the call, from which [method get_unbound_arguments_count] arguments on the right have been previously excluded.
[codeblock] [codeblock]
func get_effective_arguments(callable, call_args): func get_effective_arguments(callable, call_args):
assert(call_args.size() - callable.get_unbound_arguments_count() &gt;= 0) assert(call_args.size() - callable.get_unbound_arguments_count() &gt;= 0)
var result = call_args.slice(0, call_args.size() - callable.get_unbound_arguments_count()) var result = call_args.slice(0, call_args.size() - callable.get_unbound_arguments_count())
result.append_array(callable.get_bound_arguments()) result.append_array(callable.get_bound_arguments())
return result return result
[/codeblock] [/codeblock]
</description> </description>
</method> </method>
@ -254,8 +254,8 @@
[b]Note:[/b] When this method is chained with other similar methods, the order in which the argument list is modified is read from right to left. [b]Note:[/b] When this method is chained with other similar methods, the order in which the argument list is modified is read from right to left.
[codeblock] [codeblock]
func _ready(): func _ready():
foo.unbind(1).call(1, 2) # Calls foo(1). foo.unbind(1).call(1, 2) # Calls foo(1).
foo.bind(3, 4).unbind(1).call(1, 2) # Calls foo(1, 3, 4), note that it does not change the arguments from bind. foo.bind(3, 4).unbind(1).call(1, 2) # Calls foo(1, 3, 4), note that it does not change the arguments from bind.
[/codeblock] [/codeblock]
</description> </description>
</method> </method>

View File

@ -13,13 +13,13 @@
uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest; uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest;
void fragment() { void fragment() {
vec4 c = textureLod(screen_texture, SCREEN_UV, 0.0); vec4 c = textureLod(screen_texture, SCREEN_UV, 0.0);
if (c.a &gt; 0.0001) { if (c.a &gt; 0.0001) {
c.rgb /= c.a; c.rgb /= c.a;
} }
COLOR *= c; COLOR *= c;
} }
[/codeblock] [/codeblock]
[b]Note:[/b] Since [CanvasGroup] and [member CanvasItem.clip_children] both utilize the backbuffer, children of a [CanvasGroup] who have their [member CanvasItem.clip_children] set to anything other than [constant CanvasItem.CLIP_CHILDREN_DISABLED] will not function correctly. [b]Note:[/b] Since [CanvasGroup] and [member CanvasItem.clip_children] both utilize the backbuffer, children of a [CanvasGroup] who have their [member CanvasItem.clip_children] set to anything other than [constant CanvasItem.CLIP_CHILDREN_DISABLED] will not function correctly.

View File

@ -73,14 +73,14 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
for i in get_slide_collision_count(): for i in get_slide_collision_count():
var collision = get_slide_collision(i) var collision = get_slide_collision(i)
print("Collided with: ", collision.get_collider().name) print("Collided with: ", collision.get_collider().name)
[/gdscript] [/gdscript]
[csharp] [csharp]
for (int i = 0; i &lt; GetSlideCollisionCount(); i++) for (int i = 0; i &lt; GetSlideCollisionCount(); i++)
{ {
KinematicCollision2D collision = GetSlideCollision(i); KinematicCollision2D collision = GetSlideCollision(i);
GD.Print("Collided with: ", (collision.GetCollider() as Node).Name); GD.Print("Collided with: ", (collision.GetCollider() as Node).Name);
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -60,12 +60,12 @@
The raw normal and roughness buffer is stored in an optimized format, different than the one available in Spatial shaders. When sampling the buffer, a conversion function must be applied. Use this function, copied from [url=https://github.com/godotengine/godot/blob/da5f39889f155658cef7f7ec3cc1abb94e17d815/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl#L334-L341]here[/url]: The raw normal and roughness buffer is stored in an optimized format, different than the one available in Spatial shaders. When sampling the buffer, a conversion function must be applied. Use this function, copied from [url=https://github.com/godotengine/godot/blob/da5f39889f155658cef7f7ec3cc1abb94e17d815/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl#L334-L341]here[/url]:
[codeblock] [codeblock]
vec4 normal_roughness_compatibility(vec4 p_normal_roughness) { vec4 normal_roughness_compatibility(vec4 p_normal_roughness) {
float roughness = p_normal_roughness.w; float roughness = p_normal_roughness.w;
if (roughness &gt; 0.5) { if (roughness &gt; 0.5) {
roughness = 1.0 - roughness; roughness = 1.0 - roughness;
} }
roughness /= (127.0 / 255.0); roughness /= (127.0 / 255.0);
return vec4(normalize(p_normal_roughness.xyz * 2.0 - 1.0) * 0.5 + 0.5, roughness); return vec4(normalize(p_normal_roughness.xyz * 2.0 - 1.0) * 0.5 + 0.5, roughness);
} }
[/codeblock] [/codeblock]
</member> </member>

View File

@ -52,14 +52,14 @@
# If the file didn't load, ignore it. # If the file didn't load, ignore it.
if err != OK: if err != OK:
return return
# Iterate over all sections. # Iterate over all sections.
for player in config.get_sections(): for player in config.get_sections():
# Fetch the data for each section. # Fetch the data for each section.
var player_name = config.get_value(player, "player_name") var player_name = config.get_value(player, "player_name")
var player_score = config.get_value(player, "best_score") var player_score = config.get_value(player, "best_score")
score_data[player_name] = player_score score_data[player_name] = player_score
[/gdscript] [/gdscript]
[csharp] [csharp]
var score_data = new Godot.Collections.Dictionary(); var score_data = new Godot.Collections.Dictionary();
@ -71,16 +71,16 @@
// If the file didn't load, ignore it. // If the file didn't load, ignore it.
if (err != Error.Ok) if (err != Error.Ok)
{ {
return; return;
} }
// Iterate over all sections. // Iterate over all sections.
foreach (String player in config.GetSections()) foreach (String player in config.GetSections())
{ {
// Fetch the data for each section. // Fetch the data for each section.
var player_name = (String)config.GetValue(player, "player_name"); var player_name = (String)config.GetValue(player, "player_name");
var player_score = (int)config.GetValue(player, "best_score"); var player_score = (int)config.GetValue(player, "best_score");
score_data[player_name] = player_score; score_data[player_name] = player_score;
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -41,16 +41,16 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _can_drop_data(position, data): func _can_drop_data(position, data):
# Check position if it is relevant to you # Check position if it is relevant to you
# Otherwise, just check data # Otherwise, just check data
return typeof(data) == TYPE_DICTIONARY and data.has("expected") return typeof(data) == TYPE_DICTIONARY and data.has("expected")
[/gdscript] [/gdscript]
[csharp] [csharp]
public override bool _CanDropData(Vector2 atPosition, Variant data) public override bool _CanDropData(Vector2 atPosition, Variant data)
{ {
// Check position if it is relevant to you // Check position if it is relevant to you
// Otherwise, just check data // Otherwise, just check data
return data.VariantType == Variant.Type.Dictionary &amp;&amp; data.AsGodotDictionary().ContainsKey("expected"); return data.VariantType == Variant.Type.Dictionary &amp;&amp; data.AsGodotDictionary().ContainsKey("expected");
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -66,20 +66,20 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _can_drop_data(position, data): func _can_drop_data(position, data):
return typeof(data) == TYPE_DICTIONARY and data.has("color") return typeof(data) == TYPE_DICTIONARY and data.has("color")
func _drop_data(position, data): func _drop_data(position, data):
var color = data["color"] var color = data["color"]
[/gdscript] [/gdscript]
[csharp] [csharp]
public override bool _CanDropData(Vector2 atPosition, Variant data) public override bool _CanDropData(Vector2 atPosition, Variant data)
{ {
return data.VariantType == Variant.Type.Dictionary &amp;&amp; data.AsGodotDictionary().ContainsKey("color"); return data.VariantType == Variant.Type.Dictionary &amp;&amp; data.AsGodotDictionary().ContainsKey("color");
} }
public override void _DropData(Vector2 atPosition, Variant data) public override void _DropData(Vector2 atPosition, Variant data)
{ {
Color color = data.AsGodotDictionary()["color"].AsColor(); Color color = data.AsGodotDictionary()["color"].AsColor();
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -95,16 +95,16 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _get_drag_data(position): func _get_drag_data(position):
var mydata = make_data() # This is your custom method generating the drag data. var mydata = make_data() # This is your custom method generating the drag data.
set_drag_preview(make_preview(mydata)) # This is your custom method generating the preview of the drag data. set_drag_preview(make_preview(mydata)) # This is your custom method generating the preview of the drag data.
return mydata return mydata
[/gdscript] [/gdscript]
[csharp] [csharp]
public override Variant _GetDragData(Vector2 atPosition) public override Variant _GetDragData(Vector2 atPosition)
{ {
var myData = MakeData(); // This is your custom method generating the drag data. var myData = MakeData(); // This is your custom method generating the drag data.
SetDragPreview(MakePreview(myData)); // This is your custom method generating the preview of the drag data. SetDragPreview(MakePreview(myData)); // This is your custom method generating the preview of the drag data.
return myData; return myData;
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -135,20 +135,20 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _gui_input(event): func _gui_input(event):
if event is InputEventMouseButton: if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT and event.pressed: if event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
print("I've been clicked D:") print("I've been clicked D:")
[/gdscript] [/gdscript]
[csharp] [csharp]
public override void _GuiInput(InputEvent @event) public override void _GuiInput(InputEvent @event)
{ {
if (@event is InputEventMouseButton mb) if (@event is InputEventMouseButton mb)
{ {
if (mb.ButtonIndex == MouseButton.Left &amp;&amp; mb.Pressed) if (mb.ButtonIndex == MouseButton.Left &amp;&amp; mb.Pressed)
{ {
GD.Print("I've been clicked D:"); GD.Print("I've been clicked D:");
} }
} }
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -184,16 +184,16 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _make_custom_tooltip(for_text): func _make_custom_tooltip(for_text):
var label = Label.new() var label = Label.new()
label.text = for_text label.text = for_text
return label return label
[/gdscript] [/gdscript]
[csharp] [csharp]
public override Control _MakeCustomTooltip(string forText) public override Control _MakeCustomTooltip(string forText)
{ {
var label = new Label(); var label = new Label();
label.Text = forText; label.Text = forText;
return label; return label;
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -201,16 +201,16 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _make_custom_tooltip(for_text): func _make_custom_tooltip(for_text):
var tooltip = preload("res://some_tooltip_scene.tscn").instantiate() var tooltip = preload("res://some_tooltip_scene.tscn").instantiate()
tooltip.get_node("Label").text = for_text tooltip.get_node("Label").text = for_text
return tooltip return tooltip
[/gdscript] [/gdscript]
[csharp] [csharp]
public override Control _MakeCustomTooltip(string forText) public override Control _MakeCustomTooltip(string forText)
{ {
Node tooltip = ResourceLoader.Load&lt;PackedScene&gt;("res://some_tooltip_scene.tscn").Instantiate(); Node tooltip = ResourceLoader.Load&lt;PackedScene&gt;("res://some_tooltip_scene.tscn").Instantiate();
tooltip.GetNode&lt;Label&gt;("Label").Text = forText; tooltip.GetNode&lt;Label&gt;("Label").Text = forText;
return tooltip; return tooltip;
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -499,18 +499,18 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _ready(): func _ready():
# Get the font color defined for the current Control's class, if it exists. # Get the font color defined for the current Control's class, if it exists.
modulate = get_theme_color("font_color") modulate = get_theme_color("font_color")
# Get the font color defined for the Button class. # Get the font color defined for the Button class.
modulate = get_theme_color("font_color", "Button") modulate = get_theme_color("font_color", "Button")
[/gdscript] [/gdscript]
[csharp] [csharp]
public override void _Ready() public override void _Ready()
{ {
// Get the font color defined for the current Control's class, if it exists. // Get the font color defined for the current Control's class, if it exists.
Modulate = GetThemeColor("font_color"); Modulate = GetThemeColor("font_color");
// Get the font color defined for the Button class. // Get the font color defined for the Button class.
Modulate = GetThemeColor("font_color", "Button"); Modulate = GetThemeColor("font_color", "Button");
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -598,12 +598,12 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _process(delta): func _process(delta):
grab_click_focus() # When clicking another Control node, this node will be clicked instead. grab_click_focus() # When clicking another Control node, this node will be clicked instead.
[/gdscript] [/gdscript]
[csharp] [csharp]
public override void _Process(double delta) public override void _Process(double delta)
{ {
GrabClickFocus(); // When clicking another Control node, this node will be clicked instead. GrabClickFocus(); // When clicking another Control node, this node will be clicked instead.
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -861,12 +861,12 @@
@export var color = Color(1, 0, 0, 1) @export var color = Color(1, 0, 0, 1)
func _get_drag_data(position): func _get_drag_data(position):
# Use a control that is not in the tree # Use a control that is not in the tree
var cpb = ColorPickerButton.new() var cpb = ColorPickerButton.new()
cpb.color = color cpb.color = color
cpb.size = Vector2(50, 50) cpb.size = Vector2(50, 50)
set_drag_preview(cpb) set_drag_preview(cpb)
return color return color
[/gdscript] [/gdscript]
[csharp] [csharp]
[Export] [Export]
@ -874,12 +874,12 @@
public override Variant _GetDragData(Vector2 atPosition) public override Variant _GetDragData(Vector2 atPosition)
{ {
// Use a control that is not in the tree // Use a control that is not in the tree
var cpb = new ColorPickerButton(); var cpb = new ColorPickerButton();
cpb.Color = _color; cpb.Color = _color;
cpb.Size = new Vector2(50, 50); cpb.Size = new Vector2(50, 50);
SetDragPreview(cpb); SetDragPreview(cpb);
return _color; return _color;
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -1164,8 +1164,8 @@
[b]Note:[/b] If you want to check whether the mouse truly left the area, ignoring any top nodes, you can use code like this: [b]Note:[/b] If you want to check whether the mouse truly left the area, ignoring any top nodes, you can use code like this:
[codeblock] [codeblock]
func _on_mouse_exited(): func _on_mouse_exited():
if not Rect2(Vector2(), size).has_point(get_local_mouse_position()): if not Rect2(Vector2(), size).has_point(get_local_mouse_position()):
# Not hovering over area. # Not hovering over area.
[/codeblock] [/codeblock]
</description> </description>
</signal> </signal>
@ -1255,10 +1255,10 @@
[b]Note:[/b] This notification is received alongside [constant Node.NOTIFICATION_ENTER_TREE], so if you are instantiating a scene, the child nodes will not be initialized yet. You can use it to setup theming for this node, child nodes created from script, or if you want to access child nodes added in the editor, make sure the node is ready using [method Node.is_node_ready]. [b]Note:[/b] This notification is received alongside [constant Node.NOTIFICATION_ENTER_TREE], so if you are instantiating a scene, the child nodes will not be initialized yet. You can use it to setup theming for this node, child nodes created from script, or if you want to access child nodes added in the editor, make sure the node is ready using [method Node.is_node_ready].
[codeblock] [codeblock]
func _notification(what): func _notification(what):
if what == NOTIFICATION_THEME_CHANGED: if what == NOTIFICATION_THEME_CHANGED:
if not is_node_ready(): if not is_node_ready():
await ready # Wait until ready signal. await ready # Wait until ready signal.
$Label.add_theme_color_override("font_color", Color.YELLOW) $Label.add_theme_color_override("font_color", Color.YELLOW)
[/codeblock] [/codeblock]
</constant> </constant>
<constant name="NOTIFICATION_SCROLL_BEGIN" value="47"> <constant name="NOTIFICATION_SCROLL_BEGIN" value="47">

View File

@ -20,10 +20,10 @@
uniform float exposure : hint_range(0, 128) = 1.0; uniform float exposure : hint_range(0, 128) = 1.0;
void sky() { void sky() {
// If importing a cubemap from another engine, you may need to flip one of the `EYEDIR` components below // If importing a cubemap from another engine, you may need to flip one of the `EYEDIR` components below
// by replacing it with `-EYEDIR`. // by replacing it with `-EYEDIR`.
vec3 eyedir = vec3(EYEDIR.x, EYEDIR.y, EYEDIR.z); vec3 eyedir = vec3(EYEDIR.x, EYEDIR.y, EYEDIR.z);
COLOR = texture(source_panorama, eyedir).rgb * exposure; COLOR = texture(source_panorama, eyedir).rgb * exposure;
} }
[/codeblock] [/codeblock]
After replacing the shader code and saving, specify the imported Cubemap resource in the Shader Parameters section of the ShaderMaterial in the inspector. After replacing the shader code and saving, specify the imported Cubemap resource in the Shader Parameters section of the ShaderMaterial in the inspector.

View File

@ -16,26 +16,26 @@
var peers = [] var peers = []
func _ready(): func _ready():
server.listen(4242) server.listen(4242)
var key = load("key.key") # Your private key. var key = load("key.key") # Your private key.
var cert = load("cert.crt") # Your X509 certificate. var cert = load("cert.crt") # Your X509 certificate.
dtls.setup(TlsOptions.server(key, cert)) dtls.setup(TlsOptions.server(key, cert))
func _process(delta): func _process(delta):
while server.is_connection_available(): while server.is_connection_available():
var peer = server.take_connection() var peer = server.take_connection()
var dtls_peer = dtls.take_connection(peer) var dtls_peer = dtls.take_connection(peer)
if dtls_peer.get_status() != PacketPeerDTLS.STATUS_HANDSHAKING: if dtls_peer.get_status() != PacketPeerDTLS.STATUS_HANDSHAKING:
continue # It is normal that 50% of the connections fails due to cookie exchange. continue # It is normal that 50% of the connections fails due to cookie exchange.
print("Peer connected!") print("Peer connected!")
peers.append(dtls_peer) peers.append(dtls_peer)
for p in peers: for p in peers:
p.poll() # Must poll to update the state. p.poll() # Must poll to update the state.
if p.get_status() == PacketPeerDTLS.STATUS_CONNECTED: if p.get_status() == PacketPeerDTLS.STATUS_CONNECTED:
while p.get_available_packet_count() &gt; 0: while p.get_available_packet_count() &gt; 0:
print("Received message from client: %s" % p.get_packet().get_string_from_utf8()) print("Received message from client: %s" % p.get_packet().get_string_from_utf8())
p.put_packet("Hello DTLS client".to_utf8_buffer()) p.put_packet("Hello DTLS client".to_utf8_buffer())
[/gdscript] [/gdscript]
[csharp] [csharp]
// ServerNode.cs // ServerNode.cs
@ -43,45 +43,45 @@
public partial class ServerNode : Node public partial class ServerNode : Node
{ {
private DtlsServer _dtls = new DtlsServer(); private DtlsServer _dtls = new DtlsServer();
private UdpServer _server = new UdpServer(); private UdpServer _server = new UdpServer();
private Godot.Collections.Array&lt;PacketPeerDtls&gt; _peers = []; private Godot.Collections.Array&lt;PacketPeerDtls&gt; _peers = [];
public override void _Ready() public override void _Ready()
{ {
_server.Listen(4242); _server.Listen(4242);
var key = GD.Load&lt;CryptoKey&gt;("key.key"); // Your private key. var key = GD.Load&lt;CryptoKey&gt;("key.key"); // Your private key.
var cert = GD.Load&lt;X509Certificate&gt;("cert.crt"); // Your X509 certificate. var cert = GD.Load&lt;X509Certificate&gt;("cert.crt"); // Your X509 certificate.
_dtls.Setup(TlsOptions.Server(key, cert)); _dtls.Setup(TlsOptions.Server(key, cert));
} }
public override void _Process(double delta) public override void _Process(double delta)
{ {
while (_server.IsConnectionAvailable()) while (_server.IsConnectionAvailable())
{ {
PacketPeerUdp peer = _server.TakeConnection(); PacketPeerUdp peer = _server.TakeConnection();
PacketPeerDtls dtlsPeer = _dtls.TakeConnection(peer); PacketPeerDtls dtlsPeer = _dtls.TakeConnection(peer);
if (dtlsPeer.GetStatus() != PacketPeerDtls.Status.Handshaking) if (dtlsPeer.GetStatus() != PacketPeerDtls.Status.Handshaking)
{ {
continue; // It is normal that 50% of the connections fails due to cookie exchange. continue; // It is normal that 50% of the connections fails due to cookie exchange.
} }
GD.Print("Peer connected!"); GD.Print("Peer connected!");
_peers.Add(dtlsPeer); _peers.Add(dtlsPeer);
} }
foreach (var p in _peers) foreach (var p in _peers)
{ {
p.Poll(); // Must poll to update the state. p.Poll(); // Must poll to update the state.
if (p.GetStatus() == PacketPeerDtls.Status.Connected) if (p.GetStatus() == PacketPeerDtls.Status.Connected)
{ {
while (p.GetAvailablePacketCount() &gt; 0) while (p.GetAvailablePacketCount() &gt; 0)
{ {
GD.Print($"Received Message From Client: {p.GetPacket().GetStringFromUtf8()}"); GD.Print($"Received Message From Client: {p.GetPacket().GetStringFromUtf8()}");
p.PutPacket("Hello DTLS Client".ToUtf8Buffer()); p.PutPacket("Hello DTLS Client".ToUtf8Buffer());
} }
} }
} }
} }
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -95,18 +95,18 @@
var connected = false var connected = false
func _ready(): func _ready():
udp.connect_to_host("127.0.0.1", 4242) udp.connect_to_host("127.0.0.1", 4242)
dtls.connect_to_peer(udp, false) # Use true in production for certificate validation! dtls.connect_to_peer(udp, false) # Use true in production for certificate validation!
func _process(delta): func _process(delta):
dtls.poll() dtls.poll()
if dtls.get_status() == PacketPeerDTLS.STATUS_CONNECTED: if dtls.get_status() == PacketPeerDTLS.STATUS_CONNECTED:
if !connected: if !connected:
# Try to contact server # Try to contact server
dtls.put_packet("The answer is... 42!".to_utf8_buffer()) dtls.put_packet("The answer is... 42!".to_utf8_buffer())
while dtls.get_available_packet_count() &gt; 0: while dtls.get_available_packet_count() &gt; 0:
print("Connected: %s" % dtls.get_packet().get_string_from_utf8()) print("Connected: %s" % dtls.get_packet().get_string_from_utf8())
connected = true connected = true
[/gdscript] [/gdscript]
[csharp] [csharp]
// ClientNode.cs // ClientNode.cs
@ -115,33 +115,33 @@
public partial class ClientNode : Node public partial class ClientNode : Node
{ {
private PacketPeerDtls _dtls = new PacketPeerDtls(); private PacketPeerDtls _dtls = new PacketPeerDtls();
private PacketPeerUdp _udp = new PacketPeerUdp(); private PacketPeerUdp _udp = new PacketPeerUdp();
private bool _connected = false; private bool _connected = false;
public override void _Ready() public override void _Ready()
{ {
_udp.ConnectToHost("127.0.0.1", 4242); _udp.ConnectToHost("127.0.0.1", 4242);
_dtls.ConnectToPeer(_udp, validateCerts: false); // Use true in production for certificate validation! _dtls.ConnectToPeer(_udp, validateCerts: false); // Use true in production for certificate validation!
} }
public override void _Process(double delta) public override void _Process(double delta)
{ {
_dtls.Poll(); _dtls.Poll();
if (_dtls.GetStatus() == PacketPeerDtls.Status.Connected) if (_dtls.GetStatus() == PacketPeerDtls.Status.Connected)
{ {
if (!_connected) if (!_connected)
{ {
// Try to contact server // Try to contact server
_dtls.PutPacket("The Answer Is..42!".ToUtf8Buffer()); _dtls.PutPacket("The Answer Is..42!".ToUtf8Buffer());
} }
while (_dtls.GetAvailablePacketCount() &gt; 0) while (_dtls.GetAvailablePacketCount() &gt; 0)
{ {
GD.Print($"Connected: {_dtls.GetPacket().GetStringFromUtf8()}"); GD.Print($"Connected: {_dtls.GetPacket().GetStringFromUtf8()}");
_connected = true; _connected = true;
} }
} }
} }
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -24,12 +24,12 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
for i in Decal.TEXTURE_MAX: for i in Decal.TEXTURE_MAX:
$NewDecal.set_texture(i, $OldDecal.get_texture(i)) $NewDecal.set_texture(i, $OldDecal.get_texture(i))
[/gdscript] [/gdscript]
[csharp] [csharp]
for (int i = 0; i &lt; (int)Decal.DecalTexture.Max; i++) for (int i = 0; i &lt; (int)Decal.DecalTexture.Max; i++)
{ {
GetNode&lt;Decal&gt;("NewDecal").SetTexture(i, GetNode&lt;Decal&gt;("OldDecal").GetTexture(i)); GetNode&lt;Decal&gt;("NewDecal").SetTexture(i, GetNode&lt;Decal&gt;("OldDecal").GetTexture(i));
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -46,12 +46,12 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
for i in Decal.TEXTURE_MAX: for i in Decal.TEXTURE_MAX:
$NewDecal.set_texture(i, $OldDecal.get_texture(i)) $NewDecal.set_texture(i, $OldDecal.get_texture(i))
[/gdscript] [/gdscript]
[csharp] [csharp]
for (int i = 0; i &lt; (int)Decal.DecalTexture.Max; i++) for (int i = 0; i &lt; (int)Decal.DecalTexture.Max; i++)
{ {
GetNode&lt;Decal&gt;("NewDecal").SetTexture(i, GetNode&lt;Decal&gt;("OldDecal").GetTexture(i)); GetNode&lt;Decal&gt;("NewDecal").SetTexture(i, GetNode&lt;Decal&gt;("OldDecal").GetTexture(i));
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -14,8 +14,8 @@
var dict_variable_key = "Another key name" var dict_variable_key = "Another key name"
var dict_variable_value = "value2" var dict_variable_value = "value2"
var another_dict = { var another_dict = {
"Some key name": "value1", "Some key name": "value1",
dict_variable_key: dict_variable_value, dict_variable_key: dict_variable_value,
} }
var points_dict = {"White": 50, "Yellow": 75, "Orange": 100} var points_dict = {"White": 50, "Yellow": 75, "Orange": 100}
@ -25,16 +25,16 @@
# Additionally, key names must start with a letter or an underscore. # Additionally, key names must start with a letter or an underscore.
# Here, `some_key` is a string literal, not a variable! # Here, `some_key` is a string literal, not a variable!
another_dict = { another_dict = {
some_key = 42, some_key = 42,
} }
[/gdscript] [/gdscript]
[csharp] [csharp]
var myDict = new Godot.Collections.Dictionary(); // Creates an empty dictionary. var myDict = new Godot.Collections.Dictionary(); // Creates an empty dictionary.
var pointsDict = new Godot.Collections.Dictionary var pointsDict = new Godot.Collections.Dictionary
{ {
{"White", 50}, {"White", 50},
{"Yellow", 75}, {"Yellow", 75},
{"Orange", 100} {"Orange", 100}
}; };
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -44,22 +44,22 @@
@export_enum("White", "Yellow", "Orange") var my_color: String @export_enum("White", "Yellow", "Orange") var my_color: String
var points_dict = {"White": 50, "Yellow": 75, "Orange": 100} var points_dict = {"White": 50, "Yellow": 75, "Orange": 100}
func _ready(): func _ready():
# We can't use dot syntax here as `my_color` is a variable. # We can't use dot syntax here as `my_color` is a variable.
var points = points_dict[my_color] var points = points_dict[my_color]
[/gdscript] [/gdscript]
[csharp] [csharp]
[Export(PropertyHint.Enum, "White,Yellow,Orange")] [Export(PropertyHint.Enum, "White,Yellow,Orange")]
public string MyColor { get; set; } public string MyColor { get; set; }
private Godot.Collections.Dictionary _pointsDict = new Godot.Collections.Dictionary private Godot.Collections.Dictionary _pointsDict = new Godot.Collections.Dictionary
{ {
{"White", 50}, {"White", 50},
{"Yellow", 75}, {"Yellow", 75},
{"Orange", 100} {"Orange", 100}
}; };
public override void _Ready() public override void _Ready()
{ {
int points = (int)_pointsDict[MyColor]; int points = (int)_pointsDict[MyColor];
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -68,13 +68,13 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
var my_dict = { var my_dict = {
"First Array": [1, 2, 3, 4] # Assigns an Array to a String key. "First Array": [1, 2, 3, 4] # Assigns an Array to a String key.
} }
[/gdscript] [/gdscript]
[csharp] [csharp]
var myDict = new Godot.Collections.Dictionary var myDict = new Godot.Collections.Dictionary
{ {
{"First Array", new Godot.Collections.Array{1, 2, 3, 4}} {"First Array", new Godot.Collections.Array{1, 2, 3, 4}}
}; };
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -87,9 +87,9 @@
[csharp] [csharp]
var pointsDict = new Godot.Collections.Dictionary var pointsDict = new Godot.Collections.Dictionary
{ {
{"White", 50}, {"White", 50},
{"Yellow", 75}, {"Yellow", 75},
{"Orange", 100} {"Orange", 100}
}; };
pointsDict["Blue"] = 150; // Add "Blue" as a key and assign 150 as its value. pointsDict["Blue"] = 150; // Add "Blue" as a key and assign 150 as its value.
[/csharp] [/csharp]
@ -101,20 +101,20 @@
# To access the string "Nested value" below, use `my_dict.sub_dict.sub_key` or `my_dict["sub_dict"]["sub_key"]`. # To access the string "Nested value" below, use `my_dict.sub_dict.sub_key` or `my_dict["sub_dict"]["sub_key"]`.
# Indexing styles can be mixed and matched depending on your needs. # Indexing styles can be mixed and matched depending on your needs.
var my_dict = { var my_dict = {
"String Key": 5, "String Key": 5,
4: [1, 2, 3], 4: [1, 2, 3],
7: "Hello", 7: "Hello",
"sub_dict": {"sub_key": "Nested value"}, "sub_dict": {"sub_key": "Nested value"},
} }
[/gdscript] [/gdscript]
[csharp] [csharp]
// This is a valid dictionary. // This is a valid dictionary.
// To access the string "Nested value" below, use `((Godot.Collections.Dictionary)myDict["sub_dict"])["sub_key"]`. // To access the string "Nested value" below, use `((Godot.Collections.Dictionary)myDict["sub_dict"])["sub_key"]`.
var myDict = new Godot.Collections.Dictionary { var myDict = new Godot.Collections.Dictionary {
{"String Key", 5}, {"String Key", 5},
{4, new Godot.Collections.Array{1,2,3}}, {4, new Godot.Collections.Array{1,2,3}},
{7, "Hello"}, {7, "Hello"},
{"sub_dict", new Godot.Collections.Dictionary{{"sub_key", "Nested value"}}} {"sub_dict", new Godot.Collections.Dictionary{{"sub_key", "Nested value"}}}
}; };
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -123,13 +123,13 @@
[gdscript] [gdscript]
var groceries = {"Orange": 20, "Apple": 2, "Banana": 4} var groceries = {"Orange": 20, "Apple": 2, "Banana": 4}
for fruit in groceries: for fruit in groceries:
var amount = groceries[fruit] var amount = groceries[fruit]
[/gdscript] [/gdscript]
[csharp] [csharp]
var groceries = new Godot.Collections.Dictionary{{"Orange", 20}, {"Apple", 2}, {"Banana", 4}}; var groceries = new Godot.Collections.Dictionary{{"Orange", 20}, {"Apple", 2}, {"Banana", 4}};
foreach (var (fruit, amount) in groceries) foreach (var (fruit, amount) in groceries)
{ {
// `fruit` is the key, `amount` is the value. // `fruit` is the key, `amount` is the value.
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -276,8 +276,8 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
var my_dict = { var my_dict = {
"Godot" : 4, "Godot" : 4,
210 : null, 210 : null,
} }
print(my_dict.has("Godot")) # Prints true print(my_dict.has("Godot")) # Prints true
@ -287,8 +287,8 @@
[csharp] [csharp]
var myDict = new Godot.Collections.Dictionary var myDict = new Godot.Collections.Dictionary
{ {
{ "Godot", 4 }, { "Godot", 4 },
{ 210, default }, { 210, default },
}; };
GD.Print(myDict.ContainsKey("Godot")); // Prints True GD.Print(myDict.ContainsKey("Godot")); // Prints True
@ -299,7 +299,7 @@
In GDScript, this is equivalent to the [code]in[/code] operator: In GDScript, this is equivalent to the [code]in[/code] operator:
[codeblock] [codeblock]
if "Godot" in {"Godot": 4}: if "Godot" in {"Godot": 4}:
print("The key is here!") # Will be printed. print("The key is here!") # Will be printed.
[/codeblock] [/codeblock]
[b]Note:[/b] This method returns [code]true[/code] as long as the [param key] exists, even if its corresponding value is [code]null[/code]. [b]Note:[/b] This method returns [code]true[/code] as long as the [param key] exists, even if its corresponding value is [code]null[/code].
</description> </description>
@ -423,14 +423,14 @@
[csharp] [csharp]
var dict = new Godot.Collections.Dictionary var dict = new Godot.Collections.Dictionary
{ {
["item"] = "sword", ["item"] = "sword",
["quantity"] = 2, ["quantity"] = 2,
}; };
var otherDict = new Godot.Collections.Dictionary var otherDict = new Godot.Collections.Dictionary
{ {
["quantity"] = 15, ["quantity"] = 15,
["color"] = "silver", ["color"] = "silver",
}; };
// Overwriting of existing keys is disabled by default. // Overwriting of existing keys is disabled by default.

View File

@ -19,44 +19,44 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func dir_contents(path): func dir_contents(path):
var dir = DirAccess.open(path) var dir = DirAccess.open(path)
if dir: if dir:
dir.list_dir_begin() dir.list_dir_begin()
var file_name = dir.get_next() var file_name = dir.get_next()
while file_name != "": while file_name != "":
if dir.current_is_dir(): if dir.current_is_dir():
print("Found directory: " + file_name) print("Found directory: " + file_name)
else: else:
print("Found file: " + file_name) print("Found file: " + file_name)
file_name = dir.get_next() file_name = dir.get_next()
else: else:
print("An error occurred when trying to access the path.") print("An error occurred when trying to access the path.")
[/gdscript] [/gdscript]
[csharp] [csharp]
public void DirContents(string path) public void DirContents(string path)
{ {
using var dir = DirAccess.Open(path); using var dir = DirAccess.Open(path);
if (dir != null) if (dir != null)
{ {
dir.ListDirBegin(); dir.ListDirBegin();
string fileName = dir.GetNext(); string fileName = dir.GetNext();
while (fileName != "") while (fileName != "")
{ {
if (dir.CurrentIsDir()) if (dir.CurrentIsDir())
{ {
GD.Print($"Found directory: {fileName}"); GD.Print($"Found directory: {fileName}");
} }
else else
{ {
GD.Print($"Found file: {fileName}"); GD.Print($"Found file: {fileName}");
} }
fileName = dir.GetNext(); fileName = dir.GetNext();
} }
} }
else else
{ {
GD.Print("An error occurred when trying to access the path."); GD.Print("An error occurred when trying to access the path.");
} }
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -1783,7 +1783,7 @@
[codeblock] [codeblock]
var refresh_rate = DisplayServer.screen_get_refresh_rate() var refresh_rate = DisplayServer.screen_get_refresh_rate()
if refresh_rate &lt; 0: if refresh_rate &lt; 0:
refresh_rate = 60.0 refresh_rate = 60.0
[/codeblock] [/codeblock]
[b]Note:[/b] One of the following constants can be used as [param screen]: [constant SCREEN_OF_MAIN_WINDOW], [constant SCREEN_PRIMARY], [constant SCREEN_WITH_MOUSE_FOCUS], or [constant SCREEN_WITH_KEYBOARD_FOCUS]. [b]Note:[/b] One of the following constants can be used as [param screen]: [constant SCREEN_OF_MAIN_WINDOW], [constant SCREEN_PRIMARY], [constant SCREEN_WITH_MOUSE_FOCUS], or [constant SCREEN_WITH_KEYBOARD_FOCUS].
[b]Note:[/b] This method is implemented on Android, iOS, macOS, Linux (X11 and Wayland), and Windows. On other platforms, this method always returns [code]-1.0[/code]. [b]Note:[/b] This method is implemented on Android, iOS, macOS, Linux (X11 and Wayland), and Windows. On other platforms, this method always returns [code]-1.0[/code].

View File

@ -26,7 +26,7 @@
Add custom option to the context menu of the plugin's specified slot. When the option is activated, [param callback] will be called. Callback should take single [Array] argument; array contents depend on context menu slot. Add custom option to the context menu of the plugin's specified slot. When the option is activated, [param callback] will be called. Callback should take single [Array] argument; array contents depend on context menu slot.
[codeblock] [codeblock]
func _popup_menu(paths): func _popup_menu(paths):
add_context_menu_item("File Custom options", handle, ICON) add_context_menu_item("File Custom options", handle, ICON)
[/codeblock] [/codeblock]
If you want to assign shortcut to the menu item, use [method add_context_menu_item_from_shortcut] instead. If you want to assign shortcut to the menu item, use [method add_context_menu_item_from_shortcut] instead.
</description> </description>
@ -40,10 +40,10 @@
Add custom option to the context menu of the plugin's specified slot. The option will have the [param shortcut] assigned and reuse its callback. The shortcut has to be registered beforehand with [method add_menu_shortcut]. Add custom option to the context menu of the plugin's specified slot. The option will have the [param shortcut] assigned and reuse its callback. The shortcut has to be registered beforehand with [method add_menu_shortcut].
[codeblock] [codeblock]
func _init(): func _init():
add_menu_shortcut(SHORTCUT, handle) add_menu_shortcut(SHORTCUT, handle)
func _popup_menu(paths): func _popup_menu(paths):
add_context_menu_item_from_shortcut("File Custom options", SHORTCUT, ICON) add_context_menu_item_from_shortcut("File Custom options", SHORTCUT, ICON)
[/codeblock] [/codeblock]
</description> </description>
</method> </method>
@ -56,12 +56,12 @@
Add a submenu to the context menu of the plugin's specified slot. The submenu is not automatically handled, you need to connect to its signals yourself. Also the submenu is freed on every popup, so provide a new [PopupMenu] every time. Add a submenu to the context menu of the plugin's specified slot. The submenu is not automatically handled, you need to connect to its signals yourself. Also the submenu is freed on every popup, so provide a new [PopupMenu] every time.
[codeblock] [codeblock]
func _popup_menu(paths): func _popup_menu(paths):
var popup_menu = PopupMenu.new() var popup_menu = PopupMenu.new()
popup_menu.add_item("Blue") popup_menu.add_item("Blue")
popup_menu.add_item("White") popup_menu.add_item("White")
popup_menu.id_pressed.connect(_on_color_submenu_option) popup_menu.id_pressed.connect(_on_color_submenu_option)
add_context_submenu_item("Set Node Color", popup_menu) add_context_submenu_item("Set Node Color", popup_menu)
[/codeblock] [/codeblock]
</description> </description>
</method> </method>
@ -73,7 +73,7 @@
Registers a shortcut associated with the plugin's context menu. This method should be called once (e.g. in plugin's [method Object._init]). [param callback] will be called when user presses the specified [param shortcut] while the menu's context is in effect (e.g. FileSystem dock is focused). Callback should take single [Array] argument; array contents depend on context menu slot. Registers a shortcut associated with the plugin's context menu. This method should be called once (e.g. in plugin's [method Object._init]). [param callback] will be called when user presses the specified [param shortcut] while the menu's context is in effect (e.g. FileSystem dock is focused). Callback should take single [Array] argument; array contents depend on context menu slot.
[codeblock] [codeblock]
func _init(): func _init():
add_menu_shortcut(SHORTCUT, handle) add_menu_shortcut(SHORTCUT, handle)
[/codeblock] [/codeblock]
</description> </description>
</method> </method>
@ -95,7 +95,7 @@
Context menu of Script editor's code editor. [method _popup_menu] will be called with the path to the [CodeEdit] node. You can fetch it using this code: Context menu of Script editor's code editor. [method _popup_menu] will be called with the path to the [CodeEdit] node. You can fetch it using this code:
[codeblock] [codeblock]
func _popup_menu(paths): func _popup_menu(paths):
var code_edit = Engine.get_main_loop().root.get_node(paths[0]); var code_edit = Engine.get_main_loop().root.get_node(paths[0]);
[/codeblock] [/codeblock]
The option callback will receive reference to that node. You can use [CodeEdit] methods to perform symbol lookups etc. The option callback will receive reference to that node. You can use [CodeEdit] methods to perform symbol lookups etc.
</constant> </constant>
@ -106,7 +106,7 @@
Context menu of 2D editor's basic right-click menu. [method _popup_menu] will be called with paths to all [CanvasItem] nodes under the cursor. You can fetch them using this code: Context menu of 2D editor's basic right-click menu. [method _popup_menu] will be called with paths to all [CanvasItem] nodes under the cursor. You can fetch them using this code:
[codeblock] [codeblock]
func _popup_menu(paths): func _popup_menu(paths):
var canvas_item = Engine.get_main_loop().root.get_node(paths[0]); # Replace 0 with the desired index. var canvas_item = Engine.get_main_loop().root.get_node(paths[0]); # Replace 0 with the desired index.
[/codeblock] [/codeblock]
The paths array is empty if there weren't any nodes under cursor. The option callback will receive a typed array of [CanvasItem] nodes. The paths array is empty if there weren't any nodes under cursor. The option callback will receive a typed array of [CanvasItem] nodes.
</constant> </constant>

View File

@ -15,34 +15,34 @@
class ExampleEditorDebugger extends EditorDebuggerPlugin: class ExampleEditorDebugger extends EditorDebuggerPlugin:
func _has_capture(capture): func _has_capture(capture):
# Return true if you wish to handle messages with the prefix "my_plugin:". # Return true if you wish to handle messages with the prefix "my_plugin:".
return capture == "my_plugin" return capture == "my_plugin"
func _capture(message, data, session_id): func _capture(message, data, session_id):
if message == "my_plugin:ping": if message == "my_plugin:ping":
get_session(session_id).send_message("my_plugin:echo", data) get_session(session_id).send_message("my_plugin:echo", data)
return true return true
return false return false
func _setup_session(session_id): func _setup_session(session_id):
# Add a new tab in the debugger session UI containing a label. # Add a new tab in the debugger session UI containing a label.
var label = Label.new() var label = Label.new()
label.name = "Example plugin" # Will be used as the tab title. label.name = "Example plugin" # Will be used as the tab title.
label.text = "Example plugin" label.text = "Example plugin"
var session = get_session(session_id) var session = get_session(session_id)
# Listens to the session started and stopped signals. # Listens to the session started and stopped signals.
session.started.connect(func (): print("Session started")) session.started.connect(func (): print("Session started"))
session.stopped.connect(func (): print("Session stopped")) session.stopped.connect(func (): print("Session stopped"))
session.add_session_tab(label) session.add_session_tab(label)
var debugger = ExampleEditorDebugger.new() var debugger = ExampleEditorDebugger.new()
func _enter_tree(): func _enter_tree():
add_debugger_plugin(debugger) add_debugger_plugin(debugger)
func _exit_tree(): func _exit_tree():
remove_debugger_plugin(debugger) remove_debugger_plugin(debugger)
[/gdscript] [/gdscript]
[/codeblocks] [/codeblocks]
To connect on the running game side, use the [EngineDebugger] singleton: To connect on the running game side, use the [EngineDebugger] singleton:
@ -51,15 +51,15 @@
extends Node extends Node
func _ready(): func _ready():
EngineDebugger.register_message_capture("my_plugin", _capture) EngineDebugger.register_message_capture("my_plugin", _capture)
EngineDebugger.send_message("my_plugin:ping", ["test"]) EngineDebugger.send_message("my_plugin:ping", ["test"])
func _capture(message, data): func _capture(message, data):
# Note that the "my_plugin:" prefix is not used here. # Note that the "my_plugin:" prefix is not used here.
if message == "echo": if message == "echo":
prints("Echo received:", data) prints("Echo received:", data)
return true return true
return false return false
[/gdscript] [/gdscript]
[/codeblocks] [/codeblocks]
[b]Note:[/b] While the game is running, [method @GlobalScope.print] and similar functions [i]called in the editor[/i] do not print anything, the Output Log prints only game messages. [b]Note:[/b] While the game is running, [method @GlobalScope.print] and similar functions [i]called in the editor[/i] do not print anything, the Output Log prints only game messages.

View File

@ -202,20 +202,20 @@
Return a [Dictionary] of override values for export options, that will be used instead of user-provided values. Overridden options will be hidden from the user interface. Return a [Dictionary] of override values for export options, that will be used instead of user-provided values. Overridden options will be hidden from the user interface.
[codeblock] [codeblock]
class MyExportPlugin extends EditorExportPlugin: class MyExportPlugin extends EditorExportPlugin:
func _get_name() -&gt; String: func _get_name() -&gt; String:
return "MyExportPlugin" return "MyExportPlugin"
func _supports_platform(platform) -&gt; bool: func _supports_platform(platform) -&gt; bool:
if platform is EditorExportPlatformPC: if platform is EditorExportPlatformPC:
# Run on all desktop platforms including Windows, MacOS and Linux. # Run on all desktop platforms including Windows, MacOS and Linux.
return true return true
return false return false
func _get_export_options_overrides(platform) -&gt; Dictionary: func _get_export_options_overrides(platform) -&gt; Dictionary:
# Override "Embed PCK" to always be enabled. # Override "Embed PCK" to always be enabled.
return { return {
"binary_format/embed_pck": true, "binary_format/embed_pck": true,
} }
[/codeblock] [/codeblock]
</description> </description>
</method> </method>

View File

@ -13,104 +13,104 @@
extends EditorImportPlugin extends EditorImportPlugin
func _get_importer_name(): func _get_importer_name():
return "my.special.plugin" return "my.special.plugin"
func _get_visible_name(): func _get_visible_name():
return "Special Mesh" return "Special Mesh"
func _get_recognized_extensions(): func _get_recognized_extensions():
return ["special", "spec"] return ["special", "spec"]
func _get_save_extension(): func _get_save_extension():
return "mesh" return "mesh"
func _get_resource_type(): func _get_resource_type():
return "Mesh" return "Mesh"
func _get_preset_count(): func _get_preset_count():
return 1 return 1
func _get_preset_name(preset_index): func _get_preset_name(preset_index):
return "Default" return "Default"
func _get_import_options(path, preset_index): func _get_import_options(path, preset_index):
return [{"name": "my_option", "default_value": false}] return [{"name": "my_option", "default_value": false}]
func _import(source_file, save_path, options, platform_variants, gen_files): func _import(source_file, save_path, options, platform_variants, gen_files):
var file = FileAccess.open(source_file, FileAccess.READ) var file = FileAccess.open(source_file, FileAccess.READ)
if file == null: if file == null:
return FAILED return FAILED
var mesh = ArrayMesh.new() var mesh = ArrayMesh.new()
# Fill the Mesh with data read in "file", left as an exercise to the reader. # Fill the Mesh with data read in "file", left as an exercise to the reader.
var filename = save_path + "." + _get_save_extension() var filename = save_path + "." + _get_save_extension()
return ResourceSaver.save(mesh, filename) return ResourceSaver.save(mesh, filename)
[/gdscript] [/gdscript]
[csharp] [csharp]
using Godot; using Godot;
public partial class MySpecialPlugin : EditorImportPlugin public partial class MySpecialPlugin : EditorImportPlugin
{ {
public override string _GetImporterName() public override string _GetImporterName()
{ {
return "my.special.plugin"; return "my.special.plugin";
} }
public override string _GetVisibleName() public override string _GetVisibleName()
{ {
return "Special Mesh"; return "Special Mesh";
} }
public override string[] _GetRecognizedExtensions() public override string[] _GetRecognizedExtensions()
{ {
return ["special", "spec"]; return ["special", "spec"];
} }
public override string _GetSaveExtension() public override string _GetSaveExtension()
{ {
return "mesh"; return "mesh";
} }
public override string _GetResourceType() public override string _GetResourceType()
{ {
return "Mesh"; return "Mesh";
} }
public override int _GetPresetCount() public override int _GetPresetCount()
{ {
return 1; return 1;
} }
public override string _GetPresetName(int presetIndex) public override string _GetPresetName(int presetIndex)
{ {
return "Default"; return "Default";
} }
public override Godot.Collections.Array&lt;Godot.Collections.Dictionary&gt; _GetImportOptions(string path, int presetIndex) public override Godot.Collections.Array&lt;Godot.Collections.Dictionary&gt; _GetImportOptions(string path, int presetIndex)
{ {
return return
[ [
new Godot.Collections.Dictionary new Godot.Collections.Dictionary
{ {
{ "name", "myOption" }, { "name", "myOption" },
{ "default_value", false }, { "default_value", false },
}, },
]; ];
} }
public override Error _Import(string sourceFile, string savePath, Godot.Collections.Dictionary options, Godot.Collections.Array&lt;string&gt; platformVariants, Godot.Collections.Array&lt;string&gt; genFiles) public override Error _Import(string sourceFile, string savePath, Godot.Collections.Dictionary options, Godot.Collections.Array&lt;string&gt; platformVariants, Godot.Collections.Array&lt;string&gt; genFiles)
{ {
using var file = FileAccess.Open(sourceFile, FileAccess.ModeFlags.Read); using var file = FileAccess.Open(sourceFile, FileAccess.ModeFlags.Read);
if (file.GetError() != Error.Ok) if (file.GetError() != Error.Ok)
{ {
return Error.Failed; return Error.Failed;
} }
var mesh = new ArrayMesh(); var mesh = new ArrayMesh();
// Fill the Mesh with data read in "file", left as an exercise to the reader. // Fill the Mesh with data read in "file", left as an exercise to the reader.
string filename = $"{savePath}.{_GetSaveExtension()}"; string filename = $"{savePath}.{_GetSaveExtension()}";
return ResourceSaver.Save(mesh, filename); return ResourceSaver.Save(mesh, filename);
} }
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -164,22 +164,22 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _get_option_visibility(option, options): func _get_option_visibility(option, options):
# Only show the lossy quality setting if the compression mode is set to "Lossy". # Only show the lossy quality setting if the compression mode is set to "Lossy".
if option == "compress/lossy_quality" and options.has("compress/mode"): if option == "compress/lossy_quality" and options.has("compress/mode"):
return int(options["compress/mode"]) == COMPRESS_LOSSY # This is a constant that you set return int(options["compress/mode"]) == COMPRESS_LOSSY # This is a constant that you set
return true return true
[/gdscript] [/gdscript]
[csharp] [csharp]
public void _GetOptionVisibility(string option, Godot.Collections.Dictionary options) public void _GetOptionVisibility(string option, Godot.Collections.Dictionary options)
{ {
// Only show the lossy quality setting if the compression mode is set to "Lossy". // Only show the lossy quality setting if the compression mode is set to "Lossy".
if (option == "compress/lossy_quality" &amp;&amp; options.ContainsKey("compress/mode")) if (option == "compress/lossy_quality" &amp;&amp; options.ContainsKey("compress/mode"))
{ {
return (int)options["compress/mode"] == CompressLossy; // This is a constant you set return (int)options["compress/mode"] == CompressLossy; // This is a constant you set
} }
return true; return true;
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -356,14 +356,14 @@
[b]Example:[/b] Display the node selection dialog as soon as this node is added to the tree for the first time: [b]Example:[/b] Display the node selection dialog as soon as this node is added to the tree for the first time:
[codeblock] [codeblock]
func _ready(): func _ready():
if Engine.is_editor_hint(): if Engine.is_editor_hint():
EditorInterface.popup_node_selector(_on_node_selected, ["Button"]) EditorInterface.popup_node_selector(_on_node_selected, ["Button"])
func _on_node_selected(node_path): func _on_node_selected(node_path):
if node_path.is_empty(): if node_path.is_empty():
print("node selection canceled") print("node selection canceled")
else: else:
print("selected ", node_path) print("selected ", node_path)
[/codeblock] [/codeblock]
</description> </description>
</method> </method>
@ -377,14 +377,14 @@
Pops up an editor dialog for selecting properties from [param object]. The [param callback] must take a single argument of type [NodePath]. It is called on the selected property path (see [method NodePath.get_as_property_path]) or the empty path [code]^""[/code] if the dialog is canceled. If [param type_filter] is provided, the dialog will only show properties that match one of the listed [enum Variant.Type] values. If [param current_value] is provided, the property will be selected automatically in the property list, if it exists. Pops up an editor dialog for selecting properties from [param object]. The [param callback] must take a single argument of type [NodePath]. It is called on the selected property path (see [method NodePath.get_as_property_path]) or the empty path [code]^""[/code] if the dialog is canceled. If [param type_filter] is provided, the dialog will only show properties that match one of the listed [enum Variant.Type] values. If [param current_value] is provided, the property will be selected automatically in the property list, if it exists.
[codeblock] [codeblock]
func _ready(): func _ready():
if Engine.is_editor_hint(): if Engine.is_editor_hint():
EditorInterface.popup_property_selector(this, _on_property_selected, [TYPE_INT]) EditorInterface.popup_property_selector(this, _on_property_selected, [TYPE_INT])
func _on_property_selected(property_path): func _on_property_selected(property_path):
if property_path.is_empty(): if property_path.is_empty():
print("property selection canceled") print("property selection canceled")
else: else:
print("selected ", property_path) print("selected ", property_path)
[/codeblock] [/codeblock]
</description> </description>
</method> </method>

View File

@ -59,32 +59,32 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _forward_3d_draw_over_viewport(overlay): func _forward_3d_draw_over_viewport(overlay):
# Draw a circle at the cursor's position. # Draw a circle at the cursor's position.
overlay.draw_circle(overlay.get_local_mouse_position(), 64, Color.WHITE) overlay.draw_circle(overlay.get_local_mouse_position(), 64, Color.WHITE)
func _forward_3d_gui_input(camera, event): func _forward_3d_gui_input(camera, event):
if event is InputEventMouseMotion: if event is InputEventMouseMotion:
# Redraw the viewport when the cursor is moved. # Redraw the viewport when the cursor is moved.
update_overlays() update_overlays()
return EditorPlugin.AFTER_GUI_INPUT_STOP return EditorPlugin.AFTER_GUI_INPUT_STOP
return EditorPlugin.AFTER_GUI_INPUT_PASS return EditorPlugin.AFTER_GUI_INPUT_PASS
[/gdscript] [/gdscript]
[csharp] [csharp]
public override void _Forward3DDrawOverViewport(Control viewportControl) public override void _Forward3DDrawOverViewport(Control viewportControl)
{ {
// Draw a circle at the cursor's position. // Draw a circle at the cursor's position.
viewportControl.DrawCircle(viewportControl.GetLocalMousePosition(), 64, Colors.White); viewportControl.DrawCircle(viewportControl.GetLocalMousePosition(), 64, Colors.White);
} }
public override EditorPlugin.AfterGuiInput _Forward3DGuiInput(Camera3D viewportCamera, InputEvent @event) public override EditorPlugin.AfterGuiInput _Forward3DGuiInput(Camera3D viewportCamera, InputEvent @event)
{ {
if (@event is InputEventMouseMotion) if (@event is InputEventMouseMotion)
{ {
// Redraw the viewport when the cursor is moved. // Redraw the viewport when the cursor is moved.
UpdateOverlays(); UpdateOverlays();
return EditorPlugin.AfterGuiInput.Stop; return EditorPlugin.AfterGuiInput.Stop;
} }
return EditorPlugin.AfterGuiInput.Pass; return EditorPlugin.AfterGuiInput.Pass;
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -108,13 +108,13 @@
[gdscript] [gdscript]
# Prevents the InputEvent from reaching other Editor classes. # Prevents the InputEvent from reaching other Editor classes.
func _forward_3d_gui_input(camera, event): func _forward_3d_gui_input(camera, event):
return EditorPlugin.AFTER_GUI_INPUT_STOP return EditorPlugin.AFTER_GUI_INPUT_STOP
[/gdscript] [/gdscript]
[csharp] [csharp]
// Prevents the InputEvent from reaching other Editor classes. // Prevents the InputEvent from reaching other Editor classes.
public override EditorPlugin.AfterGuiInput _Forward3DGuiInput(Camera3D camera, InputEvent @event) public override EditorPlugin.AfterGuiInput _Forward3DGuiInput(Camera3D camera, InputEvent @event)
{ {
return EditorPlugin.AfterGuiInput.Stop; return EditorPlugin.AfterGuiInput.Stop;
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -123,13 +123,13 @@
[gdscript] [gdscript]
# Consumes InputEventMouseMotion and forwards other InputEvent types. # Consumes InputEventMouseMotion and forwards other InputEvent types.
func _forward_3d_gui_input(camera, event): func _forward_3d_gui_input(camera, event):
return EditorPlugin.AFTER_GUI_INPUT_STOP if event is InputEventMouseMotion else EditorPlugin.AFTER_GUI_INPUT_PASS return EditorPlugin.AFTER_GUI_INPUT_STOP if event is InputEventMouseMotion else EditorPlugin.AFTER_GUI_INPUT_PASS
[/gdscript] [/gdscript]
[csharp] [csharp]
// Consumes InputEventMouseMotion and forwards other InputEvent types. // Consumes InputEventMouseMotion and forwards other InputEvent types.
public override EditorPlugin.AfterGuiInput _Forward3DGuiInput(Camera3D camera, InputEvent @event) public override EditorPlugin.AfterGuiInput _Forward3DGuiInput(Camera3D camera, InputEvent @event)
{ {
return @event is InputEventMouseMotion ? EditorPlugin.AfterGuiInput.Stop : EditorPlugin.AfterGuiInput.Pass; return @event is InputEventMouseMotion ? EditorPlugin.AfterGuiInput.Stop : EditorPlugin.AfterGuiInput.Pass;
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -143,32 +143,32 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _forward_canvas_draw_over_viewport(overlay): func _forward_canvas_draw_over_viewport(overlay):
# Draw a circle at the cursor's position. # Draw a circle at the cursor's position.
overlay.draw_circle(overlay.get_local_mouse_position(), 64, Color.WHITE) overlay.draw_circle(overlay.get_local_mouse_position(), 64, Color.WHITE)
func _forward_canvas_gui_input(event): func _forward_canvas_gui_input(event):
if event is InputEventMouseMotion: if event is InputEventMouseMotion:
# Redraw the viewport when the cursor is moved. # Redraw the viewport when the cursor is moved.
update_overlays() update_overlays()
return true return true
return false return false
[/gdscript] [/gdscript]
[csharp] [csharp]
public override void _ForwardCanvasDrawOverViewport(Control viewportControl) public override void _ForwardCanvasDrawOverViewport(Control viewportControl)
{ {
// Draw a circle at the cursor's position. // Draw a circle at the cursor's position.
viewportControl.DrawCircle(viewportControl.GetLocalMousePosition(), 64, Colors.White); viewportControl.DrawCircle(viewportControl.GetLocalMousePosition(), 64, Colors.White);
} }
public override bool _ForwardCanvasGuiInput(InputEvent @event) public override bool _ForwardCanvasGuiInput(InputEvent @event)
{ {
if (@event is InputEventMouseMotion) if (@event is InputEventMouseMotion)
{ {
// Redraw the viewport when the cursor is moved. // Redraw the viewport when the cursor is moved.
UpdateOverlays(); UpdateOverlays();
return true; return true;
} }
return false; return false;
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -191,13 +191,13 @@
[gdscript] [gdscript]
# Prevents the InputEvent from reaching other Editor classes. # Prevents the InputEvent from reaching other Editor classes.
func _forward_canvas_gui_input(event): func _forward_canvas_gui_input(event):
return true return true
[/gdscript] [/gdscript]
[csharp] [csharp]
// Prevents the InputEvent from reaching other Editor classes. // Prevents the InputEvent from reaching other Editor classes.
public override bool ForwardCanvasGuiInput(InputEvent @event) public override bool ForwardCanvasGuiInput(InputEvent @event)
{ {
return true; return true;
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -206,19 +206,19 @@
[gdscript] [gdscript]
# Consumes InputEventMouseMotion and forwards other InputEvent types. # Consumes InputEventMouseMotion and forwards other InputEvent types.
func _forward_canvas_gui_input(event): func _forward_canvas_gui_input(event):
if (event is InputEventMouseMotion): if (event is InputEventMouseMotion):
return true return true
return false return false
[/gdscript] [/gdscript]
[csharp] [csharp]
// Consumes InputEventMouseMotion and forwards other InputEvent types. // Consumes InputEventMouseMotion and forwards other InputEvent types.
public override bool _ForwardCanvasGuiInput(InputEvent @event) public override bool _ForwardCanvasGuiInput(InputEvent @event)
{ {
if (@event is InputEventMouseMotion) if (@event is InputEventMouseMotion)
{ {
return true; return true;
} }
return false; return false;
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -239,18 +239,18 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _get_plugin_icon(): func _get_plugin_icon():
# You can use a custom icon: # You can use a custom icon:
return preload("res://addons/my_plugin/my_plugin_icon.svg") return preload("res://addons/my_plugin/my_plugin_icon.svg")
# Or use a built-in icon: # Or use a built-in icon:
return EditorInterface.get_editor_theme().get_icon("Node", "EditorIcons") return EditorInterface.get_editor_theme().get_icon("Node", "EditorIcons")
[/gdscript] [/gdscript]
[csharp] [csharp]
public override Texture2D _GetPluginIcon() public override Texture2D _GetPluginIcon()
{ {
// You can use a custom icon: // You can use a custom icon:
return ResourceLoader.Load&lt;Texture2D&gt;("res://addons/my_plugin/my_plugin_icon.svg"); return ResourceLoader.Load&lt;Texture2D&gt;("res://addons/my_plugin/my_plugin_icon.svg");
// Or use a built-in icon: // Or use a built-in icon:
return EditorInterface.Singleton.GetEditorTheme().GetIcon("Node", "EditorIcons"); return EditorInterface.Singleton.GetEditorTheme().GetIcon("Node", "EditorIcons");
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -272,8 +272,8 @@
[b]Note:[/b] You must implement [method _get_plugin_name] for the state to be stored and restored correctly. [b]Note:[/b] You must implement [method _get_plugin_name] for the state to be stored and restored correctly.
[codeblock] [codeblock]
func _get_state(): func _get_state():
var state = {"zoom": zoom, "preferred_color": my_color} var state = {"zoom": zoom, "preferred_color": my_color}
return state return state
[/codeblock] [/codeblock]
</description> </description>
</method> </method>
@ -286,22 +286,22 @@
If the user confirms saving, [method _save_external_data] will be called, before closing the editor. If the user confirms saving, [method _save_external_data] will be called, before closing the editor.
[codeblock] [codeblock]
func _get_unsaved_status(for_scene): func _get_unsaved_status(for_scene):
if not unsaved: if not unsaved:
return "" return ""
if for_scene.is_empty(): if for_scene.is_empty():
return "Save changes in MyCustomPlugin before closing?" return "Save changes in MyCustomPlugin before closing?"
else: else:
return "Scene %s has changes from MyCustomPlugin. Save before closing?" % for_scene.get_file() return "Scene %s has changes from MyCustomPlugin. Save before closing?" % for_scene.get_file()
func _save_external_data(): func _save_external_data():
unsaved = false unsaved = false
[/codeblock] [/codeblock]
If the plugin has no scene-specific changes, you can ignore the calls when closing scenes: If the plugin has no scene-specific changes, you can ignore the calls when closing scenes:
[codeblock] [codeblock]
func _get_unsaved_status(for_scene): func _get_unsaved_status(for_scene):
if not for_scene.is_empty(): if not for_scene.is_empty():
return "" return ""
[/codeblock] [/codeblock]
</description> </description>
</method> </method>
@ -313,8 +313,8 @@
Use [method _set_window_layout] to restore your saved layout. Use [method _set_window_layout] to restore your saved layout.
[codeblock] [codeblock]
func _get_window_layout(configuration): func _get_window_layout(configuration):
configuration.set_value("MyPlugin", "window_position", $Window.position) configuration.set_value("MyPlugin", "window_position", $Window.position)
configuration.set_value("MyPlugin", "icon_color", $Icon.modulate) configuration.set_value("MyPlugin", "icon_color", $Icon.modulate)
[/codeblock] [/codeblock]
</description> </description>
</method> </method>
@ -336,21 +336,21 @@
var plugin_control var plugin_control
func _enter_tree(): func _enter_tree():
plugin_control = preload("my_plugin_control.tscn").instantiate() plugin_control = preload("my_plugin_control.tscn").instantiate()
EditorInterface.get_editor_main_screen().add_child(plugin_control) EditorInterface.get_editor_main_screen().add_child(plugin_control)
plugin_control.hide() plugin_control.hide()
func _has_main_screen(): func _has_main_screen():
return true return true
func _make_visible(visible): func _make_visible(visible):
plugin_control.visible = visible plugin_control.visible = visible
func _get_plugin_name(): func _get_plugin_name():
return "My Super Cool Plugin 3000" return "My Super Cool Plugin 3000"
func _get_plugin_icon(): func _get_plugin_icon():
return EditorInterface.get_editor_theme().get_icon("Node", "EditorIcons") return EditorInterface.get_editor_theme().get_icon("Node", "EditorIcons")
[/codeblock] [/codeblock]
</description> </description>
</method> </method>
@ -376,8 +376,8 @@
[b]Note:[/b] Your plugin must implement [method _get_plugin_name], otherwise it will not be recognized and this method will not be called. [b]Note:[/b] Your plugin must implement [method _get_plugin_name], otherwise it will not be recognized and this method will not be called.
[codeblock] [codeblock]
func _set_state(data): func _set_state(data):
zoom = data.get("zoom", 1.0) zoom = data.get("zoom", 1.0)
preferred_color = data.get("my_color", Color.WHITE) preferred_color = data.get("my_color", Color.WHITE)
[/codeblock] [/codeblock]
</description> </description>
</method> </method>
@ -388,8 +388,8 @@
Restore the plugin GUI layout and data saved by [method _get_window_layout]. This method is called for every plugin on editor startup. Use the provided [param configuration] file to read your saved data. Restore the plugin GUI layout and data saved by [method _get_window_layout]. This method is called for every plugin on editor startup. Use the provided [param configuration] file to read your saved data.
[codeblock] [codeblock]
func _set_window_layout(configuration): func _set_window_layout(configuration):
$Window.position = configuration.get_value("MyPlugin", "window_position", Vector2()) $Window.position = configuration.get_value("MyPlugin", "window_position", Vector2())
$Icon.modulate = configuration.get_value("MyPlugin", "icon_color", Color.WHITE) $Icon.modulate = configuration.get_value("MyPlugin", "icon_color", Color.WHITE)
[/codeblock] [/codeblock]
</description> </description>
</method> </method>
@ -502,10 +502,10 @@
var inspector_plugin = MyInspectorPlugin.new() var inspector_plugin = MyInspectorPlugin.new()
func _enter_tree(): func _enter_tree():
add_inspector_plugin(inspector_plugin) add_inspector_plugin(inspector_plugin)
func _exit_tree(): func _exit_tree():
remove_inspector_plugin(inspector_plugin) remove_inspector_plugin(inspector_plugin)
[/gdscript] [/gdscript]
[/codeblocks] [/codeblocks]
</description> </description>

View File

@ -11,15 +11,15 @@
extends EditorResourceConversionPlugin extends EditorResourceConversionPlugin
func _handles(resource: Resource): func _handles(resource: Resource):
return resource is ImageTexture return resource is ImageTexture
func _converts_to(): func _converts_to():
return "PortableCompressedTexture2D" return "PortableCompressedTexture2D"
func _convert(itex: Resource): func _convert(itex: Resource):
var ptex = PortableCompressedTexture2D.new() var ptex = PortableCompressedTexture2D.new()
ptex.create_from_image(itex.get_image(), PortableCompressedTexture2D.COMPRESSION_MODE_LOSSLESS) ptex.create_from_image(itex.get_image(), PortableCompressedTexture2D.COMPRESSION_MODE_LOSSLESS)
return ptex return ptex
[/gdscript] [/gdscript]
[/codeblocks] [/codeblocks]
To use an [EditorResourceConversionPlugin], register it using the [method EditorPlugin.add_resource_conversion_plugin] method first. To use an [EditorResourceConversionPlugin], register it using the [method EditorPlugin.add_resource_conversion_plugin] method first.

View File

@ -30,10 +30,10 @@
[b]Note:[/b] If you decide to discard the [param base], make sure to call [method Node.queue_free], because it's not freed automatically. [b]Note:[/b] If you decide to discard the [param base], make sure to call [method Node.queue_free], because it's not freed automatically.
[codeblock] [codeblock]
func _make_tooltip_for_path(path, metadata, base): func _make_tooltip_for_path(path, metadata, base):
var t_rect = TextureRect.new() var t_rect = TextureRect.new()
request_thumbnail(path, t_rect) request_thumbnail(path, t_rect)
base.add_child(t_rect) # The TextureRect will appear at the bottom of the tooltip. base.add_child(t_rect) # The TextureRect will appear at the bottom of the tooltip.
return base return base
[/codeblock] [/codeblock]
</description> </description>
</method> </method>

View File

@ -14,15 +14,15 @@
# This sample changes all node names. # This sample changes all node names.
# Called right after the scene is imported and gets the root node. # Called right after the scene is imported and gets the root node.
func _post_import(scene): func _post_import(scene):
# Change all node names to "modified_[oldnodename]" # Change all node names to "modified_[oldnodename]"
iterate(scene) iterate(scene)
return scene # Remember to return the imported scene return scene # Remember to return the imported scene
func iterate(node): func iterate(node):
if node != null: if node != null:
node.name = "modified_" + node.name node.name = "modified_" + node.name
for child in node.get_children(): for child in node.get_children():
iterate(child) iterate(child)
[/gdscript] [/gdscript]
[csharp] [csharp]
using Godot; using Godot;
@ -32,24 +32,24 @@
[Tool] [Tool]
public partial class NodeRenamer : EditorScenePostImport public partial class NodeRenamer : EditorScenePostImport
{ {
public override GodotObject _PostImport(Node scene) public override GodotObject _PostImport(Node scene)
{ {
// Change all node names to "modified_[oldnodename]" // Change all node names to "modified_[oldnodename]"
Iterate(scene); Iterate(scene);
return scene; // Remember to return the imported scene return scene; // Remember to return the imported scene
} }
public void Iterate(Node node) public void Iterate(Node node)
{ {
if (node != null) if (node != null)
{ {
node.Name = $"modified_{node.Name}"; node.Name = $"modified_{node.Name}";
foreach (Node child in node.GetChildren()) foreach (Node child in node.GetChildren())
{ {
Iterate(child); Iterate(child);
} }
} }
} }
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -14,7 +14,7 @@
extends EditorScript extends EditorScript
func _run(): func _run():
print("Hello from the Godot Editor!") print("Hello from the Godot Editor!")
[/gdscript] [/gdscript]
[csharp] [csharp]
using Godot; using Godot;
@ -22,10 +22,10 @@
[Tool] [Tool]
public partial class HelloEditor : EditorScript public partial class HelloEditor : EditorScript
{ {
public override void _Run() public override void _Run()
{ {
GD.Print("Hello from the Godot Editor!"); GD.Print("Hello from the Godot Editor!");
} }
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -44,10 +44,10 @@
settings.set("category/property_name", 0) settings.set("category/property_name", 0)
var property_info = { var property_info = {
"name": "category/property_name", "name": "category/property_name",
"type": TYPE_INT, "type": TYPE_INT,
"hint": PROPERTY_HINT_ENUM, "hint": PROPERTY_HINT_ENUM,
"hint_string": "one,two,three" "hint_string": "one,two,three"
} }
settings.add_property_info(property_info) settings.add_property_info(property_info)
@ -58,10 +58,10 @@
var propertyInfo = new Godot.Collections.Dictionary var propertyInfo = new Godot.Collections.Dictionary
{ {
{"name", "category/propertyName"}, {"name", "category/propertyName"},
{"type", Variant.Type.Int}, {"type", Variant.Type.Int},
{"hint", PropertyHint.Enum}, {"hint", PropertyHint.Enum},
{"hint_string", "one,two,three"} {"hint_string", "one,two,three"}
}; };
settings.AddPropertyInfo(propertyInfo); settings.AddPropertyInfo(propertyInfo);

View File

@ -14,18 +14,18 @@
extends EditorTranslationParserPlugin extends EditorTranslationParserPlugin
func _parse_file(path): func _parse_file(path):
var ret: Array[PackedStringArray] = [] var ret: Array[PackedStringArray] = []
var file = FileAccess.open(path, FileAccess.READ) var file = FileAccess.open(path, FileAccess.READ)
var text = file.get_as_text() var text = file.get_as_text()
var split_strs = text.split(",", false) var split_strs = text.split(",", false)
for s in split_strs: for s in split_strs:
ret.append(PackedStringArray([s])) ret.append(PackedStringArray([s]))
#print("Extracted string: " + s) #print("Extracted string: " + s)
return ret return ret
func _get_recognized_extensions(): func _get_recognized_extensions():
return ["csv"] return ["csv"]
[/gdscript] [/gdscript]
[csharp] [csharp]
using Godot; using Godot;
@ -33,24 +33,24 @@
[Tool] [Tool]
public partial class CustomParser : EditorTranslationParserPlugin public partial class CustomParser : EditorTranslationParserPlugin
{ {
public override Godot.Collections.Array&lt;string[]&gt; _ParseFile(string path) public override Godot.Collections.Array&lt;string[]&gt; _ParseFile(string path)
{ {
Godot.Collections.Array&lt;string[]&gt; ret; Godot.Collections.Array&lt;string[]&gt; ret;
using var file = FileAccess.Open(path, FileAccess.ModeFlags.Read); using var file = FileAccess.Open(path, FileAccess.ModeFlags.Read);
string text = file.GetAsText(); string text = file.GetAsText();
string[] splitStrs = text.Split(",", allowEmpty: false); string[] splitStrs = text.Split(",", allowEmpty: false);
foreach (string s in splitStrs) foreach (string s in splitStrs)
{ {
ret.Add([s]); ret.Add([s]);
//GD.Print($"Extracted string: {s}"); //GD.Print($"Extracted string: {s}");
} }
return ret; return ret;
} }
public override string[] _GetRecognizedExtensions() public override string[] _GetRecognizedExtensions()
{ {
return ["csv"]; return ["csv"];
} }
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -77,24 +77,24 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _parse_file(path): func _parse_file(path):
var res = ResourceLoader.load(path, "Script") var res = ResourceLoader.load(path, "Script")
var text = res.source_code var text = res.source_code
# Parsing logic. # Parsing logic.
func _get_recognized_extensions(): func _get_recognized_extensions():
return ["gd"] return ["gd"]
[/gdscript] [/gdscript]
[csharp] [csharp]
public override Godot.Collections.Array&lt;string[]&gt; _ParseFile(string path) public override Godot.Collections.Array&lt;string[]&gt; _ParseFile(string path)
{ {
var res = ResourceLoader.Load&lt;Script&gt;(path, "Script"); var res = ResourceLoader.Load&lt;Script&gt;(path, "Script");
string text = res.SourceCode; string text = res.SourceCode;
// Parsing logic. // Parsing logic.
} }
public override string[] _GetRecognizedExtensions() public override string[] _GetRecognizedExtensions()
{ {
return ["gd"]; return ["gd"];
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -90,18 +90,18 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _physics_process(_delta): func _physics_process(_delta):
if Engine.get_physics_frames() % 2 == 0: if Engine.get_physics_frames() % 2 == 0:
pass # Run expensive logic only once every 2 physics frames here. pass # Run expensive logic only once every 2 physics frames here.
[/gdscript] [/gdscript]
[csharp] [csharp]
public override void _PhysicsProcess(double delta) public override void _PhysicsProcess(double delta)
{ {
base._PhysicsProcess(delta); base._PhysicsProcess(delta);
if (Engine.GetPhysicsFrames() % 2 == 0) if (Engine.GetPhysicsFrames() % 2 == 0)
{ {
// Run expensive logic only once every 2 physics frames here. // Run expensive logic only once every 2 physics frames here.
} }
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -121,18 +121,18 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _process(_delta): func _process(_delta):
if Engine.get_process_frames() % 5 == 0: if Engine.get_process_frames() % 5 == 0:
pass # Run expensive logic only once every 5 process (render) frames here. pass # Run expensive logic only once every 5 process (render) frames here.
[/gdscript] [/gdscript]
[csharp] [csharp]
public override void _Process(double delta) public override void _Process(double delta)
{ {
base._Process(delta); base._Process(delta);
if (Engine.GetProcessFrames() % 5 == 0) if (Engine.GetProcessFrames() % 5 == 0)
{ {
// Run expensive logic only once every 5 process (render) frames here. // Run expensive logic only once every 5 process (render) frames here.
} }
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -183,18 +183,18 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
if Engine.get_version_info().hex &gt;= 0x040100: if Engine.get_version_info().hex &gt;= 0x040100:
pass # Do things specific to version 4.1 or later. pass # Do things specific to version 4.1 or later.
else: else:
pass # Do things specific to versions before 4.1. pass # Do things specific to versions before 4.1.
[/gdscript] [/gdscript]
[csharp] [csharp]
if ((int)Engine.GetVersionInfo()["hex"] &gt;= 0x040100) if ((int)Engine.GetVersionInfo()["hex"] &gt;= 0x040100)
{ {
// Do things specific to version 4.1 or later. // Do things specific to version 4.1 or later.
} }
else else
{ {
// Do things specific to versions before 4.1. // Do things specific to versions before 4.1.
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -235,15 +235,15 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
if Engine.is_editor_hint(): if Engine.is_editor_hint():
draw_gizmos() draw_gizmos()
else: else:
simulate_physics() simulate_physics()
[/gdscript] [/gdscript]
[csharp] [csharp]
if (Engine.IsEditorHint()) if (Engine.IsEditorHint())
DrawGizmos(); DrawGizmos();
else else
SimulatePhysics(); SimulatePhysics();
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
See [url=$DOCS_URL/tutorials/plugins/running_code_in_the_editor.html]Running code in the editor[/url] in the documentation for more information. See [url=$DOCS_URL/tutorials/plugins/running_code_in_the_editor.html]Running code in the editor[/url] in the documentation for more information.
@ -262,15 +262,15 @@
Returns [code]true[/code] if the engine is inside the fixed physics process step of the main loop. Returns [code]true[/code] if the engine is inside the fixed physics process step of the main loop.
[codeblock] [codeblock]
func _enter_tree(): func _enter_tree():
# Depending on when the node is added to the tree, # Depending on when the node is added to the tree,
# prints either "true" or "false". # prints either "true" or "false".
print(Engine.is_in_physics_frame()) print(Engine.is_in_physics_frame())
func _process(delta): func _process(delta):
print(Engine.is_in_physics_frame()) # Prints false print(Engine.is_in_physics_frame()) # Prints false
func _physics_process(delta): func _physics_process(delta):
print(Engine.is_in_physics_frame()) # Prints true print(Engine.is_in_physics_frame()) # Prints true
[/codeblock] [/codeblock]
</description> </description>
</method> </method>

View File

@ -12,38 +12,38 @@
var expression = Expression.new() var expression = Expression.new()
func _ready(): func _ready():
$LineEdit.text_submitted.connect(self._on_text_submitted) $LineEdit.text_submitted.connect(self._on_text_submitted)
func _on_text_submitted(command): func _on_text_submitted(command):
var error = expression.parse(command) var error = expression.parse(command)
if error != OK: if error != OK:
print(expression.get_error_text()) print(expression.get_error_text())
return return
var result = expression.execute() var result = expression.execute()
if not expression.has_execute_failed(): if not expression.has_execute_failed():
$LineEdit.text = str(result) $LineEdit.text = str(result)
[/gdscript] [/gdscript]
[csharp] [csharp]
private Expression _expression = new Expression(); private Expression _expression = new Expression();
public override void _Ready() public override void _Ready()
{ {
GetNode&lt;LineEdit&gt;("LineEdit").TextSubmitted += OnTextEntered; GetNode&lt;LineEdit&gt;("LineEdit").TextSubmitted += OnTextEntered;
} }
private void OnTextEntered(string command) private void OnTextEntered(string command)
{ {
Error error = _expression.Parse(command); Error error = _expression.Parse(command);
if (error != Error.Ok) if (error != Error.Ok)
{ {
GD.Print(_expression.GetErrorText()); GD.Print(_expression.GetErrorText());
return; return;
} }
Variant result = _expression.Execute(); Variant result = _expression.Execute();
if (!_expression.HasExecuteFailed()) if (!_expression.HasExecuteFailed())
{ {
GetNode&lt;LineEdit&gt;("LineEdit").Text = result.ToString(); GetNode&lt;LineEdit&gt;("LineEdit").Text = result.ToString();
} }
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -9,26 +9,26 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func save_to_file(content): func save_to_file(content):
var file = FileAccess.open("user://save_game.dat", FileAccess.WRITE) var file = FileAccess.open("user://save_game.dat", FileAccess.WRITE)
file.store_string(content) file.store_string(content)
func load_from_file(): func load_from_file():
var file = FileAccess.open("user://save_game.dat", FileAccess.READ) var file = FileAccess.open("user://save_game.dat", FileAccess.READ)
var content = file.get_as_text() var content = file.get_as_text()
return content return content
[/gdscript] [/gdscript]
[csharp] [csharp]
public void SaveToFile(string content) public void SaveToFile(string content)
{ {
using var file = FileAccess.Open("user://save_game.dat", FileAccess.ModeFlags.Write); using var file = FileAccess.Open("user://save_game.dat", FileAccess.ModeFlags.Write);
file.StoreString(content); file.StoreString(content);
} }
public string LoadFromFile() public string LoadFromFile()
{ {
using var file = FileAccess.Open("user://save_game.dat", FileAccess.ModeFlags.Read); using var file = FileAccess.Open("user://save_game.dat", FileAccess.ModeFlags.Read);
string content = file.GetAsText(); string content = file.GetAsText();
return content; return content;
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -71,12 +71,12 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
while file.get_position() &lt; file.get_length(): while file.get_position() &lt; file.get_length():
# Read data # Read data
[/gdscript] [/gdscript]
[csharp] [csharp]
while (file.GetPosition() &lt; file.GetLength()) while (file.GetPosition() &lt; file.GetLength())
{ {
// Read data // Read data
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -431,29 +431,29 @@
const MAX_16B = 1 &lt;&lt; 16 const MAX_16B = 1 &lt;&lt; 16
func unsigned16_to_signed(unsigned): func unsigned16_to_signed(unsigned):
return (unsigned + MAX_15B) % MAX_16B - MAX_15B return (unsigned + MAX_15B) % MAX_16B - MAX_15B
func _ready(): func _ready():
var f = FileAccess.open("user://file.dat", FileAccess.WRITE_READ) var f = FileAccess.open("user://file.dat", FileAccess.WRITE_READ)
f.store_16(-42) # This wraps around and stores 65494 (2^16 - 42). f.store_16(-42) # This wraps around and stores 65494 (2^16 - 42).
f.store_16(121) # In bounds, will store 121. f.store_16(121) # In bounds, will store 121.
f.seek(0) # Go back to start to read the stored value. f.seek(0) # Go back to start to read the stored value.
var read1 = f.get_16() # 65494 var read1 = f.get_16() # 65494
var read2 = f.get_16() # 121 var read2 = f.get_16() # 121
var converted1 = unsigned16_to_signed(read1) # -42 var converted1 = unsigned16_to_signed(read1) # -42
var converted2 = unsigned16_to_signed(read2) # 121 var converted2 = unsigned16_to_signed(read2) # 121
[/gdscript] [/gdscript]
[csharp] [csharp]
public override void _Ready() public override void _Ready()
{ {
using var f = FileAccess.Open("user://file.dat", FileAccess.ModeFlags.WriteRead); using var f = FileAccess.Open("user://file.dat", FileAccess.ModeFlags.WriteRead);
f.Store16(unchecked((ushort)-42)); // This wraps around and stores 65494 (2^16 - 42). f.Store16(unchecked((ushort)-42)); // This wraps around and stores 65494 (2^16 - 42).
f.Store16(121); // In bounds, will store 121. f.Store16(121); // In bounds, will store 121.
f.Seek(0); // Go back to start to read the stored value. f.Seek(0); // Go back to start to read the stored value.
ushort read1 = f.Get16(); // 65494 ushort read1 = f.Get16(); // 65494
ushort read2 = f.Get16(); // 121 ushort read2 = f.Get16(); // 121
short converted1 = (short)read1; // -42 short converted1 = (short)read1; // -42
short converted2 = (short)read2; // 121 short converted2 = (short)read2; // 121
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -288,9 +288,9 @@
fv.base_font = load("res://RobotoFlex.ttf") fv.base_font = load("res://RobotoFlex.ttf")
var variation_list = fv.get_supported_variation_list() var variation_list = fv.get_supported_variation_list()
for tag in variation_list: for tag in variation_list:
var name = TextServerManager.get_primary_interface().tag_to_name(tag) var name = TextServerManager.get_primary_interface().tag_to_name(tag)
var values = variation_list[tag] var values = variation_list[tag]
print("variation axis: %s (%d)\n\tmin, max, default: %s" % [name, tag, values]) print("variation axis: %s (%d)\n\tmin, max, default: %s" % [name, tag, values])
[/codeblock] [/codeblock]
[b]Note:[/b] To set and get variation coordinates of a [FontVariation], use [member FontVariation.variation_opentype]. [b]Note:[/b] To set and get variation coordinates of a [FontVariation], use [member FontVariation.variation_opentype].
</description> </description>

View File

@ -18,8 +18,8 @@
Example code to draw a line between two [Marker2D] nodes using a series of [method CanvasItem.draw_rect] calls: Example code to draw a line between two [Marker2D] nodes using a series of [method CanvasItem.draw_rect] calls:
[codeblock] [codeblock]
func _draw(): func _draw():
for pixel in Geometry2D.bresenham_line($MarkerA.position, $MarkerB.position): for pixel in Geometry2D.bresenham_line($MarkerA.position, $MarkerB.position):
draw_rect(Rect2(pixel, Vector2.ONE), Color.WHITE) draw_rect(Rect2(pixel, Vector2.ONE), Color.WHITE)
[/codeblock] [/codeblock]
</description> </description>
</method> </method>

View File

@ -31,11 +31,11 @@
Below is a sample code to help get started: Below is a sample code to help get started:
[codeblock] [codeblock]
func _is_in_input_hotzone(in_node, in_port, mouse_position): func _is_in_input_hotzone(in_node, in_port, mouse_position):
var port_size = Vector2(get_theme_constant("port_grab_distance_horizontal"), get_theme_constant("port_grab_distance_vertical")) var port_size = Vector2(get_theme_constant("port_grab_distance_horizontal"), get_theme_constant("port_grab_distance_vertical"))
var port_pos = in_node.get_position() + in_node.get_input_port_position(in_port) - port_size / 2 var port_pos = in_node.get_position() + in_node.get_input_port_position(in_port) - port_size / 2
var rect = Rect2(port_pos, port_size) var rect = Rect2(port_pos, port_size)
return rect.has_point(mouse_position) return rect.has_point(mouse_position)
[/codeblock] [/codeblock]
</description> </description>
</method> </method>
@ -49,11 +49,11 @@
Below is a sample code to help get started: Below is a sample code to help get started:
[codeblock] [codeblock]
func _is_in_output_hotzone(in_node, in_port, mouse_position): func _is_in_output_hotzone(in_node, in_port, mouse_position):
var port_size = Vector2(get_theme_constant("port_grab_distance_horizontal"), get_theme_constant("port_grab_distance_vertical")) var port_size = Vector2(get_theme_constant("port_grab_distance_horizontal"), get_theme_constant("port_grab_distance_vertical"))
var port_pos = in_node.get_position() + in_node.get_output_port_position(in_port) - port_size / 2 var port_pos = in_node.get_position() + in_node.get_output_port_position(in_port) - port_size / 2
var rect = Rect2(port_pos, port_size) var rect = Rect2(port_pos, port_size)
return rect.has_point(mouse_position) return rect.has_point(mouse_position)
[/codeblock] [/codeblock]
</description> </description>
</method> </method>
@ -70,12 +70,12 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _is_node_hover_valid(from, from_port, to, to_port): func _is_node_hover_valid(from, from_port, to, to_port):
return from != to return from != to
[/gdscript] [/gdscript]
[csharp] [csharp]
public override bool _IsNodeHoverValid(StringName fromNode, int fromPort, StringName toNode, int toPort) public override bool _IsNodeHoverValid(StringName fromNode, int fromPort, StringName toNode, int toPort)
{ {
return fromNode != toNode; return fromNode != toNode;
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -177,11 +177,11 @@
A connection is represented as a [Dictionary] in the form of: A connection is represented as a [Dictionary] in the form of:
[codeblock] [codeblock]
{ {
from_node: StringName, from_node: StringName,
from_port: int, from_port: int,
to_node: StringName, to_node: StringName,
to_port: int, to_port: int,
keep_alive: bool keep_alive: bool
} }
[/codeblock] [/codeblock]
For example, getting a connection at a given mouse position can be achieved like this: For example, getting a connection at a given mouse position can be achieved like this:
@ -216,11 +216,11 @@
A connection is represented as a [Dictionary] in the form of: A connection is represented as a [Dictionary] in the form of:
[codeblock] [codeblock]
{ {
from_node: StringName, from_node: StringName,
from_port: int, from_port: int,
to_node: StringName, to_node: StringName,
to_port: int, to_port: int,
keep_alive: bool keep_alive: bool
} }
[/codeblock] [/codeblock]
</description> </description>
@ -233,11 +233,11 @@
A connection is represented as a [Dictionary] in the form of: A connection is represented as a [Dictionary] in the form of:
[codeblock] [codeblock]
{ {
from_node: StringName, from_node: StringName,
from_port: int, from_port: int,
to_node: StringName, to_node: StringName,
to_port: int, to_port: int,
keep_alive: bool keep_alive: bool
} }
[/codeblock] [/codeblock]
</description> </description>
@ -333,11 +333,11 @@
A connection is represented as a [Dictionary] in the form of: A connection is represented as a [Dictionary] in the form of:
[codeblock] [codeblock]
{ {
from_node: StringName, from_node: StringName,
from_port: int, from_port: int,
to_node: StringName, to_node: StringName,
to_port: int, to_port: int,
keep_alive: bool keep_alive: bool
} }
[/codeblock] [/codeblock]
Connections with [code]keep_alive[/code] set to [code]false[/code] may be deleted automatically if invalid during a redraw. Connections with [code]keep_alive[/code] set to [code]false[/code] may be deleted automatically if invalid during a redraw.

View File

@ -11,17 +11,17 @@
var ctx = HMACContext.new() var ctx = HMACContext.new()
func _ready(): func _ready():
var key = "supersecret".to_utf8_buffer() var key = "supersecret".to_utf8_buffer()
var err = ctx.start(HashingContext.HASH_SHA256, key) var err = ctx.start(HashingContext.HASH_SHA256, key)
assert(err == OK) assert(err == OK)
var msg1 = "this is ".to_utf8_buffer() var msg1 = "this is ".to_utf8_buffer()
var msg2 = "super duper secret".to_utf8_buffer() var msg2 = "super duper secret".to_utf8_buffer()
err = ctx.update(msg1) err = ctx.update(msg1)
assert(err == OK) assert(err == OK)
err = ctx.update(msg2) err = ctx.update(msg2)
assert(err == OK) assert(err == OK)
var hmac = ctx.finish() var hmac = ctx.finish()
print(hmac.hex_encode()) print(hmac.hex_encode())
[/gdscript] [/gdscript]
[csharp] [csharp]
@ -30,22 +30,22 @@
public partial class MyNode : Node public partial class MyNode : Node
{ {
private HmacContext _ctx = new HmacContext(); private HmacContext _ctx = new HmacContext();
public override void _Ready() public override void _Ready()
{ {
byte[] key = "supersecret".ToUtf8Buffer(); byte[] key = "supersecret".ToUtf8Buffer();
Error err = _ctx.Start(HashingContext.HashType.Sha256, key); Error err = _ctx.Start(HashingContext.HashType.Sha256, key);
Debug.Assert(err == Error.Ok); Debug.Assert(err == Error.Ok);
byte[] msg1 = "this is ".ToUtf8Buffer(); byte[] msg1 = "this is ".ToUtf8Buffer();
byte[] msg2 = "super duper secret".ToUtf8Buffer(); byte[] msg2 = "super duper secret".ToUtf8Buffer();
err = _ctx.Update(msg1); err = _ctx.Update(msg1);
Debug.Assert(err == Error.Ok); Debug.Assert(err == Error.Ok);
err = _ctx.Update(msg2); err = _ctx.Update(msg2);
Debug.Assert(err == Error.Ok); Debug.Assert(err == Error.Ok);
byte[] hmac = _ctx.Finish(); byte[] hmac = _ctx.Finish();
GD.Print(hmac.HexEncode()); GD.Print(hmac.HexEncode());
} }
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -62,8 +62,8 @@
Returns all response headers as a [Dictionary]. Each entry is composed by the header name, and a [String] containing the values separated by [code]"; "[/code]. The casing is kept the same as the headers were received. Returns all response headers as a [Dictionary]. Each entry is composed by the header name, and a [String] containing the values separated by [code]"; "[/code]. The casing is kept the same as the headers were received.
[codeblock] [codeblock]
{ {
"content-length": 12, "content-length": 12,
"Content-Type": "application/json; charset=UTF-8", "Content-Type": "application/json; charset=UTF-8",
} }
[/codeblock] [/codeblock]
</description> </description>
@ -119,9 +119,9 @@
[csharp] [csharp]
var fields = new Godot.Collections.Dictionary var fields = new Godot.Collections.Dictionary
{ {
{ "single", 123 }, { "single", 123 },
{ "notValued", default }, { "notValued", default },
{ "multiple", new Godot.Collections.Array { 22, 33, 44 } }, { "multiple", new Godot.Collections.Array { 22, 33, 44 } },
}; };
string queryString = httpClient.QueryStringFromDict(fields); string queryString = httpClient.QueryStringFromDict(fields);
// Returns "single=123&amp;not_valued&amp;multiple=22&amp;multiple=33&amp;multiple=44" // Returns "single=123&amp;not_valued&amp;multiple=22&amp;multiple=33&amp;multiple=44"

View File

@ -12,71 +12,71 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _ready(): func _ready():
# Create an HTTP request node and connect its completion signal. # Create an HTTP request node and connect its completion signal.
var http_request = HTTPRequest.new() var http_request = HTTPRequest.new()
add_child(http_request) add_child(http_request)
http_request.request_completed.connect(self._http_request_completed) http_request.request_completed.connect(self._http_request_completed)
# Perform a GET request. The URL below returns JSON as of writing. # Perform a GET request. The URL below returns JSON as of writing.
var error = http_request.request("https://httpbin.org/get") var error = http_request.request("https://httpbin.org/get")
if error != OK: if error != OK:
push_error("An error occurred in the HTTP request.") push_error("An error occurred in the HTTP request.")
# Perform a POST request. The URL below returns JSON as of writing. # Perform a POST request. The URL below returns JSON as of writing.
# Note: Don't make simultaneous requests using a single HTTPRequest node. # Note: Don't make simultaneous requests using a single HTTPRequest node.
# The snippet below is provided for reference only. # The snippet below is provided for reference only.
var body = JSON.new().stringify({"name": "Godette"}) var body = JSON.new().stringify({"name": "Godette"})
error = http_request.request("https://httpbin.org/post", [], HTTPClient.METHOD_POST, body) error = http_request.request("https://httpbin.org/post", [], HTTPClient.METHOD_POST, body)
if error != OK: if error != OK:
push_error("An error occurred in the HTTP request.") push_error("An error occurred in the HTTP request.")
# Called when the HTTP request is completed. # Called when the HTTP request is completed.
func _http_request_completed(result, response_code, headers, body): func _http_request_completed(result, response_code, headers, body):
var json = JSON.new() var json = JSON.new()
json.parse(body.get_string_from_utf8()) json.parse(body.get_string_from_utf8())
var response = json.get_data() var response = json.get_data()
# Will print the user agent string used by the HTTPRequest node (as recognized by httpbin.org). # Will print the user agent string used by the HTTPRequest node (as recognized by httpbin.org).
print(response.headers["User-Agent"]) print(response.headers["User-Agent"])
[/gdscript] [/gdscript]
[csharp] [csharp]
public override void _Ready() public override void _Ready()
{ {
// Create an HTTP request node and connect its completion signal. // Create an HTTP request node and connect its completion signal.
var httpRequest = new HttpRequest(); var httpRequest = new HttpRequest();
AddChild(httpRequest); AddChild(httpRequest);
httpRequest.RequestCompleted += HttpRequestCompleted; httpRequest.RequestCompleted += HttpRequestCompleted;
// Perform a GET request. The URL below returns JSON as of writing. // Perform a GET request. The URL below returns JSON as of writing.
Error error = httpRequest.Request("https://httpbin.org/get"); Error error = httpRequest.Request("https://httpbin.org/get");
if (error != Error.Ok) if (error != Error.Ok)
{ {
GD.PushError("An error occurred in the HTTP request."); GD.PushError("An error occurred in the HTTP request.");
} }
// Perform a POST request. The URL below returns JSON as of writing. // Perform a POST request. The URL below returns JSON as of writing.
// Note: Don't make simultaneous requests using a single HTTPRequest node. // Note: Don't make simultaneous requests using a single HTTPRequest node.
// The snippet below is provided for reference only. // The snippet below is provided for reference only.
string body = new Json().Stringify(new Godot.Collections.Dictionary string body = new Json().Stringify(new Godot.Collections.Dictionary
{ {
{ "name", "Godette" } { "name", "Godette" }
}); });
error = httpRequest.Request("https://httpbin.org/post", null, HttpClient.Method.Post, body); error = httpRequest.Request("https://httpbin.org/post", null, HttpClient.Method.Post, body);
if (error != Error.Ok) if (error != Error.Ok)
{ {
GD.PushError("An error occurred in the HTTP request."); GD.PushError("An error occurred in the HTTP request.");
} }
} }
// Called when the HTTP request is completed. // Called when the HTTP request is completed.
private void HttpRequestCompleted(long result, long responseCode, string[] headers, byte[] body) private void HttpRequestCompleted(long result, long responseCode, string[] headers, byte[] body)
{ {
var json = new Json(); var json = new Json();
json.Parse(body.GetStringFromUtf8()); json.Parse(body.GetStringFromUtf8());
var response = json.GetData().AsGodotDictionary(); var response = json.GetData().AsGodotDictionary();
// Will print the user agent string used by the HTTPRequest node (as recognized by httpbin.org). // Will print the user agent string used by the HTTPRequest node (as recognized by httpbin.org).
GD.Print((response["headers"].AsGodotDictionary())["User-Agent"]); GD.Print((response["headers"].AsGodotDictionary())["User-Agent"]);
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -84,69 +84,69 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _ready(): func _ready():
# Create an HTTP request node and connect its completion signal. # Create an HTTP request node and connect its completion signal.
var http_request = HTTPRequest.new() var http_request = HTTPRequest.new()
add_child(http_request) add_child(http_request)
http_request.request_completed.connect(self._http_request_completed) http_request.request_completed.connect(self._http_request_completed)
# Perform the HTTP request. The URL below returns a PNG image as of writing. # Perform the HTTP request. The URL below returns a PNG image as of writing.
var error = http_request.request("https://placehold.co/512") var error = http_request.request("https://placehold.co/512")
if error != OK: if error != OK:
push_error("An error occurred in the HTTP request.") push_error("An error occurred in the HTTP request.")
# Called when the HTTP request is completed. # Called when the HTTP request is completed.
func _http_request_completed(result, response_code, headers, body): func _http_request_completed(result, response_code, headers, body):
if result != HTTPRequest.RESULT_SUCCESS: if result != HTTPRequest.RESULT_SUCCESS:
push_error("Image couldn't be downloaded. Try a different image.") push_error("Image couldn't be downloaded. Try a different image.")
var image = Image.new() var image = Image.new()
var error = image.load_png_from_buffer(body) var error = image.load_png_from_buffer(body)
if error != OK: if error != OK:
push_error("Couldn't load the image.") push_error("Couldn't load the image.")
var texture = ImageTexture.create_from_image(image) var texture = ImageTexture.create_from_image(image)
# Display the image in a TextureRect node. # Display the image in a TextureRect node.
var texture_rect = TextureRect.new() var texture_rect = TextureRect.new()
add_child(texture_rect) add_child(texture_rect)
texture_rect.texture = texture texture_rect.texture = texture
[/gdscript] [/gdscript]
[csharp] [csharp]
public override void _Ready() public override void _Ready()
{ {
// Create an HTTP request node and connect its completion signal. // Create an HTTP request node and connect its completion signal.
var httpRequest = new HttpRequest(); var httpRequest = new HttpRequest();
AddChild(httpRequest); AddChild(httpRequest);
httpRequest.RequestCompleted += HttpRequestCompleted; httpRequest.RequestCompleted += HttpRequestCompleted;
// Perform the HTTP request. The URL below returns a PNG image as of writing. // Perform the HTTP request. The URL below returns a PNG image as of writing.
Error error = httpRequest.Request("https://placehold.co/512"); Error error = httpRequest.Request("https://placehold.co/512");
if (error != Error.Ok) if (error != Error.Ok)
{ {
GD.PushError("An error occurred in the HTTP request."); GD.PushError("An error occurred in the HTTP request.");
} }
} }
// Called when the HTTP request is completed. // Called when the HTTP request is completed.
private void HttpRequestCompleted(long result, long responseCode, string[] headers, byte[] body) private void HttpRequestCompleted(long result, long responseCode, string[] headers, byte[] body)
{ {
if (result != (long)HttpRequest.Result.Success) if (result != (long)HttpRequest.Result.Success)
{ {
GD.PushError("Image couldn't be downloaded. Try a different image."); GD.PushError("Image couldn't be downloaded. Try a different image.");
} }
var image = new Image(); var image = new Image();
Error error = image.LoadPngFromBuffer(body); Error error = image.LoadPngFromBuffer(body);
if (error != Error.Ok) if (error != Error.Ok)
{ {
GD.PushError("Couldn't load the image."); GD.PushError("Couldn't load the image.");
} }
var texture = ImageTexture.CreateFromImage(image); var texture = ImageTexture.CreateFromImage(image);
// Display the image in a TextureRect node. // Display the image in a TextureRect node.
var textureRect = new TextureRect(); var textureRect = new TextureRect();
AddChild(textureRect); AddChild(textureRect);
textureRect.Texture = texture; textureRect.Texture = texture;
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -11,48 +11,48 @@
const CHUNK_SIZE = 1024 const CHUNK_SIZE = 1024
func hash_file(path): func hash_file(path):
# Check that file exists. # Check that file exists.
if not FileAccess.file_exists(path): if not FileAccess.file_exists(path):
return return
# Start an SHA-256 context. # Start an SHA-256 context.
var ctx = HashingContext.new() var ctx = HashingContext.new()
ctx.start(HashingContext.HASH_SHA256) ctx.start(HashingContext.HASH_SHA256)
# Open the file to hash. # Open the file to hash.
var file = FileAccess.open(path, FileAccess.READ) var file = FileAccess.open(path, FileAccess.READ)
# Update the context after reading each chunk. # Update the context after reading each chunk.
while file.get_position() &lt; file.get_length(): while file.get_position() &lt; file.get_length():
var remaining = file.get_length() - file.get_position() var remaining = file.get_length() - file.get_position()
ctx.update(file.get_buffer(min(remaining, CHUNK_SIZE))) ctx.update(file.get_buffer(min(remaining, CHUNK_SIZE)))
# Get the computed hash. # Get the computed hash.
var res = ctx.finish() var res = ctx.finish()
# Print the result as hex string and array. # Print the result as hex string and array.
printt(res.hex_encode(), Array(res)) printt(res.hex_encode(), Array(res))
[/gdscript] [/gdscript]
[csharp] [csharp]
public const int ChunkSize = 1024; public const int ChunkSize = 1024;
public void HashFile(string path) public void HashFile(string path)
{ {
// Check that file exists. // Check that file exists.
if (!FileAccess.FileExists(path)) if (!FileAccess.FileExists(path))
{ {
return; return;
} }
// Start an SHA-256 context. // Start an SHA-256 context.
var ctx = new HashingContext(); var ctx = new HashingContext();
ctx.Start(HashingContext.HashType.Sha256); ctx.Start(HashingContext.HashType.Sha256);
// Open the file to hash. // Open the file to hash.
using var file = FileAccess.Open(path, FileAccess.ModeFlags.Read); using var file = FileAccess.Open(path, FileAccess.ModeFlags.Read);
// Update the context after reading each chunk. // Update the context after reading each chunk.
while (file.GetPosition() &lt; file.GetLength()) while (file.GetPosition() &lt; file.GetLength())
{ {
int remaining = (int)(file.GetLength() - file.GetPosition()); int remaining = (int)(file.GetLength() - file.GetPosition());
ctx.Update(file.GetBuffer(Mathf.Min(remaining, ChunkSize))); ctx.Update(file.GetBuffer(Mathf.Min(remaining, ChunkSize)));
} }
// Get the computed hash. // Get the computed hash.
byte[] res = ctx.Finish(); byte[] res = ctx.Finish();
// Print the result as hex string and array. // Print the result as hex string and array.
GD.PrintT(res.HexEncode(), (Variant)res); GD.PrintT(res.HexEncode(), (Variant)res);
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -36,10 +36,10 @@
Each adapter is a dictionary of the form: Each adapter is a dictionary of the form:
[codeblock] [codeblock]
{ {
"index": "1", # Interface index. "index": "1", # Interface index.
"name": "eth0", # Interface name. "name": "eth0", # Interface name.
"friendly": "Ethernet One", # A friendly name (might be empty). "friendly": "Ethernet One", # A friendly name (might be empty).
"addresses": ["192.168.1.101"], # An array of IP addresses associated to this interface. "addresses": ["192.168.1.101"], # An array of IP addresses associated to this interface.
} }
[/codeblock] [/codeblock]
</description> </description>

View File

@ -20,14 +20,14 @@
var images = [] var images = []
const LAYERS = 6 const LAYERS = 6
for i in LAYERS: for i in LAYERS:
var image = Image.create_empty(128, 128, false, Image.FORMAT_RGB8) var image = Image.create_empty(128, 128, false, Image.FORMAT_RGB8)
if i % 3 == 0: if i % 3 == 0:
image.fill(Color.RED) image.fill(Color.RED)
elif i % 3 == 1: elif i % 3 == 1:
image.fill(Color.GREEN) image.fill(Color.GREEN)
else: else:
image.fill(Color.BLUE) image.fill(Color.BLUE)
images.push_back(image) images.push_back(image)
# Create and save a 2D texture array. The array of images must have at least 1 Image. # Create and save a 2D texture array. The array of images must have at least 1 Image.
var texture_2d_array = Texture2DArray.new() var texture_2d_array = Texture2DArray.new()

View File

@ -68,20 +68,20 @@
For keyboard layouts with a single label on the key, it is equivalent to [member keycode]. For keyboard layouts with a single label on the key, it is equivalent to [member keycode].
To get a human-readable representation of the [InputEventKey], use [code]OS.get_keycode_string(event.key_label)[/code] where [code]event[/code] is the [InputEventKey]. To get a human-readable representation of the [InputEventKey], use [code]OS.get_keycode_string(event.key_label)[/code] where [code]event[/code] is the [InputEventKey].
[codeblock lang=text] [codeblock lang=text]
+-----+ +-----+ +-----+ +-----+
| Q | | Q | - "Q" - keycode | Q | | Q | - "Q" - keycode
| Й | | ض | - "Й" and "ض" - key_label | Й | | ض | - "Й" and "ض" - key_label
+-----+ +-----+ +-----+ +-----+
[/codeblock] [/codeblock]
</member> </member>
<member name="keycode" type="int" setter="set_keycode" getter="get_keycode" enum="Key" default="0"> <member name="keycode" type="int" setter="set_keycode" getter="get_keycode" enum="Key" default="0">
Latin label printed on the key in the current keyboard layout, which corresponds to one of the [enum Key] constants. Latin label printed on the key in the current keyboard layout, which corresponds to one of the [enum Key] constants.
To get a human-readable representation of the [InputEventKey], use [code]OS.get_keycode_string(event.keycode)[/code] where [code]event[/code] is the [InputEventKey]. To get a human-readable representation of the [InputEventKey], use [code]OS.get_keycode_string(event.keycode)[/code] where [code]event[/code] is the [InputEventKey].
[codeblock lang=text] [codeblock lang=text]
+-----+ +-----+ +-----+ +-----+
| Q | | Q | - "Q" - keycode | Q | | Q | - "Q" - keycode
| Й | | ض | - "Й" and "ض" - key_label | Й | | ض | - "Й" and "ض" - key_label
+-----+ +-----+ +-----+ +-----+
[/codeblock] [/codeblock]
</member> </member>
<member name="location" type="int" setter="set_location" getter="get_location" enum="KeyLocation" default="0"> <member name="location" type="int" setter="set_location" getter="get_location" enum="KeyLocation" default="0">
@ -93,18 +93,18 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _input(event): func _input(event):
if event is InputEventKey: if event is InputEventKey:
var keycode = DisplayServer.keyboard_get_keycode_from_physical(event.physical_keycode) var keycode = DisplayServer.keyboard_get_keycode_from_physical(event.physical_keycode)
print(OS.get_keycode_string(keycode)) print(OS.get_keycode_string(keycode))
[/gdscript] [/gdscript]
[csharp] [csharp]
public override void _Input(InputEvent @event) public override void _Input(InputEvent @event)
{ {
if (@event is InputEventKey inputEventKey) if (@event is InputEventKey inputEventKey)
{ {
var keycode = DisplayServer.KeyboardGetKeycodeFromPhysical(inputEventKey.PhysicalKeycode); var keycode = DisplayServer.KeyboardGetKeycodeFromPhysical(inputEventKey.PhysicalKeycode);
GD.Print(OS.GetKeycodeString(keycode)); GD.Print(OS.GetKeycodeString(keycode));
} }
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -10,50 +10,50 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _ready(): func _ready():
OS.open_midi_inputs() OS.open_midi_inputs()
print(OS.get_connected_midi_inputs()) print(OS.get_connected_midi_inputs())
func _input(input_event): func _input(input_event):
if input_event is InputEventMIDI: if input_event is InputEventMIDI:
_print_midi_info(input_event) _print_midi_info(input_event)
func _print_midi_info(midi_event): func _print_midi_info(midi_event):
print(midi_event) print(midi_event)
print("Channel ", midi_event.channel) print("Channel ", midi_event.channel)
print("Message ", midi_event.message) print("Message ", midi_event.message)
print("Pitch ", midi_event.pitch) print("Pitch ", midi_event.pitch)
print("Velocity ", midi_event.velocity) print("Velocity ", midi_event.velocity)
print("Instrument ", midi_event.instrument) print("Instrument ", midi_event.instrument)
print("Pressure ", midi_event.pressure) print("Pressure ", midi_event.pressure)
print("Controller number: ", midi_event.controller_number) print("Controller number: ", midi_event.controller_number)
print("Controller value: ", midi_event.controller_value) print("Controller value: ", midi_event.controller_value)
[/gdscript] [/gdscript]
[csharp] [csharp]
public override void _Ready() public override void _Ready()
{ {
OS.OpenMidiInputs(); OS.OpenMidiInputs();
GD.Print(OS.GetConnectedMidiInputs()); GD.Print(OS.GetConnectedMidiInputs());
} }
public override void _Input(InputEvent inputEvent) public override void _Input(InputEvent inputEvent)
{ {
if (inputEvent is InputEventMidi midiEvent) if (inputEvent is InputEventMidi midiEvent)
{ {
PrintMIDIInfo(midiEvent); PrintMIDIInfo(midiEvent);
} }
} }
private void PrintMIDIInfo(InputEventMidi midiEvent) private void PrintMIDIInfo(InputEventMidi midiEvent)
{ {
GD.Print(midiEvent); GD.Print(midiEvent);
GD.Print($"Channel {midiEvent.Channel}"); GD.Print($"Channel {midiEvent.Channel}");
GD.Print($"Message {midiEvent.Message}"); GD.Print($"Message {midiEvent.Message}");
GD.Print($"Pitch {midiEvent.Pitch}"); GD.Print($"Pitch {midiEvent.Pitch}");
GD.Print($"Velocity {midiEvent.Velocity}"); GD.Print($"Velocity {midiEvent.Velocity}");
GD.Print($"Instrument {midiEvent.Instrument}"); GD.Print($"Instrument {midiEvent.Instrument}");
GD.Print($"Pressure {midiEvent.Pressure}"); GD.Print($"Pressure {midiEvent.Pressure}");
GD.Print($"Controller number: {midiEvent.ControllerNumber}"); GD.Print($"Controller number: {midiEvent.ControllerNumber}");
GD.Print($"Controller value: {midiEvent.ControllerValue}"); GD.Print($"Controller value: {midiEvent.ControllerValue}");
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -96,9 +96,9 @@
[b]Note:[/b] Some MIDI devices may send a [constant MIDI_MESSAGE_NOTE_ON] message with [code]0[/code] velocity and expect it to be treated the same as a [constant MIDI_MESSAGE_NOTE_OFF] message. If necessary, this can be handled with a few lines of code: [b]Note:[/b] Some MIDI devices may send a [constant MIDI_MESSAGE_NOTE_ON] message with [code]0[/code] velocity and expect it to be treated the same as a [constant MIDI_MESSAGE_NOTE_OFF] message. If necessary, this can be handled with a few lines of code:
[codeblock] [codeblock]
func _input(event): func _input(event):
if event is InputEventMIDI: if event is InputEventMIDI:
if event.message == MIDI_MESSAGE_NOTE_ON and event.velocity &gt; 0: if event.message == MIDI_MESSAGE_NOTE_ON and event.velocity &gt; 0:
print("Note pressed!") print("Note pressed!")
[/codeblock] [/codeblock]
</member> </member>
</members> </members>

View File

@ -16,13 +16,13 @@
var json = JSON.new() var json = JSON.new()
var error = json.parse(json_string) var error = json.parse(json_string)
if error == OK: if error == OK:
var data_received = json.data var data_received = json.data
if typeof(data_received) == TYPE_ARRAY: if typeof(data_received) == TYPE_ARRAY:
print(data_received) # Prints the array. print(data_received) # Prints the array.
else: else:
print("Unexpected data") print("Unexpected data")
else: else:
print("JSON Parse Error: ", json.get_error_message(), " in ", json_string, " at line ", json.get_error_line()) print("JSON Parse Error: ", json.get_error_message(), " in ", json_string, " at line ", json.get_error_line())
[/codeblock] [/codeblock]
Alternatively, you can parse strings using the static [method parse_string] method, but it doesn't handle errors. Alternatively, you can parse strings using the static [method parse_string] method, but it doesn't handle errors.
[codeblock] [codeblock]
@ -47,7 +47,7 @@
You can convert a native value to a JSON string like this: You can convert a native value to a JSON string like this:
[codeblock] [codeblock]
func encode_data(value, full_objects = false): func encode_data(value, full_objects = false):
return JSON.stringify(JSON.from_native(value, full_objects)) return JSON.stringify(JSON.from_native(value, full_objects))
[/codeblock] [/codeblock]
</description> </description>
</method> </method>
@ -105,18 +105,18 @@
## JSON.stringify(my_dictionary, "\t") ## JSON.stringify(my_dictionary, "\t")
{ {
"name": "my_dictionary", "name": "my_dictionary",
"version": "1.0.0", "version": "1.0.0",
"entities": [ "entities": [
{ {
"name": "entity_0", "name": "entity_0",
"value": "value_0" "value": "value_0"
}, },
{ {
"name": "entity_1", "name": "entity_1",
"value": "value_1" "value": "value_1"
} }
] ]
} }
## JSON.stringify(my_dictionary, "...") ## JSON.stringify(my_dictionary, "...")
@ -147,7 +147,7 @@
You can convert a JSON string back to a native value like this: You can convert a JSON string back to a native value like this:
[codeblock] [codeblock]
func decode_data(string, allow_objects = false): func decode_data(string, allow_objects = false):
return JSON.to_native(JSON.parse_string(string), allow_objects) return JSON.to_native(JSON.parse_string(string), allow_objects)
[/codeblock] [/codeblock]
</description> </description>
</method> </method>

View File

@ -12,25 +12,25 @@
var console = JavaScriptBridge.get_interface("console") var console = JavaScriptBridge.get_interface("console")
func _init(): func _init():
var buf = JavaScriptBridge.create_object("ArrayBuffer", 10) # new ArrayBuffer(10) var buf = JavaScriptBridge.create_object("ArrayBuffer", 10) # new ArrayBuffer(10)
print(buf) # Prints [JavaScriptObject:OBJECT_ID] print(buf) # Prints [JavaScriptObject:OBJECT_ID]
var uint8arr = JavaScriptBridge.create_object("Uint8Array", buf) # new Uint8Array(buf) var uint8arr = JavaScriptBridge.create_object("Uint8Array", buf) # new Uint8Array(buf)
uint8arr[1] = 255 uint8arr[1] = 255
prints(uint8arr[1], uint8arr.byteLength) # Prints "255 10" prints(uint8arr[1], uint8arr.byteLength) # Prints "255 10"
# Prints "Uint8Array(10) [ 0, 255, 0, 0, 0, 0, 0, 0, 0, 0 ]" in the browser's console. # Prints "Uint8Array(10) [ 0, 255, 0, 0, 0, 0, 0, 0, 0, 0 ]" in the browser's console.
console.log(uint8arr) console.log(uint8arr)
# Equivalent of JavaScriptBridge: Array.from(uint8arr).forEach(myCallback) # Equivalent of JavaScriptBridge: Array.from(uint8arr).forEach(myCallback)
JavaScriptBridge.get_interface("Array").from(uint8arr).forEach(_my_js_callback) JavaScriptBridge.get_interface("Array").from(uint8arr).forEach(_my_js_callback)
func myCallback(args): func myCallback(args):
# Will be called with the parameters passed to the "forEach" callback # Will be called with the parameters passed to the "forEach" callback
# [0, 0, [JavaScriptObject:1173]] # [0, 0, [JavaScriptObject:1173]]
# [255, 1, [JavaScriptObject:1173]] # [255, 1, [JavaScriptObject:1173]]
# ... # ...
# [0, 9, [JavaScriptObject:1180]] # [0, 9, [JavaScriptObject:1180]]
print(args) print(args)
[/codeblock] [/codeblock]
[b]Note:[/b] Only available in the Web platform. [b]Note:[/b] Only available in the Web platform.
</description> </description>

View File

@ -95,38 +95,38 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _ready(): func _ready():
var menu = get_menu() var menu = get_menu()
# Remove all items after "Redo". # Remove all items after "Redo".
menu.item_count = menu.get_item_index(MENU_REDO) + 1 menu.item_count = menu.get_item_index(MENU_REDO) + 1
# Add custom items. # Add custom items.
menu.add_separator() menu.add_separator()
menu.add_item("Insert Date", MENU_MAX + 1) menu.add_item("Insert Date", MENU_MAX + 1)
# Connect callback. # Connect callback.
menu.id_pressed.connect(_on_item_pressed) menu.id_pressed.connect(_on_item_pressed)
func _on_item_pressed(id): func _on_item_pressed(id):
if id == MENU_MAX + 1: if id == MENU_MAX + 1:
insert_text_at_caret(Time.get_date_string_from_system()) insert_text_at_caret(Time.get_date_string_from_system())
[/gdscript] [/gdscript]
[csharp] [csharp]
public override void _Ready() public override void _Ready()
{ {
var menu = GetMenu(); var menu = GetMenu();
// Remove all items after "Redo". // Remove all items after "Redo".
menu.ItemCount = menu.GetItemIndex(LineEdit.MenuItems.Redo) + 1; menu.ItemCount = menu.GetItemIndex(LineEdit.MenuItems.Redo) + 1;
// Add custom items. // Add custom items.
menu.AddSeparator(); menu.AddSeparator();
menu.AddItem("Insert Date", LineEdit.MenuItems.Max + 1); menu.AddItem("Insert Date", LineEdit.MenuItems.Max + 1);
// Add event handler. // Add event handler.
menu.IdPressed += OnItemPressed; menu.IdPressed += OnItemPressed;
} }
public void OnItemPressed(int id) public void OnItemPressed(int id)
{ {
if (id == LineEdit.MenuItems.Max + 1) if (id == LineEdit.MenuItems.Max + 1)
{ {
InsertTextAtCaret(Time.GetDateStringFromSystem()); InsertTextAtCaret(Time.GetDateStringFromSystem());
} }
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -15,17 +15,17 @@
var time_elapsed = 0 var time_elapsed = 0
func _initialize(): func _initialize():
print("Initialized:") print("Initialized:")
print(" Starting time: %s" % str(time_elapsed)) print(" Starting time: %s" % str(time_elapsed))
func _process(delta): func _process(delta):
time_elapsed += delta time_elapsed += delta
# Return true to end the main loop. # Return true to end the main loop.
return Input.get_mouse_button_mask() != 0 || Input.is_key_pressed(KEY_ESCAPE) return Input.get_mouse_button_mask() != 0 || Input.is_key_pressed(KEY_ESCAPE)
func _finalize(): func _finalize():
print("Finalized:") print("Finalized:")
print(" End time: %s" % str(time_elapsed)) print(" End time: %s" % str(time_elapsed))
[/gdscript] [/gdscript]
[csharp] [csharp]
using Godot; using Godot;
@ -33,26 +33,26 @@
[GlobalClass] [GlobalClass]
public partial class CustomMainLoop : MainLoop public partial class CustomMainLoop : MainLoop
{ {
private double _timeElapsed = 0; private double _timeElapsed = 0;
public override void _Initialize() public override void _Initialize()
{ {
GD.Print("Initialized:"); GD.Print("Initialized:");
GD.Print($" Starting Time: {_timeElapsed}"); GD.Print($" Starting Time: {_timeElapsed}");
} }
public override bool _Process(double delta) public override bool _Process(double delta)
{ {
_timeElapsed += delta; _timeElapsed += delta;
// Return true to end the main loop. // Return true to end the main loop.
return Input.GetMouseButtonMask() != 0 || Input.IsKeyPressed(Key.Escape); return Input.GetMouseButtonMask() != 0 || Input.IsKeyPressed(Key.Escape);
} }
private void _Finalize() private void _Finalize()
{ {
GD.Print("Finalized:"); GD.Print("Finalized:");
GD.Print($" End Time: {_timeElapsed}"); GD.Print($" End Time: {_timeElapsed}");
} }
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -14,11 +14,11 @@
var mdt = MeshDataTool.new() var mdt = MeshDataTool.new()
mdt.create_from_surface(mesh, 0) mdt.create_from_surface(mesh, 0)
for i in range(mdt.get_vertex_count()): for i in range(mdt.get_vertex_count()):
var vertex = mdt.get_vertex(i) var vertex = mdt.get_vertex(i)
# In this example we extend the mesh by one unit, which results in separated faces as it is flat shaded. # In this example we extend the mesh by one unit, which results in separated faces as it is flat shaded.
vertex += mdt.get_vertex_normal(i) vertex += mdt.get_vertex_normal(i)
# Save your change. # Save your change.
mdt.set_vertex(i, vertex) mdt.set_vertex(i, vertex)
mesh.clear_surfaces() mesh.clear_surfaces()
mdt.commit_to_surface(mesh) mdt.commit_to_surface(mesh)
var mi = MeshInstance.new() var mi = MeshInstance.new()
@ -32,11 +32,11 @@
mdt.CreateFromSurface(mesh, 0); mdt.CreateFromSurface(mesh, 0);
for (var i = 0; i &lt; mdt.GetVertexCount(); i++) for (var i = 0; i &lt; mdt.GetVertexCount(); i++)
{ {
Vector3 vertex = mdt.GetVertex(i); Vector3 vertex = mdt.GetVertex(i);
// In this example we extend the mesh by one unit, which results in separated faces as it is flat shaded. // In this example we extend the mesh by one unit, which results in separated faces as it is flat shaded.
vertex += mdt.GetVertexNormal(i); vertex += mdt.GetVertexNormal(i);
// Save your change. // Save your change.
mdt.SetVertex(i, vertex); mdt.SetVertex(i, vertex);
} }
mesh.ClearSurfaces(); mesh.ClearSurfaces();
mdt.CommitToSurface(mesh); mdt.CommitToSurface(mesh);

View File

@ -35,9 +35,9 @@
Called when the engine determines whether this [MovieWriter] is able to handle the file at [param path]. Must return [code]true[/code] if this [MovieWriter] is able to handle the given file path, [code]false[/code] otherwise. Typically, [method _handles_file] is overridden as follows to allow the user to record a file at any path with a given file extension: Called when the engine determines whether this [MovieWriter] is able to handle the file at [param path]. Must return [code]true[/code] if this [MovieWriter] is able to handle the given file path, [code]false[/code] otherwise. Typically, [method _handles_file] is overridden as follows to allow the user to record a file at any path with a given file extension:
[codeblock] [codeblock]
func _handles_file(path): func _handles_file(path):
# Allows specifying an output file with a `.mkv` file extension (case-insensitive), # Allows specifying an output file with a `.mkv` file extension (case-insensitive),
# either in the Project Settings or with the `--write-movie &lt;path&gt;` command line argument. # either in the Project Settings or with the `--write-movie &lt;path&gt;` command line argument.
return path.get_extension().to_lower() == "mkv" return path.get_extension().to_lower() == "mkv"
[/codeblock] [/codeblock]
</description> </description>
</method> </method>

View File

@ -15,57 +15,57 @@
var base_multiplayer = SceneMultiplayer.new() var base_multiplayer = SceneMultiplayer.new()
func _init(): func _init():
# Just passthrough base signals (copied to var to avoid cyclic reference) # Just passthrough base signals (copied to var to avoid cyclic reference)
var cts = connected_to_server var cts = connected_to_server
var cf = connection_failed var cf = connection_failed
var sd = server_disconnected var sd = server_disconnected
var pc = peer_connected var pc = peer_connected
var pd = peer_disconnected var pd = peer_disconnected
base_multiplayer.connected_to_server.connect(func(): cts.emit()) base_multiplayer.connected_to_server.connect(func(): cts.emit())
base_multiplayer.connection_failed.connect(func(): cf.emit()) base_multiplayer.connection_failed.connect(func(): cf.emit())
base_multiplayer.server_disconnected.connect(func(): sd.emit()) base_multiplayer.server_disconnected.connect(func(): sd.emit())
base_multiplayer.peer_connected.connect(func(id): pc.emit(id)) base_multiplayer.peer_connected.connect(func(id): pc.emit(id))
base_multiplayer.peer_disconnected.connect(func(id): pd.emit(id)) base_multiplayer.peer_disconnected.connect(func(id): pd.emit(id))
func _poll(): func _poll():
return base_multiplayer.poll() return base_multiplayer.poll()
# Log RPC being made and forward it to the default multiplayer. # Log RPC being made and forward it to the default multiplayer.
func _rpc(peer: int, object: Object, method: StringName, args: Array) -&gt; Error: func _rpc(peer: int, object: Object, method: StringName, args: Array) -&gt; Error:
print("Got RPC for %d: %s::%s(%s)" % [peer, object, method, args]) print("Got RPC for %d: %s::%s(%s)" % [peer, object, method, args])
return base_multiplayer.rpc(peer, object, method, args) return base_multiplayer.rpc(peer, object, method, args)
# Log configuration add. E.g. root path (nullptr, NodePath), replication (Node, Spawner|Synchronizer), custom. # Log configuration add. E.g. root path (nullptr, NodePath), replication (Node, Spawner|Synchronizer), custom.
func _object_configuration_add(object, config: Variant) -&gt; Error: func _object_configuration_add(object, config: Variant) -&gt; Error:
if config is MultiplayerSynchronizer: if config is MultiplayerSynchronizer:
print("Adding synchronization configuration for %s. Synchronizer: %s" % [object, config]) print("Adding synchronization configuration for %s. Synchronizer: %s" % [object, config])
elif config is MultiplayerSpawner: elif config is MultiplayerSpawner:
print("Adding node %s to the spawn list. Spawner: %s" % [object, config]) print("Adding node %s to the spawn list. Spawner: %s" % [object, config])
return base_multiplayer.object_configuration_add(object, config) return base_multiplayer.object_configuration_add(object, config)
# Log configuration remove. E.g. root path (nullptr, NodePath), replication (Node, Spawner|Synchronizer), custom. # Log configuration remove. E.g. root path (nullptr, NodePath), replication (Node, Spawner|Synchronizer), custom.
func _object_configuration_remove(object, config: Variant) -&gt; Error: func _object_configuration_remove(object, config: Variant) -&gt; Error:
if config is MultiplayerSynchronizer: if config is MultiplayerSynchronizer:
print("Removing synchronization configuration for %s. Synchronizer: %s" % [object, config]) print("Removing synchronization configuration for %s. Synchronizer: %s" % [object, config])
elif config is MultiplayerSpawner: elif config is MultiplayerSpawner:
print("Removing node %s from the spawn list. Spawner: %s" % [object, config]) print("Removing node %s from the spawn list. Spawner: %s" % [object, config])
return base_multiplayer.object_configuration_remove(object, config) return base_multiplayer.object_configuration_remove(object, config)
# These can be optional, but in our case we want to extend SceneMultiplayer, so forward everything. # These can be optional, but in our case we want to extend SceneMultiplayer, so forward everything.
func _set_multiplayer_peer(p_peer: MultiplayerPeer): func _set_multiplayer_peer(p_peer: MultiplayerPeer):
base_multiplayer.multiplayer_peer = p_peer base_multiplayer.multiplayer_peer = p_peer
func _get_multiplayer_peer() -&gt; MultiplayerPeer: func _get_multiplayer_peer() -&gt; MultiplayerPeer:
return base_multiplayer.multiplayer_peer return base_multiplayer.multiplayer_peer
func _get_unique_id() -&gt; int: func _get_unique_id() -&gt; int:
return base_multiplayer.get_unique_id() return base_multiplayer.get_unique_id()
func _get_remote_sender_id() -&gt; int: func _get_remote_sender_id() -&gt; int:
return base_multiplayer.get_remote_sender_id() return base_multiplayer.get_remote_sender_id()
func _get_peer_ids() -&gt; PackedInt32Array: func _get_peer_ids() -&gt; PackedInt32Array:
return base_multiplayer.get_peers() return base_multiplayer.get_peers()
[/gdscript] [/gdscript]
[/codeblocks] [/codeblocks]
Then in your main scene or in an autoload call [method SceneTree.set_multiplayer] to start using your custom [MultiplayerAPI]: Then in your main scene or in an autoload call [method SceneTree.set_multiplayer] to start using your custom [MultiplayerAPI]:
@ -73,8 +73,8 @@
[gdscript] [gdscript]
# autoload.gd # autoload.gd
func _enter_tree(): func _enter_tree():
# Sets our custom multiplayer as the main one in SceneTree. # Sets our custom multiplayer as the main one in SceneTree.
get_tree().set_multiplayer(LogMultiplayer.new()) get_tree().set_multiplayer(LogMultiplayer.new())
[/gdscript] [/gdscript]
[/codeblocks] [/codeblocks]
Native extensions can alternatively use the [method MultiplayerAPI.set_default_interface] method during initialization to configure themselves as the default implementation. Native extensions can alternatively use the [method MultiplayerAPI.set_default_interface] method during initialization to configure themselves as the default implementation.

View File

@ -11,28 +11,28 @@
var menu var menu
func _menu_callback(item_id): func _menu_callback(item_id):
if item_id == "ITEM_CUT": if item_id == "ITEM_CUT":
cut() cut()
elif item_id == "ITEM_COPY": elif item_id == "ITEM_COPY":
copy() copy()
elif item_id == "ITEM_PASTE": elif item_id == "ITEM_PASTE":
paste() paste()
func _enter_tree(): func _enter_tree():
# Create new menu and add items: # Create new menu and add items:
menu = NativeMenu.create_menu() menu = NativeMenu.create_menu()
NativeMenu.add_item(menu, "Cut", _menu_callback, Callable(), "ITEM_CUT") NativeMenu.add_item(menu, "Cut", _menu_callback, Callable(), "ITEM_CUT")
NativeMenu.add_item(menu, "Copy", _menu_callback, Callable(), "ITEM_COPY") NativeMenu.add_item(menu, "Copy", _menu_callback, Callable(), "ITEM_COPY")
NativeMenu.add_separator(menu) NativeMenu.add_separator(menu)
NativeMenu.add_item(menu, "Paste", _menu_callback, Callable(), "ITEM_PASTE") NativeMenu.add_item(menu, "Paste", _menu_callback, Callable(), "ITEM_PASTE")
func _on_button_pressed(): func _on_button_pressed():
# Show popup menu at mouse position: # Show popup menu at mouse position:
NativeMenu.popup(menu, DisplayServer.mouse_get_position()) NativeMenu.popup(menu, DisplayServer.mouse_get_position())
func _exit_tree(): func _exit_tree():
# Remove menu when it's no longer needed: # Remove menu when it's no longer needed:
NativeMenu.free_menu(menu) NativeMenu.free_menu(menu)
[/codeblock] [/codeblock]
</description> </description>
<tutorials> <tutorials>

View File

@ -58,15 +58,15 @@
Call [method update_configuration_warnings] when the warnings need to be updated for this node. Call [method update_configuration_warnings] when the warnings need to be updated for this node.
[codeblock] [codeblock]
@export var energy = 0: @export var energy = 0:
set(value): set(value):
energy = value energy = value
update_configuration_warnings() update_configuration_warnings()
func _get_configuration_warnings(): func _get_configuration_warnings():
if energy &lt; 0: if energy &lt; 0:
return ["Energy must be 0 or greater."] return ["Energy must be 0 or greater."]
else: else:
return [] return []
[/codeblock] [/codeblock]
</description> </description>
</method> </method>
@ -168,14 +168,14 @@
[gdscript] [gdscript]
var child_node = get_child(0) var child_node = get_child(0)
if child_node.get_parent(): if child_node.get_parent():
child_node.get_parent().remove_child(child_node) child_node.get_parent().remove_child(child_node)
add_child(child_node) add_child(child_node)
[/gdscript] [/gdscript]
[csharp] [csharp]
Node childNode = GetChild(0); Node childNode = GetChild(0);
if (childNode.GetParent() != null) if (childNode.GetParent() != null)
{ {
childNode.GetParent().RemoveChild(childNode); childNode.GetParent().RemoveChild(childNode);
} }
AddChild(childNode); AddChild(childNode);
[/csharp] [/csharp]
@ -372,16 +372,16 @@
# Stores the node's non-internal groups only (as an array of StringNames). # Stores the node's non-internal groups only (as an array of StringNames).
var non_internal_groups = [] var non_internal_groups = []
for group in get_groups(): for group in get_groups():
if not str(group).begins_with("_"): if not str(group).begins_with("_"):
non_internal_groups.push_back(group) non_internal_groups.push_back(group)
[/gdscript] [/gdscript]
[csharp] [csharp]
// Stores the node's non-internal groups only (as a List of StringNames). // Stores the node's non-internal groups only (as a List of StringNames).
List&lt;string&gt; nonInternalGroups = new List&lt;string&gt;(); List&lt;string&gt; nonInternalGroups = new List&lt;string&gt;();
foreach (string group in GetGroups()) foreach (string group in GetGroups())
{ {
if (!group.BeginsWith("_")) if (!group.BeginsWith("_"))
nonInternalGroups.Add(group); nonInternalGroups.Add(group);
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -1300,10 +1300,10 @@
[b]Note:[/b] This notification is received alongside [constant NOTIFICATION_ENTER_TREE], so if you are instantiating a scene, the child nodes will not be initialized yet. You can use it to setup translations for this node, child nodes created from script, or if you want to access child nodes added in the editor, make sure the node is ready using [method is_node_ready]. [b]Note:[/b] This notification is received alongside [constant NOTIFICATION_ENTER_TREE], so if you are instantiating a scene, the child nodes will not be initialized yet. You can use it to setup translations for this node, child nodes created from script, or if you want to access child nodes added in the editor, make sure the node is ready using [method is_node_ready].
[codeblock] [codeblock]
func _notification(what): func _notification(what):
if what == NOTIFICATION_TRANSLATION_CHANGED: if what == NOTIFICATION_TRANSLATION_CHANGED:
if not is_node_ready(): if not is_node_ready():
await ready # Wait until ready signal. await ready # Wait until ready signal.
$Label.text = atr("%d Bananas") % banana_counter $Label.text = atr("%d Bananas") % banana_counter
[/codeblock] [/codeblock]
</constant> </constant>
<constant name="NOTIFICATION_WM_ABOUT" value="2011"> <constant name="NOTIFICATION_WM_ABOUT" value="2011">

View File

@ -196,29 +196,29 @@
[gdscript] [gdscript]
var arguments = {} var arguments = {}
for argument in OS.get_cmdline_args(): for argument in OS.get_cmdline_args():
if argument.contains("="): if argument.contains("="):
var key_value = argument.split("=") var key_value = argument.split("=")
arguments[key_value[0].trim_prefix("--")] = key_value[1] arguments[key_value[0].trim_prefix("--")] = key_value[1]
else: else:
# Options without an argument will be present in the dictionary, # Options without an argument will be present in the dictionary,
# with the value set to an empty string. # with the value set to an empty string.
arguments[argument.trim_prefix("--")] = "" arguments[argument.trim_prefix("--")] = ""
[/gdscript] [/gdscript]
[csharp] [csharp]
var arguments = new Dictionary&lt;string, string&gt;(); var arguments = new Dictionary&lt;string, string&gt;();
foreach (var argument in OS.GetCmdlineArgs()) foreach (var argument in OS.GetCmdlineArgs())
{ {
if (argument.Contains('=')) if (argument.Contains('='))
{ {
string[] keyValue = argument.Split("="); string[] keyValue = argument.Split("=");
arguments[keyValue[0].TrimPrefix("--")] = keyValue[1]; arguments[keyValue[0].TrimPrefix("--")] = keyValue[1];
} }
else else
{ {
// Options without an argument will be present in the dictionary, // Options without an argument will be present in the dictionary,
// with the value set to an empty string. // with the value set to an empty string.
arguments[argument.TrimPrefix("--")] = ""; arguments[argument.TrimPrefix("--")] = "";
} }
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -383,44 +383,44 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
match OS.get_name(): match OS.get_name():
"Windows": "Windows":
print("Welcome to Windows!") print("Welcome to Windows!")
"macOS": "macOS":
print("Welcome to macOS!") print("Welcome to macOS!")
"Linux", "FreeBSD", "NetBSD", "OpenBSD", "BSD": "Linux", "FreeBSD", "NetBSD", "OpenBSD", "BSD":
print("Welcome to Linux/BSD!") print("Welcome to Linux/BSD!")
"Android": "Android":
print("Welcome to Android!") print("Welcome to Android!")
"iOS": "iOS":
print("Welcome to iOS!") print("Welcome to iOS!")
"Web": "Web":
print("Welcome to the Web!") print("Welcome to the Web!")
[/gdscript] [/gdscript]
[csharp] [csharp]
switch (OS.GetName()) switch (OS.GetName())
{ {
case "Windows": case "Windows":
GD.Print("Welcome to Windows"); GD.Print("Welcome to Windows");
break; break;
case "macOS": case "macOS":
GD.Print("Welcome to macOS!"); GD.Print("Welcome to macOS!");
break; break;
case "Linux": case "Linux":
case "FreeBSD": case "FreeBSD":
case "NetBSD": case "NetBSD":
case "OpenBSD": case "OpenBSD":
case "BSD": case "BSD":
GD.Print("Welcome to Linux/BSD!"); GD.Print("Welcome to Linux/BSD!");
break; break;
case "Android": case "Android":
GD.Print("Welcome to Android!"); GD.Print("Welcome to Android!");
break; break;
case "iOS": case "iOS":
GD.Print("Welcome to iOS!"); GD.Print("Welcome to iOS!");
break; break;
case "Web": case "Web":
GD.Print("Welcome to the Web!"); GD.Print("Welcome to the Web!");
break; break;
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -39,36 +39,36 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _get(property): func _get(property):
if property == "fake_property": if property == "fake_property":
print("Getting my property!") print("Getting my property!")
return 4 return 4
func _get_property_list(): func _get_property_list():
return [ return [
{ "name": "fake_property", "type": TYPE_INT } { "name": "fake_property", "type": TYPE_INT }
] ]
[/gdscript] [/gdscript]
[csharp] [csharp]
public override Variant _Get(StringName property) public override Variant _Get(StringName property)
{ {
if (property == "FakeProperty") if (property == "FakeProperty")
{ {
GD.Print("Getting my property!"); GD.Print("Getting my property!");
return 4; return 4;
} }
return default; return default;
} }
public override Godot.Collections.Array&lt;Godot.Collections.Dictionary&gt; _GetPropertyList() public override Godot.Collections.Array&lt;Godot.Collections.Dictionary&gt; _GetPropertyList()
{ {
return return
[ [
new Godot.Collections.Dictionary() new Godot.Collections.Dictionary()
{ {
{ "name", "FakeProperty" }, { "name", "FakeProperty" },
{ "type", (int)Variant.Type.Int }, { "type", (int)Variant.Type.Int },
}, },
]; ];
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -87,98 +87,98 @@
extends Node extends Node
@export var number_count = 3: @export var number_count = 3:
set(nc): set(nc):
number_count = nc number_count = nc
numbers.resize(number_count) numbers.resize(number_count)
notify_property_list_changed() notify_property_list_changed()
var numbers = PackedInt32Array([0, 0, 0]) var numbers = PackedInt32Array([0, 0, 0])
func _get_property_list(): func _get_property_list():
var properties = [] var properties = []
for i in range(number_count): for i in range(number_count):
properties.append({ properties.append({
"name": "number_%d" % i, "name": "number_%d" % i,
"type": TYPE_INT, "type": TYPE_INT,
"hint": PROPERTY_HINT_ENUM, "hint": PROPERTY_HINT_ENUM,
"hint_string": "ZERO,ONE,TWO,THREE,FOUR,FIVE", "hint_string": "ZERO,ONE,TWO,THREE,FOUR,FIVE",
}) })
return properties return properties
func _get(property): func _get(property):
if property.begins_with("number_"): if property.begins_with("number_"):
var index = property.get_slice("_", 1).to_int() var index = property.get_slice("_", 1).to_int()
return numbers[index] return numbers[index]
func _set(property, value): func _set(property, value):
if property.begins_with("number_"): if property.begins_with("number_"):
var index = property.get_slice("_", 1).to_int() var index = property.get_slice("_", 1).to_int()
numbers[index] = value numbers[index] = value
return true return true
return false return false
[/gdscript] [/gdscript]
[csharp] [csharp]
[Tool] [Tool]
public partial class MyNode : Node public partial class MyNode : Node
{ {
private int _numberCount; private int _numberCount;
[Export] [Export]
public int NumberCount public int NumberCount
{ {
get =&gt; _numberCount; get =&gt; _numberCount;
set set
{ {
_numberCount = value; _numberCount = value;
_numbers.Resize(_numberCount); _numbers.Resize(_numberCount);
NotifyPropertyListChanged(); NotifyPropertyListChanged();
} }
} }
private Godot.Collections.Array&lt;int&gt; _numbers = []; private Godot.Collections.Array&lt;int&gt; _numbers = [];
public override Godot.Collections.Array&lt;Godot.Collections.Dictionary&gt; _GetPropertyList() public override Godot.Collections.Array&lt;Godot.Collections.Dictionary&gt; _GetPropertyList()
{ {
Godot.Collections.Array&lt;Godot.Collections.Dictionary&gt; properties = []; Godot.Collections.Array&lt;Godot.Collections.Dictionary&gt; properties = [];
for (int i = 0; i &lt; _numberCount; i++) for (int i = 0; i &lt; _numberCount; i++)
{ {
properties.Add(new Godot.Collections.Dictionary() properties.Add(new Godot.Collections.Dictionary()
{ {
{ "name", $"number_{i}" }, { "name", $"number_{i}" },
{ "type", (int)Variant.Type.Int }, { "type", (int)Variant.Type.Int },
{ "hint", (int)PropertyHint.Enum }, { "hint", (int)PropertyHint.Enum },
{ "hint_string", "Zero,One,Two,Three,Four,Five" }, { "hint_string", "Zero,One,Two,Three,Four,Five" },
}); });
} }
return properties; return properties;
} }
public override Variant _Get(StringName property) public override Variant _Get(StringName property)
{ {
string propertyName = property.ToString(); string propertyName = property.ToString();
if (propertyName.StartsWith("number_")) if (propertyName.StartsWith("number_"))
{ {
int index = int.Parse(propertyName.Substring("number_".Length)); int index = int.Parse(propertyName.Substring("number_".Length));
return _numbers[index]; return _numbers[index];
} }
return default; return default;
} }
public override bool _Set(StringName property, Variant value) public override bool _Set(StringName property, Variant value)
{ {
string propertyName = property.ToString(); string propertyName = property.ToString();
if (propertyName.StartsWith("number_")) if (propertyName.StartsWith("number_"))
{ {
int index = int.Parse(propertyName.Substring("number_".Length)); int index = int.Parse(propertyName.Substring("number_".Length));
_numbers[index] = value.As&lt;int&gt;(); _numbers[index] = value.As&lt;int&gt;();
return true; return true;
} }
return false; return false;
} }
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -208,29 +208,29 @@
Initializes the iterator. [param iter] stores the iteration state. Since GDScript does not support passing arguments by reference, a single-element array is used as a wrapper. Returns [code]true[/code] so long as the iterator has not reached the end. Initializes the iterator. [param iter] stores the iteration state. Since GDScript does not support passing arguments by reference, a single-element array is used as a wrapper. Returns [code]true[/code] so long as the iterator has not reached the end.
[codeblock] [codeblock]
class MyRange: class MyRange:
var _from var _from
var _to var _to
func _init(from, to): func _init(from, to):
assert(from &lt;= to) assert(from &lt;= to)
_from = from _from = from
_to = to _to = to
func _iter_init(iter): func _iter_init(iter):
iter[0] = _from iter[0] = _from
return iter[0] &lt; _to return iter[0] &lt; _to
func _iter_next(iter): func _iter_next(iter):
iter[0] += 1 iter[0] += 1
return iter[0] &lt; _to return iter[0] &lt; _to
func _iter_get(iter): func _iter_get(iter):
return iter return iter
func _ready(): func _ready():
var my_range = MyRange.new(2, 5) var my_range = MyRange.new(2, 5)
for x in my_range: for x in my_range:
print(x) # Prints 2, 3, 4. print(x) # Prints 2, 3, 4.
[/codeblock] [/codeblock]
[b]Note:[/b] Alternatively, you can ignore [param iter] and use the object's state instead, see [url=$DOCS_URL/tutorials/scripting/gdscript/gdscript_advanced.html#custom-iterators]online docs[/url] for an example. Note that in this case you will not be able to reuse the same iterator instance in nested loops. Also, make sure you reset the iterator state in this method if you want to reuse the same instance multiple times. [b]Note:[/b] Alternatively, you can ignore [param iter] and use the object's state instead, see [url=$DOCS_URL/tutorials/scripting/gdscript/gdscript_advanced.html#custom-iterators]online docs[/url] for an example. Note that in this case you will not be able to reuse the same iterator instance in nested loops. Also, make sure you reset the iterator state in this method if you want to reuse the same instance multiple times.
</description> </description>
@ -250,16 +250,16 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _notification(what): func _notification(what):
if what == NOTIFICATION_PREDELETE: if what == NOTIFICATION_PREDELETE:
print("Goodbye!") print("Goodbye!")
[/gdscript] [/gdscript]
[csharp] [csharp]
public override void _Notification(int what) public override void _Notification(int what)
{ {
if (what == NotificationPredelete) if (what == NotificationPredelete)
{ {
GD.Print("Goodbye!"); GD.Print("Goodbye!");
} }
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -294,42 +294,42 @@
var internal_data = {} var internal_data = {}
func _set(property, value): func _set(property, value):
if property == "fake_property": if property == "fake_property":
# Storing the value in the fake property. # Storing the value in the fake property.
internal_data["fake_property"] = value internal_data["fake_property"] = value
return true return true
return false return false
func _get_property_list(): func _get_property_list():
return [ return [
{ "name": "fake_property", "type": TYPE_INT } { "name": "fake_property", "type": TYPE_INT }
] ]
[/gdscript] [/gdscript]
[csharp] [csharp]
private Godot.Collections.Dictionary _internalData = new Godot.Collections.Dictionary(); private Godot.Collections.Dictionary _internalData = new Godot.Collections.Dictionary();
public override bool _Set(StringName property, Variant value) public override bool _Set(StringName property, Variant value)
{ {
if (property == "FakeProperty") if (property == "FakeProperty")
{ {
// Storing the value in the fake property. // Storing the value in the fake property.
_internalData["FakeProperty"] = value; _internalData["FakeProperty"] = value;
return true; return true;
} }
return false; return false;
} }
public override Godot.Collections.Array&lt;Godot.Collections.Dictionary&gt; _GetPropertyList() public override Godot.Collections.Array&lt;Godot.Collections.Dictionary&gt; _GetPropertyList()
{ {
return return
[ [
new Godot.Collections.Dictionary() new Godot.Collections.Dictionary()
{ {
{ "name", "FakeProperty" }, { "name", "FakeProperty" },
{ "type", (int)Variant.Type.Int }, { "type", (int)Variant.Type.Int },
}, },
]; ];
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -341,11 +341,11 @@
Override this method to customize the return value of [method to_string], and therefore the object's representation as a [String]. Override this method to customize the return value of [method to_string], and therefore the object's representation as a [String].
[codeblock] [codeblock]
func _to_string(): func _to_string():
return "Welcome to Godot 4!" return "Welcome to Godot 4!"
func _init(): func _init():
print(self) # Prints "Welcome to Godot 4!" print(self) # Prints "Welcome to Godot 4!"
var a = str(self) # a is "Welcome to Godot 4!" var a = str(self) # a is "Welcome to Godot 4!"
[/codeblock] [/codeblock]
</description> </description>
</method> </method>
@ -360,43 +360,43 @@
extends Node extends Node
@export var is_number_editable: bool: @export var is_number_editable: bool:
set(value): set(value):
is_number_editable = value is_number_editable = value
notify_property_list_changed() notify_property_list_changed()
@export var number: int @export var number: int
func _validate_property(property: Dictionary): func _validate_property(property: Dictionary):
if property.name == "number" and not is_number_editable: if property.name == "number" and not is_number_editable:
property.usage |= PROPERTY_USAGE_READ_ONLY property.usage |= PROPERTY_USAGE_READ_ONLY
[/gdscript] [/gdscript]
[csharp] [csharp]
[Tool] [Tool]
public partial class MyNode : Node public partial class MyNode : Node
{ {
private bool _isNumberEditable; private bool _isNumberEditable;
[Export] [Export]
public bool IsNumberEditable public bool IsNumberEditable
{ {
get =&gt; _isNumberEditable; get =&gt; _isNumberEditable;
set set
{ {
_isNumberEditable = value; _isNumberEditable = value;
NotifyPropertyListChanged(); NotifyPropertyListChanged();
} }
} }
[Export] [Export]
public int Number { get; set; } public int Number { get; set; }
public override void _ValidateProperty(Godot.Collections.Dictionary property) public override void _ValidateProperty(Godot.Collections.Dictionary property)
{ {
if (property["name"].AsStringName() == PropertyName.Number &amp;&amp; !IsNumberEditable) if (property["name"].AsStringName() == PropertyName.Number &amp;&amp; !IsNumberEditable)
{ {
var usage = property["usage"].As&lt;PropertyUsageFlags&gt;() | PropertyUsageFlags.ReadOnly; var usage = property["usage"].As&lt;PropertyUsageFlags&gt;() | PropertyUsageFlags.ReadOnly;
property["usage"] = (int)usage; property["usage"] = (int)usage;
} }
} }
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -411,23 +411,23 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
add_user_signal("hurt", [ add_user_signal("hurt", [
{ "name": "damage", "type": TYPE_INT }, { "name": "damage", "type": TYPE_INT },
{ "name": "source", "type": TYPE_OBJECT } { "name": "source", "type": TYPE_OBJECT }
]) ])
[/gdscript] [/gdscript]
[csharp] [csharp]
AddUserSignal("Hurt", AddUserSignal("Hurt",
[ [
new Godot.Collections.Dictionary() new Godot.Collections.Dictionary()
{ {
{ "name", "damage" }, { "name", "damage" },
{ "type", (int)Variant.Type.Int }, { "type", (int)Variant.Type.Int },
}, },
new Godot.Collections.Dictionary() new Godot.Collections.Dictionary()
{ {
{ "name", "source" }, { "name", "source" },
{ "type", (int)Variant.Type.Object }, { "type", (int)Variant.Type.Object },
}, },
]); ]);
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -15,7 +15,7 @@
[codeblock] [codeblock]
var container = load("packed_data.res") var container = load("packed_data.res")
for key in container: for key in container:
prints(key, container[key]) prints(key, container[key])
[/codeblock] [/codeblock]
Prints: Prints:
[codeblock lang=text] [codeblock lang=text]

View File

@ -10,11 +10,11 @@
packed.pack([1, 2, 3, ["nested1", "nested2"], 4, 5, 6]) packed.pack([1, 2, 3, ["nested1", "nested2"], 4, 5, 6])
for element in packed: for element in packed:
if element is PackedDataContainerRef: if element is PackedDataContainerRef:
for subelement in element: for subelement in element:
print("::", subelement) print("::", subelement)
else: else:
print(element) print(element)
[/codeblock] [/codeblock]
Prints: Prints:
[codeblock lang=text] [codeblock lang=text]

View File

@ -41,9 +41,9 @@
# Only `node` and `body` are now packed. # Only `node` and `body` are now packed.
var result = scene.pack(node) var result = scene.pack(node)
if result == OK: if result == OK:
var error = ResourceSaver.save(scene, "res://path/name.tscn") # Or "user://..." var error = ResourceSaver.save(scene, "res://path/name.tscn") # Or "user://..."
if error != OK: if error != OK:
push_error("An error occurred while saving the scene to disk.") push_error("An error occurred while saving the scene to disk.")
[/gdscript] [/gdscript]
[csharp] [csharp]
// Create the objects. // Create the objects.
@ -63,11 +63,11 @@
Error result = scene.Pack(node); Error result = scene.Pack(node);
if (result == Error.Ok) if (result == Error.Ok)
{ {
Error error = ResourceSaver.Save(scene, "res://path/name.tscn"); // Or "user://..." Error error = ResourceSaver.Save(scene, "res://path/name.tscn"); // Or "user://..."
if (error != Error.Ok) if (error != Error.Ok)
{ {
GD.PushError("An error occurred while saving the scene to disk."); GD.PushError("An error occurred while saving the scene to disk.");
} }
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -20,15 +20,15 @@
var peer var peer
func _ready(): func _ready():
peer = PacketPeerUDP.new() peer = PacketPeerUDP.new()
peer.bind(4433) peer.bind(4433)
func _process(_delta): func _process(_delta):
if peer.get_available_packet_count() &gt; 0: if peer.get_available_packet_count() &gt; 0:
var array_bytes = peer.get_packet() var array_bytes = peer.get_packet()
var packet_string = array_bytes.get_string_from_ascii() var packet_string = array_bytes.get_string_from_ascii()
print("Received message: ", packet_string) print("Received message: ", packet_string)
[/codeblock] [/codeblock]
[b]Note:[/b] When exporting to Android, make sure to enable the [code]INTERNET[/code] permission in the Android export preset before exporting the project or using one-click deploy. Otherwise, network communication of any kind will be blocked by Android. [b]Note:[/b] When exporting to Android, make sure to enable the [code]INTERNET[/code] permission in the Android export preset before exporting the project or using one-click deploy. Otherwise, network communication of any kind will be blocked by Android.
</description> </description>
@ -141,9 +141,9 @@
# Client # Client
while socket.wait() == OK: while socket.wait() == OK:
var data = socket.get_packet().get_string_from_ascii() var data = socket.get_packet().get_string_from_ascii()
if data == "Time to stop": if data == "Time to stop":
return return
[/gdscript] [/gdscript]
[csharp] [csharp]
var socket = new PacketPeerUdp(); var socket = new PacketPeerUdp();
@ -154,11 +154,11 @@
// Client // Client
while (socket.Wait() == OK) while (socket.Wait() == OK)
{ {
string data = socket.GetPacket().GetStringFromASCII(); string data = socket.GetPacket().GetStringFromASCII();
if (data == "Time to stop") if (data == "Time to stop")
{ {
return; return;
} }
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -23,47 +23,47 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _ready(): func _ready():
var monitor_value = Callable(self, "get_monitor_value") var monitor_value = Callable(self, "get_monitor_value")
# Adds monitor with name "MyName" to category "MyCategory". # Adds monitor with name "MyName" to category "MyCategory".
Performance.add_custom_monitor("MyCategory/MyMonitor", monitor_value) Performance.add_custom_monitor("MyCategory/MyMonitor", monitor_value)
# Adds monitor with name "MyName" to category "Custom". # Adds monitor with name "MyName" to category "Custom".
# Note: "MyCategory/MyMonitor" and "MyMonitor" have same name but different IDs, so the code is valid. # Note: "MyCategory/MyMonitor" and "MyMonitor" have same name but different IDs, so the code is valid.
Performance.add_custom_monitor("MyMonitor", monitor_value) Performance.add_custom_monitor("MyMonitor", monitor_value)
# Adds monitor with name "MyName" to category "Custom". # Adds monitor with name "MyName" to category "Custom".
# Note: "MyMonitor" and "Custom/MyMonitor" have same name and same category but different IDs, so the code is valid. # Note: "MyMonitor" and "Custom/MyMonitor" have same name and same category but different IDs, so the code is valid.
Performance.add_custom_monitor("Custom/MyMonitor", monitor_value) Performance.add_custom_monitor("Custom/MyMonitor", monitor_value)
# Adds monitor with name "MyCategoryOne/MyCategoryTwo/MyMonitor" to category "Custom". # Adds monitor with name "MyCategoryOne/MyCategoryTwo/MyMonitor" to category "Custom".
Performance.add_custom_monitor("MyCategoryOne/MyCategoryTwo/MyMonitor", monitor_value) Performance.add_custom_monitor("MyCategoryOne/MyCategoryTwo/MyMonitor", monitor_value)
func get_monitor_value(): func get_monitor_value():
return randi() % 25 return randi() % 25
[/gdscript] [/gdscript]
[csharp] [csharp]
public override void _Ready() public override void _Ready()
{ {
var monitorValue = new Callable(this, MethodName.GetMonitorValue); var monitorValue = new Callable(this, MethodName.GetMonitorValue);
// Adds monitor with name "MyName" to category "MyCategory". // Adds monitor with name "MyName" to category "MyCategory".
Performance.AddCustomMonitor("MyCategory/MyMonitor", monitorValue); Performance.AddCustomMonitor("MyCategory/MyMonitor", monitorValue);
// Adds monitor with name "MyName" to category "Custom". // Adds monitor with name "MyName" to category "Custom".
// Note: "MyCategory/MyMonitor" and "MyMonitor" have same name but different ids so the code is valid. // Note: "MyCategory/MyMonitor" and "MyMonitor" have same name but different ids so the code is valid.
Performance.AddCustomMonitor("MyMonitor", monitorValue); Performance.AddCustomMonitor("MyMonitor", monitorValue);
// Adds monitor with name "MyName" to category "Custom". // Adds monitor with name "MyName" to category "Custom".
// Note: "MyMonitor" and "Custom/MyMonitor" have same name and same category but different ids so the code is valid. // Note: "MyMonitor" and "Custom/MyMonitor" have same name and same category but different ids so the code is valid.
Performance.AddCustomMonitor("Custom/MyMonitor", monitorValue); Performance.AddCustomMonitor("Custom/MyMonitor", monitorValue);
// Adds monitor with name "MyCategoryOne/MyCategoryTwo/MyMonitor" to category "Custom". // Adds monitor with name "MyCategoryOne/MyCategoryTwo/MyMonitor" to category "Custom".
Performance.AddCustomMonitor("MyCategoryOne/MyCategoryTwo/MyMonitor", monitorValue); Performance.AddCustomMonitor("MyCategoryOne/MyCategoryTwo/MyMonitor", monitorValue);
} }
public int GetMonitorValue() public int GetMonitorValue()
{ {
return GD.Randi() % 25; return GD.Randi() % 25;
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -33,34 +33,34 @@
</member> </member>
<member name="shape_rid" type="RID" setter="set_shape_rid" getter="get_shape_rid" default="RID()"> <member name="shape_rid" type="RID" setter="set_shape_rid" getter="get_shape_rid" default="RID()">
The queried shape's [RID] that will be used for collision/intersection queries. Use this over [member shape] if you want to optimize for performance using the Servers API: The queried shape's [RID] that will be used for collision/intersection queries. Use this over [member shape] if you want to optimize for performance using the Servers API:
[codeblocks] [codeblocks]
[gdscript] [gdscript]
var shape_rid = PhysicsServer2D.circle_shape_create() var shape_rid = PhysicsServer2D.circle_shape_create()
var radius = 64 var radius = 64
PhysicsServer2D.shape_set_data(shape_rid, radius) PhysicsServer2D.shape_set_data(shape_rid, radius)
var params = PhysicsShapeQueryParameters2D.new() var params = PhysicsShapeQueryParameters2D.new()
params.shape_rid = shape_rid params.shape_rid = shape_rid
# Execute physics queries here... # Execute physics queries here...
# Release the shape when done with physics queries. # Release the shape when done with physics queries.
PhysicsServer2D.free_rid(shape_rid) PhysicsServer2D.free_rid(shape_rid)
[/gdscript] [/gdscript]
[csharp] [csharp]
RID shapeRid = PhysicsServer2D.CircleShapeCreate(); RID shapeRid = PhysicsServer2D.CircleShapeCreate();
int radius = 64; int radius = 64;
PhysicsServer2D.ShapeSetData(shapeRid, radius); PhysicsServer2D.ShapeSetData(shapeRid, radius);
var params = new PhysicsShapeQueryParameters2D(); var params = new PhysicsShapeQueryParameters2D();
params.ShapeRid = shapeRid; params.ShapeRid = shapeRid;
// Execute physics queries here... // Execute physics queries here...
// Release the shape when done with physics queries. // Release the shape when done with physics queries.
PhysicsServer2D.FreeRid(shapeRid); PhysicsServer2D.FreeRid(shapeRid);
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
</member> </member>
<member name="transform" type="Transform2D" setter="set_transform" getter="get_transform" default="Transform2D(1, 0, 0, 1, 0, 0)"> <member name="transform" type="Transform2D" setter="set_transform" getter="get_transform" default="Transform2D(1, 0, 0, 1, 0, 0)">
The queried shape's transform matrix. The queried shape's transform matrix.

View File

@ -33,34 +33,34 @@
</member> </member>
<member name="shape_rid" type="RID" setter="set_shape_rid" getter="get_shape_rid" default="RID()"> <member name="shape_rid" type="RID" setter="set_shape_rid" getter="get_shape_rid" default="RID()">
The queried shape's [RID] that will be used for collision/intersection queries. Use this over [member shape] if you want to optimize for performance using the Servers API: The queried shape's [RID] that will be used for collision/intersection queries. Use this over [member shape] if you want to optimize for performance using the Servers API:
[codeblocks] [codeblocks]
[gdscript] [gdscript]
var shape_rid = PhysicsServer3D.shape_create(PhysicsServer3D.SHAPE_SPHERE) var shape_rid = PhysicsServer3D.shape_create(PhysicsServer3D.SHAPE_SPHERE)
var radius = 2.0 var radius = 2.0
PhysicsServer3D.shape_set_data(shape_rid, radius) PhysicsServer3D.shape_set_data(shape_rid, radius)
var params = PhysicsShapeQueryParameters3D.new() var params = PhysicsShapeQueryParameters3D.new()
params.shape_rid = shape_rid params.shape_rid = shape_rid
# Execute physics queries here... # Execute physics queries here...
# Release the shape when done with physics queries. # Release the shape when done with physics queries.
PhysicsServer3D.free_rid(shape_rid) PhysicsServer3D.free_rid(shape_rid)
[/gdscript] [/gdscript]
[csharp] [csharp]
RID shapeRid = PhysicsServer3D.ShapeCreate(PhysicsServer3D.ShapeType.Sphere); RID shapeRid = PhysicsServer3D.ShapeCreate(PhysicsServer3D.ShapeType.Sphere);
float radius = 2.0f; float radius = 2.0f;
PhysicsServer3D.ShapeSetData(shapeRid, radius); PhysicsServer3D.ShapeSetData(shapeRid, radius);
var params = new PhysicsShapeQueryParameters3D(); var params = new PhysicsShapeQueryParameters3D();
params.ShapeRid = shapeRid; params.ShapeRid = shapeRid;
// Execute physics queries here... // Execute physics queries here...
// Release the shape when done with physics queries. // Release the shape when done with physics queries.
PhysicsServer3D.FreeRid(shapeRid); PhysicsServer3D.FreeRid(shapeRid);
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
</member> </member>
<member name="transform" type="Transform3D" setter="set_transform" getter="get_transform" default="Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)"> <member name="transform" type="Transform3D" setter="set_transform" getter="get_transform" default="Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)">
The queried shape's transform matrix. The queried shape's transform matrix.

View File

@ -56,9 +56,9 @@
var polygonPathFinder = new PolygonPathFinder(); var polygonPathFinder = new PolygonPathFinder();
Vector2[] points = Vector2[] points =
[ [
new Vector2(0.0f, 0.0f), new Vector2(0.0f, 0.0f),
new Vector2(1.0f, 0.0f), new Vector2(1.0f, 0.0f),
new Vector2(0.0f, 1.0f) new Vector2(0.0f, 1.0f)
]; ];
int[] connections = [0, 1, 1, 2, 2, 0]; int[] connections = [0, 1, 1, 2, 2, 0];
polygonPathFinder.Setup(points, connections); polygonPathFinder.Setup(points, connections);
@ -93,9 +93,9 @@
var polygonPathFinder = new PolygonPathFinder(); var polygonPathFinder = new PolygonPathFinder();
Vector2[] points = Vector2[] points =
[ [
new Vector2(0.0f, 0.0f), new Vector2(0.0f, 0.0f),
new Vector2(1.0f, 0.0f), new Vector2(1.0f, 0.0f),
new Vector2(0.0f, 1.0f) new Vector2(0.0f, 1.0f)
]; ];
int[] connections = [0, 1, 1, 2, 2, 0]; int[] connections = [0, 1, 1, 2, 2, 0];
polygonPathFinder.Setup(points, connections); polygonPathFinder.Setup(points, connections);

View File

@ -137,18 +137,18 @@
An [param id] can optionally be provided, as well as an accelerator ([param accel]). If no [param id] is provided, one will be created from the index. If no [param accel] is provided, then the default value of 0 (corresponding to [constant @GlobalScope.KEY_NONE]) will be assigned to the item (which means it won't have any accelerator). See [method get_item_accelerator] for more info on accelerators. An [param id] can optionally be provided, as well as an accelerator ([param accel]). If no [param id] is provided, one will be created from the index. If no [param accel] is provided, then the default value of 0 (corresponding to [constant @GlobalScope.KEY_NONE]) will be assigned to the item (which means it won't have any accelerator). See [method get_item_accelerator] for more info on accelerators.
[codeblock] [codeblock]
func _ready(): func _ready():
add_multistate_item("Item", 3, 0) add_multistate_item("Item", 3, 0)
index_pressed.connect(func(index: int): index_pressed.connect(func(index: int):
toggle_item_multistate(index) toggle_item_multistate(index)
match get_item_multistate(index): match get_item_multistate(index):
0: 0:
print("First state") print("First state")
1: 1:
print("Second state") print("Second state")
2: 2:
print("Third state") print("Third state")
) )
[/codeblock] [/codeblock]
[b]Note:[/b] Multistate items don't update their state automatically and must be done manually. See [method toggle_item_multistate], [method set_item_multistate] and [method get_item_multistate] for more info on how to control it. [b]Note:[/b] Multistate items don't update their state automatically and must be done manually. See [method toggle_item_multistate], [method set_item_multistate] and [method get_item_multistate] for more info on how to control it.
</description> </description>

View File

@ -29,10 +29,10 @@
ProjectSettings.set("category/property_name", 0) ProjectSettings.set("category/property_name", 0)
var property_info = { var property_info = {
"name": "category/property_name", "name": "category/property_name",
"type": TYPE_INT, "type": TYPE_INT,
"hint": PROPERTY_HINT_ENUM, "hint": PROPERTY_HINT_ENUM,
"hint_string": "one,two,three" "hint_string": "one,two,three"
} }
ProjectSettings.add_property_info(property_info) ProjectSettings.add_property_info(property_info)
@ -42,10 +42,10 @@
var propertyInfo = new Godot.Collections.Dictionary var propertyInfo = new Godot.Collections.Dictionary
{ {
{"name", "category/propertyName"}, {"name", "category/propertyName"},
{"type", (int)Variant.Type.Int}, {"type", (int)Variant.Type.Int},
{"hint", (int)PropertyHint.Enum}, {"hint", (int)PropertyHint.Enum},
{"hint_string", "one,two,three"}, {"hint_string", "one,two,three"},
}; };
ProjectSettings.AddPropertyInfo(propertyInfo); ProjectSettings.AddPropertyInfo(propertyInfo);
@ -133,15 +133,15 @@
[codeblock] [codeblock]
var path = "" var path = ""
if OS.has_feature("editor"): if OS.has_feature("editor"):
# Running from an editor binary. # Running from an editor binary.
# `path` will contain the absolute path to `hello.txt` located in the project root. # `path` will contain the absolute path to `hello.txt` located in the project root.
path = ProjectSettings.globalize_path("res://hello.txt") path = ProjectSettings.globalize_path("res://hello.txt")
else: else:
# Running from an exported project. # Running from an exported project.
# `path` will contain the absolute path to `hello.txt` next to the executable. # `path` will contain the absolute path to `hello.txt` next to the executable.
# This is *not* identical to using `ProjectSettings.globalize_path()` with a `res://` path, # This is *not* identical to using `ProjectSettings.globalize_path()` with a `res://` path,
# but is close enough in spirit. # but is close enough in spirit.
path = OS.get_executable_path().get_base_dir().path_join("hello.txt") path = OS.get_executable_path().get_base_dir().path_join("hello.txt")
[/codeblock] [/codeblock]
</description> </description>
</method> </method>
@ -215,10 +215,10 @@
const SETTING_DEFAULT = 10.0 const SETTING_DEFAULT = 10.0
func _enter_tree(): func _enter_tree():
if not ProjectSettings.has_setting(SETTING_NAME): if not ProjectSettings.has_setting(SETTING_NAME):
ProjectSettings.set_setting(SETTING_NAME, SETTING_DEFAULT) ProjectSettings.set_setting(SETTING_NAME, SETTING_DEFAULT)
ProjectSettings.set_initial_value(SETTING_NAME, SETTING_DEFAULT) ProjectSettings.set_initial_value(SETTING_NAME, SETTING_DEFAULT)
[/codeblock] [/codeblock]
If you have a project setting defined by an [EditorPlugin], but want to use it in a running project, you will need a similar code at runtime. If you have a project setting defined by an [EditorPlugin], but want to use it in a running project, you will need a similar code at runtime.
</description> </description>

View File

@ -72,12 +72,12 @@
@export var curve: Curve @export var curve: Curve
func _ready(): func _ready():
var tween = create_tween() var tween = create_tween()
# Interpolate the value using a custom curve. # Interpolate the value using a custom curve.
tween.tween_property(self, "position:x", 300, 1).as_relative().set_custom_interpolator(tween_curve) tween.tween_property(self, "position:x", 300, 1).as_relative().set_custom_interpolator(tween_curve)
func tween_curve(v): func tween_curve(v):
return curve.sample_baked(v) return curve.sample_baked(v)
[/gdscript] [/gdscript]
[csharp] [csharp]
[Export] [Export]
@ -85,15 +85,15 @@
public override void _Ready() public override void _Ready()
{ {
Tween tween = CreateTween(); Tween tween = CreateTween();
// Interpolate the value using a custom curve. // Interpolate the value using a custom curve.
Callable tweenCurveCallable = Callable.From&lt;float, float&gt;(TweenCurve); Callable tweenCurveCallable = Callable.From&lt;float, float&gt;(TweenCurve);
tween.TweenProperty(this, "position:x", 300.0f, 1.0f).AsRelative().SetCustomInterpolator(tweenCurveCallable); tween.TweenProperty(this, "position:x", 300.0f, 1.0f).AsRelative().SetCustomInterpolator(tweenCurveCallable);
} }
private float TweenCurve(float value) private float TweenCurve(float value)
{ {
return Curve.SampleBaked(value); return Curve.SampleBaked(value);
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -10,7 +10,7 @@
[codeblock] [codeblock]
var rng = RandomNumberGenerator.new() var rng = RandomNumberGenerator.new()
func _ready(): func _ready():
var my_random_number = rng.randf_range(-10.0, 10.0) var my_random_number = rng.randf_range(-10.0, 10.0)
[/codeblock] [/codeblock]
</description> </description>
<tutorials> <tutorials>

View File

@ -73,7 +73,7 @@
[b]Note:[/b] Downloading large buffers can have a prohibitive cost for real-time even when using the asynchronous method due to hardware bandwidth limitations. When dealing with large resources, you can adjust settings such as [member ProjectSettings.rendering/rendering_device/staging_buffer/block_size_kb] to improve the transfer speed at the cost of extra memory. [b]Note:[/b] Downloading large buffers can have a prohibitive cost for real-time even when using the asynchronous method due to hardware bandwidth limitations. When dealing with large resources, you can adjust settings such as [member ProjectSettings.rendering/rendering_device/staging_buffer/block_size_kb] to improve the transfer speed at the cost of extra memory.
[codeblock] [codeblock]
func _buffer_get_data_callback(array): func _buffer_get_data_callback(array):
value = array.decode_u32(0) value = array.decode_u32(0)
... ...
@ -132,9 +132,9 @@
rd.compute_list_bind_uniform_set(compute_list, dilate_uniform_set, 1) rd.compute_list_bind_uniform_set(compute_list, dilate_uniform_set, 1)
for i in atlas_slices: for i in atlas_slices:
rd.compute_list_set_push_constant(compute_list, push_constant, push_constant.size()) rd.compute_list_set_push_constant(compute_list, push_constant, push_constant.size())
rd.compute_list_dispatch(compute_list, group_size.x, group_size.y, group_size.z) rd.compute_list_dispatch(compute_list, group_size.x, group_size.y, group_size.z)
# No barrier, let them run all together. # No barrier, let them run all together.
rd.compute_list_end() rd.compute_list_end()
[/codeblock] [/codeblock]
@ -981,7 +981,7 @@
[b]Note:[/b] Downloading large textures can have a prohibitive cost for real-time even when using the asynchronous method due to hardware bandwidth limitations. When dealing with large resources, you can adjust settings such as [member ProjectSettings.rendering/rendering_device/staging_buffer/texture_download_region_size_px] and [member ProjectSettings.rendering/rendering_device/staging_buffer/block_size_kb] to improve the transfer speed at the cost of extra memory. [b]Note:[/b] Downloading large textures can have a prohibitive cost for real-time even when using the asynchronous method due to hardware bandwidth limitations. When dealing with large resources, you can adjust settings such as [member ProjectSettings.rendering/rendering_device/staging_buffer/texture_download_region_size_px] and [member ProjectSettings.rendering/rendering_device/staging_buffer/block_size_kb] to improve the transfer speed at the cost of extra memory.
[codeblock] [codeblock]
func _texture_get_data_callback(array): func _texture_get_data_callback(array):
value = array.decode_u32(0) value = array.decode_u32(0)
... ...
@ -2101,8 +2101,8 @@
rd = RenderingServer.get_rendering_device() rd = RenderingServer.get_rendering_device()
if rd.has_feature(RenderingDevice.SUPPORTS_BUFFER_DEVICE_ADDRESS): if rd.has_feature(RenderingDevice.SUPPORTS_BUFFER_DEVICE_ADDRESS):
storage_buffer = rd.storage_buffer_create(bytes.size(), bytes, RenderingDevice.STORAGE_BUFFER_USAGE_SHADER_DEVICE_ADDRESS): storage_buffer = rd.storage_buffer_create(bytes.size(), bytes, RenderingDevice.STORAGE_BUFFER_USAGE_SHADER_DEVICE_ADDRESS)
storage_buffer_address = rd.buffer_get_device_address(storage_buffer) storage_buffer_address = rd.buffer_get_device_address(storage_buffer)
[/gdscript] [/gdscript]
[/codeblocks] [/codeblocks]
</constant> </constant>
@ -2164,7 +2164,7 @@
</constant> </constant>
<constant name="RENDER_PRIMITIVE_TRIANGLES_WITH_ADJACENCY" value="6" enum="RenderPrimitive"> <constant name="RENDER_PRIMITIVE_TRIANGLES_WITH_ADJACENCY" value="6" enum="RenderPrimitive">
[url=https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#drawing-triangle-lists-with-adjacency]Triangle list rendering primitive with adjacency.[/url] [url=https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#drawing-triangle-lists-with-adjacency]Triangle list rendering primitive with adjacency.[/url]
[b]Note:[/b] Adjacency is only useful with geometry shaders, which Godot does not expose. [b]Note:[/b] Adjacency is only useful with geometry shaders, which Godot does not expose.
</constant> </constant>
<constant name="RENDER_PRIMITIVE_TRIANGLE_STRIPS" value="7" enum="RenderPrimitive"> <constant name="RENDER_PRIMITIVE_TRIANGLE_STRIPS" value="7" enum="RenderPrimitive">
Triangle strip rendering primitive. Triangles drawn are connected to the previous triangle. Triangle strip rendering primitive. Triangles drawn are connected to the previous triangle.

View File

@ -93,12 +93,12 @@
The normalization factor can be calculated from exposure value (EV100) as follows: The normalization factor can be calculated from exposure value (EV100) as follows:
[codeblock] [codeblock]
func get_exposure_normalization(ev100: float): func get_exposure_normalization(ev100: float):
return 1.0 / (pow(2.0, ev100) * 1.2) return 1.0 / (pow(2.0, ev100) * 1.2)
[/codeblock] [/codeblock]
The exposure value can be calculated from aperture (in f-stops), shutter speed (in seconds), and sensitivity (in ISO) as follows: The exposure value can be calculated from aperture (in f-stops), shutter speed (in seconds), and sensitivity (in ISO) as follows:
[codeblock] [codeblock]
func get_exposure(aperture: float, shutter_speed: float, sensitivity: float): func get_exposure(aperture: float, shutter_speed: float, sensitivity: float):
return log((aperture * aperture) / shutter_speed * (100.0 / sensitivity)) / log(2) return log((aperture * aperture) / shutter_speed * (100.0 / sensitivity)) / log(2)
[/codeblock] [/codeblock]
</description> </description>
</method> </method>
@ -1634,10 +1634,10 @@
[b]Note:[/b] Rendering information is not available until at least 2 frames have been rendered by the engine. If rendering information is not available, [method get_rendering_info] returns [code]0[/code]. To print rendering information in [code]_ready()[/code] successfully, use the following: [b]Note:[/b] Rendering information is not available until at least 2 frames have been rendered by the engine. If rendering information is not available, [method get_rendering_info] returns [code]0[/code]. To print rendering information in [code]_ready()[/code] successfully, use the following:
[codeblock] [codeblock]
func _ready(): func _ready():
for _i in 2: for _i in 2:
await get_tree().process_frame await get_tree().process_frame
print(RenderingServer.get_rendering_info(RENDERING_INFO_TOTAL_DRAW_CALLS_IN_FRAME)) print(RenderingServer.get_rendering_info(RENDERING_INFO_TOTAL_DRAW_CALLS_IN_FRAME))
[/codeblock] [/codeblock]
</description> </description>
</method> </method>
@ -3858,8 +3858,8 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _ready(): func _ready():
RenderingServer.viewport_attach_to_screen(get_viewport().get_viewport_rid(), Rect2()) RenderingServer.viewport_attach_to_screen(get_viewport().get_viewport_rid(), Rect2())
RenderingServer.viewport_attach_to_screen($Viewport.get_viewport_rid(), Rect2(0, 0, 600, 600)) RenderingServer.viewport_attach_to_screen($Viewport.get_viewport_rid(), Rect2(0, 0, 600, 600))
[/gdscript] [/gdscript]
[/codeblocks] [/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 further optimization, see [method viewport_set_render_direct_to_screen]. 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 further optimization, see [method viewport_set_render_direct_to_screen].
@ -3901,14 +3901,14 @@
[b]Note:[/b] Viewport rendering information is not available until at least 2 frames have been rendered by the engine. If rendering information is not available, [method viewport_get_render_info] returns [code]0[/code]. To print rendering information in [code]_ready()[/code] successfully, use the following: [b]Note:[/b] Viewport rendering information is not available until at least 2 frames have been rendered by the engine. If rendering information is not available, [method viewport_get_render_info] returns [code]0[/code]. To print rendering information in [code]_ready()[/code] successfully, use the following:
[codeblock] [codeblock]
func _ready(): func _ready():
for _i in 2: for _i in 2:
await get_tree().process_frame await get_tree().process_frame
print( print(
RenderingServer.viewport_get_render_info(get_viewport().get_viewport_rid(), RenderingServer.viewport_get_render_info(get_viewport().get_viewport_rid(),
RenderingServer.VIEWPORT_RENDER_INFO_TYPE_VISIBLE, RenderingServer.VIEWPORT_RENDER_INFO_TYPE_VISIBLE,
RenderingServer.VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME) RenderingServer.VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME)
) )
[/codeblock] [/codeblock]
</description> </description>
</method> </method>

View File

@ -44,7 +44,7 @@
var damage = 0 var damage = 0
func _setup_local_to_scene(): func _setup_local_to_scene():
damage = randi_range(10, 40) damage = randi_range(10, 40)
[/codeblock] [/codeblock]
</description> </description>
</method> </method>
@ -77,10 +77,10 @@
[b]Note:[/b] For custom resources, it's recommended to call this method whenever a meaningful change occurs, such as a modified property. This ensures that custom [Object]s depending on the resource are properly updated. [b]Note:[/b] For custom resources, it's recommended to call this method whenever a meaningful change occurs, such as a modified property. This ensures that custom [Object]s depending on the resource are properly updated.
[codeblock] [codeblock]
var damage: var damage:
set(new_value): set(new_value):
if damage != new_value: if damage != new_value:
damage = new_value damage = new_value
emit_changed() emit_changed()
[/codeblock] [/codeblock]
</description> </description>
</method> </method>

View File

@ -17,13 +17,13 @@
Called when the engine compilation profile editor wants to check what build options an imported resource needs. For example, [ResourceImporterDynamicFont] has a property called [member ResourceImporterDynamicFont.multichannel_signed_distance_field], that depends on the engine to be build with the "msdfgen" module. If that resource happened to be a custom one, it would be handled like this: Called when the engine compilation profile editor wants to check what build options an imported resource needs. For example, [ResourceImporterDynamicFont] has a property called [member ResourceImporterDynamicFont.multichannel_signed_distance_field], that depends on the engine to be build with the "msdfgen" module. If that resource happened to be a custom one, it would be handled like this:
[codeblock] [codeblock]
func _get_build_dependencies(path): func _get_build_dependencies(path):
var resource = load(path) var resource = load(path)
var dependencies = PackedStringArray() var dependencies = PackedStringArray()
if resource.multichannel_signed_distance_field: if resource.multichannel_signed_distance_field:
dependencies.push_back("module_msdfgen_enabled") dependencies.push_back("module_msdfgen_enabled")
return dependencies return dependencies
[/codeblock] [/codeblock]
</description> </description>
</method> </method>

View File

@ -48,8 +48,8 @@
[b]Note:[/b] The dependencies are returned with slices separated by [code]::[/code]. You can use [method String.get_slice] to get their components. [b]Note:[/b] The dependencies are returned with slices separated by [code]::[/code]. You can use [method String.get_slice] to get their components.
[codeblock] [codeblock]
for dependency in ResourceLoader.get_dependencies(path): for dependency in ResourceLoader.get_dependencies(path):
print(dependency.get_slice("::", 0)) # Prints the UID. print(dependency.get_slice("::", 0)) # Prints the UID.
print(dependency.get_slice("::", 2)) # Prints the path. print(dependency.get_slice("::", 2)) # Prints the path.
[/codeblock] [/codeblock]
</description> </description>
</method> </method>

View File

@ -147,38 +147,38 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _ready(): func _ready():
var menu = get_menu() var menu = get_menu()
# Remove "Select All" item. # Remove "Select All" item.
menu.remove_item(MENU_SELECT_ALL) menu.remove_item(MENU_SELECT_ALL)
# Add custom items. # Add custom items.
menu.add_separator() menu.add_separator()
menu.add_item("Duplicate Text", MENU_MAX + 1) menu.add_item("Duplicate Text", MENU_MAX + 1)
# Connect callback. # Connect callback.
menu.id_pressed.connect(_on_item_pressed) menu.id_pressed.connect(_on_item_pressed)
func _on_item_pressed(id): func _on_item_pressed(id):
if id == MENU_MAX + 1: if id == MENU_MAX + 1:
add_text("\n" + get_parsed_text()) add_text("\n" + get_parsed_text())
[/gdscript] [/gdscript]
[csharp] [csharp]
public override void _Ready() public override void _Ready()
{ {
var menu = GetMenu(); var menu = GetMenu();
// Remove "Select All" item. // Remove "Select All" item.
menu.RemoveItem(RichTextLabel.MenuItems.SelectAll); menu.RemoveItem(RichTextLabel.MenuItems.SelectAll);
// Add custom items. // Add custom items.
menu.AddSeparator(); menu.AddSeparator();
menu.AddItem("Duplicate Text", RichTextLabel.MenuItems.Max + 1); menu.AddItem("Duplicate Text", RichTextLabel.MenuItems.Max + 1);
// Add event handler. // Add event handler.
menu.IdPressed += OnItemPressed; menu.IdPressed += OnItemPressed;
} }
public void OnItemPressed(int id) public void OnItemPressed(int id)
{ {
if (id == TextEdit.MenuItems.Max + 1) if (id == TextEdit.MenuItems.Max + 1)
{ {
AddText("\n" + GetParsedText()); AddText("\n" + GetParsedText());
} }
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -277,10 +277,10 @@
extends RichTextLabel extends RichTextLabel
func _ready(): func _ready():
install_effect(MyCustomEffect.new()) install_effect(MyCustomEffect.new())
# Alternatively, if not using `class_name` in the script that extends RichTextEffect: # Alternatively, if not using `class_name` in the script that extends RichTextEffect:
install_effect(preload("res://effect.gd").new()) install_effect(preload("res://effect.gd").new())
[/codeblock] [/codeblock]
</description> </description>
</method> </method>
@ -773,8 +773,8 @@
# This assumes RichTextLabel's `meta_clicked` signal was connected to # This assumes RichTextLabel's `meta_clicked` signal was connected to
# the function below using the signal connection dialog. # the function below using the signal connection dialog.
func _richtextlabel_on_meta_clicked(meta): func _richtextlabel_on_meta_clicked(meta):
# `meta` is of Variant type, so convert it to a String to avoid script errors at run-time. # `meta` is of Variant type, so convert it to a String to avoid script errors at run-time.
OS.shell_open(str(meta)) OS.shell_open(str(meta))
[/gdscript] [/gdscript]
[/codeblocks] [/codeblocks]
</description> </description>

View File

@ -183,19 +183,19 @@
@onready var ball = $Ball @onready var ball = $Ball
func get_ball_inertia(): func get_ball_inertia():
return 1.0 / PhysicsServer2D.body_get_direct_state(ball.get_rid()).inverse_inertia return 1.0 / PhysicsServer2D.body_get_direct_state(ball.get_rid()).inverse_inertia
[/gdscript] [/gdscript]
[csharp] [csharp]
private RigidBody2D _ball; private RigidBody2D _ball;
public override void _Ready() public override void _Ready()
{ {
_ball = GetNode&lt;RigidBody2D&gt;("Ball"); _ball = GetNode&lt;RigidBody2D&gt;("Ball");
} }
private float GetBallInertia() private float GetBallInertia()
{ {
return 1.0f / PhysicsServer2D.BodyGetDirectState(_ball.GetRid()).InverseInertia; return 1.0f / PhysicsServer2D.BodyGetDirectState(_ball.GetRid()).InverseInertia;
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -190,19 +190,19 @@
@onready var ball = $Ball @onready var ball = $Ball
func get_ball_inertia(): func get_ball_inertia():
return PhysicsServer3D.body_get_direct_state(ball.get_rid()).inverse_inertia.inverse() return PhysicsServer3D.body_get_direct_state(ball.get_rid()).inverse_inertia.inverse()
[/gdscript] [/gdscript]
[csharp] [csharp]
private RigidBody3D _ball; private RigidBody3D _ball;
public override void _Ready() public override void _Ready()
{ {
_ball = GetNode&lt;RigidBody3D&gt;("Ball"); _ball = GetNode&lt;RigidBody3D&gt;("Ball");
} }
private Vector3 GetBallInertia() private Vector3 GetBallInertia()
{ {
return PhysicsServer3D.BodyGetDirectState(_ball.GetRid()).InverseInertia.Inverse(); return PhysicsServer3D.BodyGetDirectState(_ball.GetRid()).InverseInertia.Inverse();
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -33,8 +33,8 @@
[codeblock] [codeblock]
# Calls "hide" to all nodes of the "enemies" group, at the end of the frame and in reverse tree order. # Calls "hide" to all nodes of the "enemies" group, at the end of the frame and in reverse tree order.
get_tree().call_group_flags( get_tree().call_group_flags(
SceneTree.GROUP_CALL_DEFERRED | SceneTree.GROUP_CALL_REVERSE, SceneTree.GROUP_CALL_DEFERRED | SceneTree.GROUP_CALL_REVERSE,
"enemies", "hide") "enemies", "hide")
[/codeblock] [/codeblock]
[b]Note:[/b] In C#, [param method] must be in snake_case when referring to built-in Godot methods. Prefer using the names exposed in the [code]MethodName[/code] class to avoid allocating a new [StringName] on each call. [b]Note:[/b] In C#, [param method] must be in snake_case when referring to built-in Godot methods. Prefer using the names exposed in the [code]MethodName[/code] class to avoid allocating a new [StringName] on each call.
</description> </description>
@ -76,16 +76,16 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func some_function(): func some_function():
print("start") print("start")
await get_tree().create_timer(1.0).timeout await get_tree().create_timer(1.0).timeout
print("end") print("end")
[/gdscript] [/gdscript]
[csharp] [csharp]
public async Task SomeFunction() public async Task SomeFunction()
{ {
GD.Print("start"); GD.Print("start");
await ToSignal(GetTree().CreateTimer(1.0f), SceneTreeTimer.SignalName.Timeout); await ToSignal(GetTree().CreateTimer(1.0f), SceneTreeTimer.SignalName.Timeout);
GD.Print("end"); GD.Print("end");
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -9,16 +9,16 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func some_function(): func some_function():
print("Timer started.") print("Timer started.")
await get_tree().create_timer(1.0).timeout await get_tree().create_timer(1.0).timeout
print("Timer ended.") print("Timer ended.")
[/gdscript] [/gdscript]
[csharp] [csharp]
public async Task SomeFunction() public async Task SomeFunction()
{ {
GD.Print("Timer started."); GD.Print("Timer started.");
await ToSignal(GetTree().CreateTimer(1.0f), SceneTreeTimer.SignalName.Timeout); await ToSignal(GetTree().CreateTimer(1.0f), SceneTreeTimer.SignalName.Timeout);
GD.Print("Timer ended."); GD.Print("Timer ended.");
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -8,18 +8,18 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _ready(): func _ready():
var dialog = ScriptCreateDialog.new(); var dialog = ScriptCreateDialog.new();
dialog.config("Node", "res://new_node.gd") # For in-engine types. 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.config("\"res://base_node.gd\"", "res://derived_node.gd") # For script types.
dialog.popup_centered() dialog.popup_centered()
[/gdscript] [/gdscript]
[csharp] [csharp]
public override void _Ready() public override void _Ready()
{ {
var dialog = new ScriptCreateDialog(); var dialog = new ScriptCreateDialog();
dialog.Config("Node", "res://NewNode.cs"); // For in-engine types. dialog.Config("Node", "res://NewNode.cs"); // For in-engine types.
dialog.Config("\"res://BaseNode.cs\"", "res://DerivedNode.cs"); // For script types. dialog.Config("\"res://BaseNode.cs\"", "res://DerivedNode.cs"); // For script types.
dialog.PopupCentered(); dialog.PopupCentered();
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -57,7 +57,7 @@
[b]Note:[/b] If you are setting this value in the [method Node._ready] function or earlier, it needs to be wrapped with [method Object.set_deferred], since scroll bar's [member Range.max_value] is not initialized yet. [b]Note:[/b] If you are setting this value in the [method Node._ready] function or earlier, it needs to be wrapped with [method Object.set_deferred], since scroll bar's [member Range.max_value] is not initialized yet.
[codeblock] [codeblock]
func _ready(): func _ready():
set_deferred("scroll_horizontal", 600) set_deferred("scroll_horizontal", 600)
[/codeblock] [/codeblock]
</member> </member>
<member name="scroll_horizontal_custom_step" type="float" setter="set_horizontal_custom_step" getter="get_horizontal_custom_step" default="-1.0"> <member name="scroll_horizontal_custom_step" type="float" setter="set_horizontal_custom_step" getter="get_horizontal_custom_step" default="-1.0">
@ -68,7 +68,7 @@
[b]Note:[/b] Setting it early needs to be deferred, just like in [member scroll_horizontal]. [b]Note:[/b] Setting it early needs to be deferred, just like in [member scroll_horizontal].
[codeblock] [codeblock]
func _ready(): func _ready():
set_deferred("scroll_vertical", 600) set_deferred("scroll_vertical", 600)
[/codeblock] [/codeblock]
</member> </member>
<member name="scroll_vertical_custom_step" type="float" setter="set_vertical_custom_step" getter="get_vertical_custom_step" default="-1.0"> <member name="scroll_vertical_custom_step" type="float" setter="set_vertical_custom_step" getter="get_vertical_custom_step" default="-1.0">

View File

@ -28,44 +28,44 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _ready(): func _ready():
var button = Button.new() var button = Button.new()
# `button_down` here is a Signal Variant type. We therefore call the Signal.connect() method, not Object.connect(). # `button_down` here is a Signal Variant type. We therefore call the Signal.connect() method, not Object.connect().
# See discussion below for a more in-depth overview of the API. # See discussion below for a more in-depth overview of the API.
button.button_down.connect(_on_button_down) button.button_down.connect(_on_button_down)
# This assumes that a `Player` class exists, which defines a `hit` signal. # This assumes that a `Player` class exists, which defines a `hit` signal.
var player = Player.new() var player = Player.new()
# We use Signal.connect() again, and we also use the Callable.bind() method, # We use Signal.connect() again, and we also use the Callable.bind() method,
# which returns a new Callable with the parameter binds. # which returns a new Callable with the parameter binds.
player.hit.connect(_on_player_hit.bind("sword", 100)) player.hit.connect(_on_player_hit.bind("sword", 100))
func _on_button_down(): func _on_button_down():
print("Button down!") print("Button down!")
func _on_player_hit(weapon_type, damage): func _on_player_hit(weapon_type, damage):
print("Hit with weapon %s for %d damage." % [weapon_type, damage]) print("Hit with weapon %s for %d damage." % [weapon_type, damage])
[/gdscript] [/gdscript]
[csharp] [csharp]
public override void _Ready() public override void _Ready()
{ {
var button = new Button(); var button = new Button();
// C# supports passing signals as events, so we can use this idiomatic construct: // C# supports passing signals as events, so we can use this idiomatic construct:
button.ButtonDown += OnButtonDown; button.ButtonDown += OnButtonDown;
// This assumes that a `Player` class exists, which defines a `Hit` signal. // This assumes that a `Player` class exists, which defines a `Hit` signal.
var player = new Player(); var player = new Player();
// We can use lambdas when we need to bind additional parameters. // We can use lambdas when we need to bind additional parameters.
player.Hit += () =&gt; OnPlayerHit("sword", 100); player.Hit += () =&gt; OnPlayerHit("sword", 100);
} }
private void OnButtonDown() private void OnButtonDown()
{ {
GD.Print("Button down!"); GD.Print("Button down!");
} }
private void OnPlayerHit(string weaponType, int damage) private void OnPlayerHit(string weaponType, int damage)
{ {
GD.Print($"Hit with weapon {weaponType} for {damage} damage."); GD.Print($"Hit with weapon {weaponType} for {damage} damage.");
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -74,34 +74,34 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _ready(): func _ready():
var button = Button.new() var button = Button.new()
# Option 1: Object.connect() with an implicit Callable for the defined function. # Option 1: Object.connect() with an implicit Callable for the defined function.
button.connect("button_down", _on_button_down) button.connect("button_down", _on_button_down)
# Option 2: Object.connect() with a constructed Callable using a target object and method name. # Option 2: Object.connect() with a constructed Callable using a target object and method name.
button.connect("button_down", Callable(self, "_on_button_down")) button.connect("button_down", Callable(self, "_on_button_down"))
# Option 3: Signal.connect() with an implicit Callable for the defined function. # Option 3: Signal.connect() with an implicit Callable for the defined function.
button.button_down.connect(_on_button_down) button.button_down.connect(_on_button_down)
# Option 4: Signal.connect() with a constructed Callable using a target object and method name. # Option 4: Signal.connect() with a constructed Callable using a target object and method name.
button.button_down.connect(Callable(self, "_on_button_down")) button.button_down.connect(Callable(self, "_on_button_down"))
func _on_button_down(): func _on_button_down():
print("Button down!") print("Button down!")
[/gdscript] [/gdscript]
[csharp] [csharp]
public override void _Ready() public override void _Ready()
{ {
var button = new Button(); var button = new Button();
// Option 1: In C#, we can use signals as events and connect with this idiomatic syntax: // Option 1: In C#, we can use signals as events and connect with this idiomatic syntax:
button.ButtonDown += OnButtonDown; button.ButtonDown += OnButtonDown;
// Option 2: GodotObject.Connect() with a constructed Callable from a method group. // Option 2: GodotObject.Connect() with a constructed Callable from a method group.
button.Connect(Button.SignalName.ButtonDown, Callable.From(OnButtonDown)); button.Connect(Button.SignalName.ButtonDown, Callable.From(OnButtonDown));
// Option 3: GodotObject.Connect() with a constructed Callable using a target object and method name. // Option 3: GodotObject.Connect() with a constructed Callable using a target object and method name.
button.Connect(Button.SignalName.ButtonDown, new Callable(this, MethodName.OnButtonDown)); button.Connect(Button.SignalName.ButtonDown, new Callable(this, MethodName.OnButtonDown));
} }
private void OnButtonDown() private void OnButtonDown()
{ {
GD.Print("Button down!"); GD.Print("Button down!");
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -112,37 +112,37 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _ready(): func _ready():
# This assumes that a `Player` class exists, which defines a `hit` signal. # This assumes that a `Player` class exists, which defines a `hit` signal.
var player = Player.new() var player = Player.new()
# Using Callable.bind(). # Using Callable.bind().
player.hit.connect(_on_player_hit.bind("sword", 100)) player.hit.connect(_on_player_hit.bind("sword", 100))
# Parameters added when emitting the signal are passed first. # Parameters added when emitting the signal are passed first.
player.hit.emit("Dark lord", 5) player.hit.emit("Dark lord", 5)
# We pass two arguments when emitting (`hit_by`, `level`), # We pass two arguments when emitting (`hit_by`, `level`),
# and bind two more arguments when connecting (`weapon_type`, `damage`). # and bind two more arguments when connecting (`weapon_type`, `damage`).
func _on_player_hit(hit_by, level, weapon_type, damage): func _on_player_hit(hit_by, level, weapon_type, damage):
print("Hit by %s (level %d) with weapon %s for %d damage." % [hit_by, level, weapon_type, damage]) print("Hit by %s (level %d) with weapon %s for %d damage." % [hit_by, level, weapon_type, damage])
[/gdscript] [/gdscript]
[csharp] [csharp]
public override void _Ready() public override void _Ready()
{ {
// This assumes that a `Player` class exists, which defines a `Hit` signal. // This assumes that a `Player` class exists, which defines a `Hit` signal.
var player = new Player(); var player = new Player();
// Using lambda expressions that create a closure that captures the additional parameters. // Using lambda expressions that create a closure that captures the additional parameters.
// The lambda only receives the parameters defined by the signal's delegate. // The lambda only receives the parameters defined by the signal's delegate.
player.Hit += (hitBy, level) =&gt; OnPlayerHit(hitBy, level, "sword", 100); player.Hit += (hitBy, level) =&gt; OnPlayerHit(hitBy, level, "sword", 100);
// Parameters added when emitting the signal are passed first. // Parameters added when emitting the signal are passed first.
player.EmitSignal(SignalName.Hit, "Dark lord", 5); player.EmitSignal(SignalName.Hit, "Dark lord", 5);
} }
// We pass two arguments when emitting (`hit_by`, `level`), // We pass two arguments when emitting (`hit_by`, `level`),
// and bind two more arguments when connecting (`weapon_type`, `damage`). // and bind two more arguments when connecting (`weapon_type`, `damage`).
private void OnPlayerHit(string hitBy, int level, string weaponType, int damage) private void OnPlayerHit(string hitBy, int level, string weaponType, int damage)
{ {
GD.Print($"Hit by {hitBy} (level {level}) with weapon {weaponType} for {damage} damage."); GD.Print($"Hit by {hitBy} (level {level}) with weapon {weaponType} for {damage} damage.");
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -184,10 +184,10 @@
A signal can only be connected once to the same [Callable]. If the signal is already connected, this method returns [constant ERR_INVALID_PARAMETER] and generates an error, unless the signal is connected with [constant Object.CONNECT_REFERENCE_COUNTED]. To prevent this, use [method is_connected] first to check for existing connections. A signal can only be connected once to the same [Callable]. If the signal is already connected, this method returns [constant ERR_INVALID_PARAMETER] and generates an error, unless the signal is connected with [constant Object.CONNECT_REFERENCE_COUNTED]. To prevent this, use [method is_connected] first to check for existing connections.
[codeblock] [codeblock]
for button in $Buttons.get_children(): for button in $Buttons.get_children():
button.pressed.connect(_on_pressed.bind(button)) button.pressed.connect(_on_pressed.bind(button))
func _on_pressed(button): func _on_pressed(button):
print(button.name, " was pressed") print(button.name, " was pressed")
[/codeblock] [/codeblock]
[b]Note:[/b] If the [param callable]'s object is freed, the connection will be lost. [b]Note:[/b] If the [param callable]'s object is freed, the connection will be lost.
</description> </description>

View File

@ -18,23 +18,23 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _input(event): func _input(event):
if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT: if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
if get_rect().has_point(to_local(event.position)): if get_rect().has_point(to_local(event.position)):
print("A click!") print("A click!")
[/gdscript] [/gdscript]
[csharp] [csharp]
public override void _Input(InputEvent @event) public override void _Input(InputEvent @event)
{ {
if (@event is InputEventMouseButton inputEventMouse) if (@event is InputEventMouseButton inputEventMouse)
{ {
if (inputEventMouse.Pressed &amp;&amp; inputEventMouse.ButtonIndex == MouseButton.Left) if (inputEventMouse.Pressed &amp;&amp; inputEventMouse.ButtonIndex == MouseButton.Left)
{ {
if (GetRect().HasPoint(ToLocal(inputEventMouse.Position))) if (GetRect().HasPoint(ToLocal(inputEventMouse.Position)))
{ {
GD.Print("A click!"); GD.Print("A click!");
} }
} }
} }
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -46,12 +46,12 @@
[b]Example:[/b] Possible return value. This means columns [code]0[/code] to [code]4[/code] should be red, and columns [code]5[/code] to the end of the line should be green: [b]Example:[/b] Possible return value. This means columns [code]0[/code] to [code]4[/code] should be red, and columns [code]5[/code] to the end of the line should be green:
[codeblock] [codeblock]
{ {
0: { 0: {
"color": Color(1, 0, 0) "color": Color(1, 0, 0)
}, },
5: { 5: {
"color": Color(0, 1, 0) "color": Color(0, 1, 0)
} }
} }
[/codeblock] [/codeblock]
</description> </description>

View File

@ -132,9 +132,9 @@
begin_complex_operation() begin_complex_operation()
begin_multicaret_edit() begin_multicaret_edit()
for i in range(get_caret_count()): for i in range(get_caret_count()):
if multicaret_edit_ignore_caret(i): if multicaret_edit_ignore_caret(i):
continue continue
# Logic here. # Logic here.
end_multicaret_edit() end_multicaret_edit()
end_complex_operation() end_complex_operation()
[/codeblock] [/codeblock]
@ -466,38 +466,38 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _ready(): func _ready():
var menu = get_menu() var menu = get_menu()
# Remove all items after "Redo". # Remove all items after "Redo".
menu.item_count = menu.get_item_index(MENU_REDO) + 1 menu.item_count = menu.get_item_index(MENU_REDO) + 1
# Add custom items. # Add custom items.
menu.add_separator() menu.add_separator()
menu.add_item("Insert Date", MENU_MAX + 1) menu.add_item("Insert Date", MENU_MAX + 1)
# Connect callback. # Connect callback.
menu.id_pressed.connect(_on_item_pressed) menu.id_pressed.connect(_on_item_pressed)
func _on_item_pressed(id): func _on_item_pressed(id):
if id == MENU_MAX + 1: if id == MENU_MAX + 1:
insert_text_at_caret(Time.get_date_string_from_system()) insert_text_at_caret(Time.get_date_string_from_system())
[/gdscript] [/gdscript]
[csharp] [csharp]
public override void _Ready() public override void _Ready()
{ {
var menu = GetMenu(); var menu = GetMenu();
// Remove all items after "Redo". // Remove all items after "Redo".
menu.ItemCount = menu.GetItemIndex(TextEdit.MenuItems.Redo) + 1; menu.ItemCount = menu.GetItemIndex(TextEdit.MenuItems.Redo) + 1;
// Add custom items. // Add custom items.
menu.AddSeparator(); menu.AddSeparator();
menu.AddItem("Insert Date", TextEdit.MenuItems.Max + 1); menu.AddItem("Insert Date", TextEdit.MenuItems.Max + 1);
// Add event handler. // Add event handler.
menu.IdPressed += OnItemPressed; menu.IdPressed += OnItemPressed;
} }
public void OnItemPressed(int id) public void OnItemPressed(int id)
{ {
if (id == TextEdit.MenuItems.Max + 1) if (id == TextEdit.MenuItems.Max + 1)
{ {
InsertTextAtCaret(Time.GetDateStringFromSystem()); InsertTextAtCaret(Time.GetDateStringFromSystem());
} }
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -971,17 +971,17 @@
[gdscript] [gdscript]
var result = search("print", SEARCH_WHOLE_WORDS, 0, 0) var result = search("print", SEARCH_WHOLE_WORDS, 0, 0)
if result.x != -1: if result.x != -1:
# Result found. # Result found.
var line_number = result.y var line_number = result.y
var column_number = result.x var column_number = result.x
[/gdscript] [/gdscript]
[csharp] [csharp]
Vector2I result = Search("print", (uint)TextEdit.SearchFlags.WholeWords, 0, 0); Vector2I result = Search("print", (uint)TextEdit.SearchFlags.WholeWords, 0, 0);
if (result.X != -1) if (result.X != -1)
{ {
// Result found. // Result found.
int lineNumber = result.Y; int lineNumber = result.Y;
int columnNumber = result.X; int columnNumber = result.X;
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -9,12 +9,12 @@
[codeblock] [codeblock]
var dummy_text_server = TextServerManager.find_interface("Dummy") var dummy_text_server = TextServerManager.find_interface("Dummy")
if dummy_text_server != null: if dummy_text_server != null:
TextServerManager.set_primary_interface(dummy_text_server) TextServerManager.set_primary_interface(dummy_text_server)
# If the other text servers are unneeded, they can be removed: # If the other text servers are unneeded, they can be removed:
for i in TextServerManager.get_interface_count(): for i in TextServerManager.get_interface_count():
var text_server = TextServerManager.get_interface(i) var text_server = TextServerManager.get_interface(i)
if text_server != dummy_text_server: if text_server != dummy_text_server:
TextServerManager.remove_interface(text_server) TextServerManager.remove_interface(text_server)
[/codeblock] [/codeblock]
The command line argument [code]--text-driver Dummy[/code] (case-sensitive) can be used to force the "Dummy" [TextServer] on any project. The command line argument [code]--text-driver Dummy[/code] (case-sensitive) can be used to force the "Dummy" [TextServer] on any project.
</description> </description>

View File

@ -128,12 +128,12 @@
If [param layer] is negative, the layers are accessed from the last one. If [param layer] is negative, the layers are accessed from the last one.
[codeblock] [codeblock]
func get_clicked_tile_power(): func get_clicked_tile_power():
var clicked_cell = tile_map.local_to_map(tile_map.get_local_mouse_position()) var clicked_cell = tile_map.local_to_map(tile_map.get_local_mouse_position())
var data = tile_map.get_cell_tile_data(0, clicked_cell) var data = tile_map.get_cell_tile_data(0, clicked_cell)
if data: if data:
return data.get_custom_data("power") return data.get_custom_data("power")
else: else:
return 0 return 0
[/codeblock] [/codeblock]
If [param use_proxies] is [code]false[/code], ignores the [TileSet]'s tile proxies. See [method TileSet.map_tile_proxy]. If [param use_proxies] is [code]false[/code], ignores the [TileSet]'s tile proxies. See [method TileSet.map_tile_proxy].
</description> </description>

View File

@ -102,12 +102,12 @@
Returns the [TileData] object associated with the given cell, or [code]null[/code] if the cell does not exist or is not a [TileSetAtlasSource]. Returns the [TileData] object associated with the given cell, or [code]null[/code] if the cell does not exist or is not a [TileSetAtlasSource].
[codeblock] [codeblock]
func get_clicked_tile_power(): func get_clicked_tile_power():
var clicked_cell = tile_map_layer.local_to_map(tile_map_layer.get_local_mouse_position()) var clicked_cell = tile_map_layer.local_to_map(tile_map_layer.get_local_mouse_position())
var data = tile_map_layer.get_cell_tile_data(clicked_cell) var data = tile_map_layer.get_cell_tile_data(clicked_cell)
if data: if data:
return data.get_custom_data("power") return data.get_custom_data("power")
else: else:
return 0 return 0
[/codeblock] [/codeblock]
</description> </description>
</method> </method>

View File

@ -292,16 +292,16 @@
[codeblock] [codeblock]
var alternate_id = $TileMapLayer.get_cell_alternative_tile(Vector2i(2, 2)) var alternate_id = $TileMapLayer.get_cell_alternative_tile(Vector2i(2, 2))
if not alternate_id &amp; TileSetAtlasSource.TRANSFORM_FLIP_H: if not alternate_id &amp; TileSetAtlasSource.TRANSFORM_FLIP_H:
# If tile is not already flipped, flip it. # If tile is not already flipped, flip it.
$TileMapLayer.set_cell(Vector2i(2, 2), source_id, atlas_coords, alternate_id | TileSetAtlasSource.TRANSFORM_FLIP_H) $TileMapLayer.set_cell(Vector2i(2, 2), source_id, atlas_coords, alternate_id | TileSetAtlasSource.TRANSFORM_FLIP_H)
[/codeblock] [/codeblock]
[b]Note:[/b] These transformations can be combined to do the equivalent of 0, 90, 180, and 270 degree rotations, as shown below: [b]Note:[/b] These transformations can be combined to do the equivalent of 0, 90, 180, and 270 degree rotations, as shown below:
[codeblock] [codeblock]
enum TileTransform { enum TileTransform {
ROTATE_0 = 0, ROTATE_0 = 0,
ROTATE_90 = TileSetAtlasSource.TRANSFORM_TRANSPOSE | TileSetAtlasSource.TRANSFORM_FLIP_H, ROTATE_90 = TileSetAtlasSource.TRANSFORM_TRANSPOSE | TileSetAtlasSource.TRANSFORM_FLIP_H,
ROTATE_180 = TileSetAtlasSource.TRANSFORM_FLIP_H | TileSetAtlasSource.TRANSFORM_FLIP_V, ROTATE_180 = TileSetAtlasSource.TRANSFORM_FLIP_H | TileSetAtlasSource.TRANSFORM_FLIP_V,
ROTATE_270 = TileSetAtlasSource.TRANSFORM_TRANSPOSE | TileSetAtlasSource.TRANSFORM_FLIP_V, ROTATE_270 = TileSetAtlasSource.TRANSFORM_TRANSPOSE | TileSetAtlasSource.TRANSFORM_FLIP_V,
} }
[/codeblock] [/codeblock]
</constant> </constant>

View File

@ -12,23 +12,23 @@
[gdscript] [gdscript]
var source_id = tile_map_layer.get_cell_source_id(Vector2i(x, y)) var source_id = tile_map_layer.get_cell_source_id(Vector2i(x, y))
if source_id &gt; -1: if source_id &gt; -1:
var scene_source = tile_map_layer.tile_set.get_source(source_id) var scene_source = tile_map_layer.tile_set.get_source(source_id)
if scene_source is TileSetScenesCollectionSource: if scene_source is TileSetScenesCollectionSource:
var alt_id = tile_map_layer.get_cell_alternative_tile(Vector2i(x, y)) var alt_id = tile_map_layer.get_cell_alternative_tile(Vector2i(x, y))
# The assigned PackedScene. # The assigned PackedScene.
var scene = scene_source.get_scene_tile_scene(alt_id) var scene = scene_source.get_scene_tile_scene(alt_id)
[/gdscript] [/gdscript]
[csharp] [csharp]
int sourceId = tileMapLayer.GetCellSourceId(new Vector2I(x, y)); int sourceId = tileMapLayer.GetCellSourceId(new Vector2I(x, y));
if (sourceId &gt; -1) if (sourceId &gt; -1)
{ {
TileSetSource source = tileMapLayer.TileSet.GetSource(sourceId); TileSetSource source = tileMapLayer.TileSet.GetSource(sourceId);
if (source is TileSetScenesCollectionSource sceneSource) if (source is TileSetScenesCollectionSource sceneSource)
{ {
int altId = tileMapLayer.GetCellAlternativeTile(new Vector2I(x, y)); int altId = tileMapLayer.GetCellAlternativeTile(new Vector2I(x, y));
// The assigned PackedScene. // The assigned PackedScene.
PackedScene scene = sceneSource.GetSceneTileScene(altId); PackedScene scene = sceneSource.GetSceneTileScene(altId);
} }
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -9,7 +9,7 @@
Without requiring much code, a timer node can be added and configured in the editor. The [signal timeout] signal it emits can also be connected through the Node dock in the editor: Without requiring much code, a timer node can be added and configured in the editor. The [signal timeout] signal it emits can also be connected through the Node dock in the editor:
[codeblock] [codeblock]
func _on_timer_timeout(): func _on_timer_timeout():
print("Time to attack!") print("Time to attack!")
[/codeblock] [/codeblock]
[b]Note:[/b] To create a one-shot timer without instantiating a node, use [method SceneTree.create_timer]. [b]Note:[/b] To create a one-shot timer without instantiating a node, use [method SceneTree.create_timer].
[b]Note:[/b] Timers are affected by [member Engine.time_scale]. The higher the time scale, the sooner timers will end. How often a timer processes may depend on the framerate or [member Engine.physics_ticks_per_second]. [b]Note:[/b] Timers are affected by [member Engine.time_scale]. The higher the time scale, the sooner timers will end. How often a timer processes may depend on the framerate or [member Engine.physics_ticks_per_second].

View File

@ -109,9 +109,9 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
var my_transform = Transform2D( var my_transform = Transform2D(
Vector2(2, 0), Vector2(2, 0),
Vector2(0, 4), Vector2(0, 4),
Vector2(0, 0) Vector2(0, 0)
) )
# Rotating the Transform2D in any way preserves its scale. # Rotating the Transform2D in any way preserves its scale.
my_transform = my_transform.rotated(TAU / 2) my_transform = my_transform.rotated(TAU / 2)
@ -120,9 +120,9 @@
[/gdscript] [/gdscript]
[csharp] [csharp]
var myTransform = new Transform2D( var myTransform = new Transform2D(
Vector3(2.0f, 0.0f), Vector3(2.0f, 0.0f),
Vector3(0.0f, 4.0f), Vector3(0.0f, 4.0f),
Vector3(0.0f, 0.0f) Vector3(0.0f, 0.0f)
); );
// Rotating the Transform2D in any way preserves its scale. // Rotating the Transform2D in any way preserves its scale.
myTransform = myTransform.Rotated(Mathf.Tau / 2.0f); myTransform = myTransform.Rotated(Mathf.Tau / 2.0f);

View File

@ -9,24 +9,24 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _ready(): func _ready():
var tree = Tree.new() var tree = Tree.new()
var root = tree.create_item() var root = tree.create_item()
tree.hide_root = true tree.hide_root = true
var child1 = tree.create_item(root) var child1 = tree.create_item(root)
var child2 = tree.create_item(root) var child2 = tree.create_item(root)
var subchild1 = tree.create_item(child1) var subchild1 = tree.create_item(child1)
subchild1.set_text(0, "Subchild1") subchild1.set_text(0, "Subchild1")
[/gdscript] [/gdscript]
[csharp] [csharp]
public override void _Ready() public override void _Ready()
{ {
var tree = new Tree(); var tree = new Tree();
TreeItem root = tree.CreateItem(); TreeItem root = tree.CreateItem();
tree.HideRoot = true; tree.HideRoot = true;
TreeItem child1 = tree.CreateItem(root); TreeItem child1 = tree.CreateItem(root);
TreeItem child2 = tree.CreateItem(root); TreeItem child2 = tree.CreateItem(root);
TreeItem subchild1 = tree.CreateItem(child1); TreeItem subchild1 = tree.CreateItem(child1);
subchild1.SetText(0, "Subchild1"); subchild1.SetText(0, "Subchild1");
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -153,20 +153,20 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _ready(): func _ready():
$Tree.item_edited.connect(on_Tree_item_edited) $Tree.item_edited.connect(on_Tree_item_edited)
func on_Tree_item_edited(): func on_Tree_item_edited():
print($Tree.get_edited()) # This item just got edited (e.g. checked). print($Tree.get_edited()) # This item just got edited (e.g. checked).
[/gdscript] [/gdscript]
[csharp] [csharp]
public override void _Ready() public override void _Ready()
{ {
GetNode&lt;Tree&gt;("Tree").ItemEdited += OnTreeItemEdited; GetNode&lt;Tree&gt;("Tree").ItemEdited += OnTreeItemEdited;
} }
public void OnTreeItemEdited() public void OnTreeItemEdited()
{ {
GD.Print(GetNode&lt;Tree&gt;("Tree").GetEdited()); // This item just got edited (e.g. checked). GD.Print(GetNode&lt;Tree&gt;("Tree").GetEdited()); // This item just got edited (e.g. checked).
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -58,12 +58,12 @@
[gdscript] [gdscript]
var tween = create_tween() var tween = create_tween()
for sprite in get_children(): for sprite in get_children():
tween.tween_property(sprite, "position", Vector2(0, 0), 1.0) tween.tween_property(sprite, "position", Vector2(0, 0), 1.0)
[/gdscript] [/gdscript]
[csharp] [csharp]
Tween tween = CreateTween(); Tween tween = CreateTween();
foreach (Node sprite in GetChildren()) foreach (Node sprite in GetChildren())
tween.TweenProperty(sprite, "position", Vector2.Zero, 1.0f); tween.TweenProperty(sprite, "position", Vector2.Zero, 1.0f);
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
In the example above, all children of a node are moved one after another to position (0, 0). In the example above, all children of a node are moved one after another to position (0, 0).
@ -72,18 +72,18 @@
[gdscript] [gdscript]
var tween var tween
func animate(): func animate():
if tween: if tween:
tween.kill() # Abort the previous animation. tween.kill() # Abort the previous animation.
tween = create_tween() tween = create_tween()
[/gdscript] [/gdscript]
[csharp] [csharp]
private Tween _tween; private Tween _tween;
public void Animate() public void Animate()
{ {
if (_tween != null) if (_tween != null)
_tween.Kill(); // Abort the previous animation _tween.Kill(); // Abort the previous animation
_tween = CreateTween(); _tween = CreateTween();
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -413,24 +413,24 @@
[codeblocks] [codeblocks]
[gdscript] [gdscript]
func _ready(): func _ready():
var tween = create_tween() var tween = create_tween()
tween.tween_method(set_label_text, 0, 10, 1.0).set_delay(1.0) tween.tween_method(set_label_text, 0, 10, 1.0).set_delay(1.0)
func set_label_text(value: int): func set_label_text(value: int):
$Label.text = "Counting " + str(value) $Label.text = "Counting " + str(value)
[/gdscript] [/gdscript]
[csharp] [csharp]
public override void _Ready() public override void _Ready()
{ {
base._Ready(); base._Ready();
Tween tween = CreateTween(); Tween tween = CreateTween();
tween.TweenMethod(Callable.From&lt;int&gt;(SetLabelText), 0.0f, 10.0f, 1.0f).SetDelay(1.0f); tween.TweenMethod(Callable.From&lt;int&gt;(SetLabelText), 0.0f, 10.0f, 1.0f).SetDelay(1.0f);
} }
private void SetLabelText(int value) private void SetLabelText(int value)
{ {
GetNode&lt;Label&gt;("Label").Text = $"Counting {value}"; GetNode&lt;Label&gt;("Label").Text = $"Counting {value}";
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -17,22 +17,22 @@
var peers = [] var peers = []
func _ready(): func _ready():
server.listen(4242) server.listen(4242)
func _process(delta): func _process(delta):
server.poll() # Important! server.poll() # Important!
if server.is_connection_available(): if server.is_connection_available():
var peer = server.take_connection() var peer = server.take_connection()
var packet = peer.get_packet() var packet = peer.get_packet()
print("Accepted peer: %s:%s" % [peer.get_packet_ip(), peer.get_packet_port()]) print("Accepted peer: %s:%s" % [peer.get_packet_ip(), peer.get_packet_port()])
print("Received data: %s" % [packet.get_string_from_utf8()]) print("Received data: %s" % [packet.get_string_from_utf8()])
# Reply so it knows we received the message. # Reply so it knows we received the message.
peer.put_packet(packet) peer.put_packet(packet)
# Keep a reference so we can keep contacting the remote peer. # Keep a reference so we can keep contacting the remote peer.
peers.append(peer) peers.append(peer)
for i in range(0, peers.size()): for i in range(0, peers.size()):
pass # Do something with the connected peers. pass # Do something with the connected peers.
[/gdscript] [/gdscript]
[csharp] [csharp]
// ServerNode.cs // ServerNode.cs
@ -41,33 +41,33 @@
public partial class ServerNode : Node public partial class ServerNode : Node
{ {
private UdpServer _server = new UdpServer(); private UdpServer _server = new UdpServer();
private List&lt;PacketPeerUdp&gt; _peers = new List&lt;PacketPeerUdp&gt;(); private List&lt;PacketPeerUdp&gt; _peers = new List&lt;PacketPeerUdp&gt;();
public override void _Ready() public override void _Ready()
{ {
_server.Listen(4242); _server.Listen(4242);
} }
public override void _Process(double delta) public override void _Process(double delta)
{ {
_server.Poll(); // Important! _server.Poll(); // Important!
if (_server.IsConnectionAvailable()) if (_server.IsConnectionAvailable())
{ {
PacketPeerUdp peer = _server.TakeConnection(); PacketPeerUdp peer = _server.TakeConnection();
byte[] packet = peer.GetPacket(); byte[] packet = peer.GetPacket();
GD.Print($"Accepted Peer: {peer.GetPacketIP()}:{peer.GetPacketPort()}"); GD.Print($"Accepted Peer: {peer.GetPacketIP()}:{peer.GetPacketPort()}");
GD.Print($"Received Data: {packet.GetStringFromUtf8()}"); GD.Print($"Received Data: {packet.GetStringFromUtf8()}");
// Reply so it knows we received the message. // Reply so it knows we received the message.
peer.PutPacket(packet); peer.PutPacket(packet);
// Keep a reference so we can keep contacting the remote peer. // Keep a reference so we can keep contacting the remote peer.
_peers.Add(peer); _peers.Add(peer);
} }
foreach (var peer in _peers) foreach (var peer in _peers)
{ {
// Do something with the peers. // Do something with the peers.
} }
} }
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]
@ -81,15 +81,15 @@
var connected = false var connected = false
func _ready(): func _ready():
udp.connect_to_host("127.0.0.1", 4242) udp.connect_to_host("127.0.0.1", 4242)
func _process(delta): func _process(delta):
if !connected: if !connected:
# Try to contact server # Try to contact server
udp.put_packet("The answer is... 42!".to_utf8_buffer()) udp.put_packet("The answer is... 42!".to_utf8_buffer())
if udp.get_available_packet_count() &gt; 0: if udp.get_available_packet_count() &gt; 0:
print("Connected: %s" % udp.get_packet().get_string_from_utf8()) print("Connected: %s" % udp.get_packet().get_string_from_utf8())
connected = true connected = true
[/gdscript] [/gdscript]
[csharp] [csharp]
// ClientNode.cs // ClientNode.cs
@ -97,27 +97,27 @@
public partial class ClientNode : Node public partial class ClientNode : Node
{ {
private PacketPeerUdp _udp = new PacketPeerUdp(); private PacketPeerUdp _udp = new PacketPeerUdp();
private bool _connected = false; private bool _connected = false;
public override void _Ready() public override void _Ready()
{ {
_udp.ConnectToHost("127.0.0.1", 4242); _udp.ConnectToHost("127.0.0.1", 4242);
} }
public override void _Process(double delta) public override void _Process(double delta)
{ {
if (!_connected) if (!_connected)
{ {
// Try to contact server // Try to contact server
_udp.PutPacket("The Answer Is..42!".ToUtf8Buffer()); _udp.PutPacket("The Answer Is..42!".ToUtf8Buffer());
} }
if (_udp.GetAvailablePacketCount() &gt; 0) if (_udp.GetAvailablePacketCount() &gt; 0)
{ {
GD.Print($"Connected: {_udp.GetPacket().GetStringFromUtf8()}"); GD.Print($"Connected: {_udp.GetPacket().GetStringFromUtf8()}");
_connected = true; _connected = true;
} }
} }
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -12,47 +12,47 @@
var undo_redo = UndoRedo.new() var undo_redo = UndoRedo.new()
func do_something(): func do_something():
pass # Put your code here. pass # Put your code here.
func undo_something(): func undo_something():
pass # Put here the code that reverts what's done by "do_something()". pass # Put here the code that reverts what's done by "do_something()".
func _on_my_button_pressed(): func _on_my_button_pressed():
var node = get_node("MyNode2D") var node = get_node("MyNode2D")
undo_redo.create_action("Move the node") undo_redo.create_action("Move the node")
undo_redo.add_do_method(do_something) undo_redo.add_do_method(do_something)
undo_redo.add_undo_method(undo_something) undo_redo.add_undo_method(undo_something)
undo_redo.add_do_property(node, "position", Vector2(100,100)) undo_redo.add_do_property(node, "position", Vector2(100,100))
undo_redo.add_undo_property(node, "position", node.position) undo_redo.add_undo_property(node, "position", node.position)
undo_redo.commit_action() undo_redo.commit_action()
[/gdscript] [/gdscript]
[csharp] [csharp]
private UndoRedo _undoRedo; private UndoRedo _undoRedo;
public override void _Ready() public override void _Ready()
{ {
_undoRedo = new UndoRedo(); _undoRedo = new UndoRedo();
} }
public void DoSomething() public void DoSomething()
{ {
// Put your code here. // Put your code here.
} }
public void UndoSomething() public void UndoSomething()
{ {
// Put here the code that reverts what's done by "DoSomething()". // Put here the code that reverts what's done by "DoSomething()".
} }
private void OnMyButtonPressed() private void OnMyButtonPressed()
{ {
var node = GetNode&lt;Node2D&gt;("MyNode2D"); var node = GetNode&lt;Node2D&gt;("MyNode2D");
_undoRedo.CreateAction("Move the node"); _undoRedo.CreateAction("Move the node");
_undoRedo.AddDoMethod(new Callable(this, MethodName.DoSomething)); _undoRedo.AddDoMethod(new Callable(this, MethodName.DoSomething));
_undoRedo.AddUndoMethod(new Callable(this, MethodName.UndoSomething)); _undoRedo.AddUndoMethod(new Callable(this, MethodName.UndoSomething));
_undoRedo.AddDoProperty(node, "position", new Vector2(100, 100)); _undoRedo.AddDoProperty(node, "position", new Vector2(100, 100));
_undoRedo.AddUndoProperty(node, "position", node.Position); _undoRedo.AddUndoProperty(node, "position", node.Position);
_undoRedo.CommitAction(); _undoRedo.CommitAction();
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

View File

@ -34,32 +34,32 @@
[gdscript] [gdscript]
var foo = 2 var foo = 2
match typeof(foo): match typeof(foo):
TYPE_NIL: TYPE_NIL:
print("foo is null") print("foo is null")
TYPE_INT: TYPE_INT:
print("foo is an integer") print("foo is an integer")
TYPE_OBJECT: TYPE_OBJECT:
# Note that Objects are their own special category. # Note that Objects are their own special category.
# To get the name of the underlying Object type, you need the `get_class()` method. # To get the name of the underlying Object type, you need the `get_class()` method.
print("foo is a(n) %s" % foo.get_class()) # inject the class name into a formatted string. print("foo is a(n) %s" % foo.get_class()) # inject the class name into a formatted string.
# Note that this does not get the script's `class_name` global identifier. # Note that this does not get the script's `class_name` global identifier.
# If the `class_name` is needed, use `foo.get_script().get_global_name()` instead. # If the `class_name` is needed, use `foo.get_script().get_global_name()` instead.
[/gdscript] [/gdscript]
[csharp] [csharp]
Variant foo = 2; Variant foo = 2;
switch (foo.VariantType) switch (foo.VariantType)
{ {
case Variant.Type.Nil: case Variant.Type.Nil:
GD.Print("foo is null"); GD.Print("foo is null");
break; break;
case Variant.Type.Int: case Variant.Type.Int:
GD.Print("foo is an integer"); GD.Print("foo is an integer");
break; break;
case Variant.Type.Object: case Variant.Type.Object:
// Note that Objects are their own special category. // Note that Objects are their own special category.
// You can convert a Variant to a GodotObject and use reflection to get its name. // You can convert a Variant to a GodotObject and use reflection to get its name.
GD.Print($"foo is a(n) {foo.AsGodotObject().GetType().Name}"); GD.Print($"foo is a(n) {foo.AsGodotObject().GetType().Name}");
break; break;
} }
[/csharp] [/csharp]
[/codeblocks] [/codeblocks]

Some files were not shown because too many files have changed in this diff Show More